mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-03 22:26:07 +00:00
feat: added camunda app connection
This commit is contained in:
@@ -12,6 +12,10 @@ import {
|
|||||||
AzureKeyVaultConnectionListItemSchema,
|
AzureKeyVaultConnectionListItemSchema,
|
||||||
SanitizedAzureKeyVaultConnectionSchema
|
SanitizedAzureKeyVaultConnectionSchema
|
||||||
} from "@app/services/app-connection/azure-key-vault";
|
} from "@app/services/app-connection/azure-key-vault";
|
||||||
|
import {
|
||||||
|
CamundaConnectionListItemSchema,
|
||||||
|
SanitizedCamundaConnectionSchema
|
||||||
|
} from "@app/services/app-connection/camunda";
|
||||||
import {
|
import {
|
||||||
DatabricksConnectionListItemSchema,
|
DatabricksConnectionListItemSchema,
|
||||||
SanitizedDatabricksConnectionSchema
|
SanitizedDatabricksConnectionSchema
|
||||||
@@ -39,7 +43,8 @@ const SanitizedAppConnectionSchema = z.union([
|
|||||||
...SanitizedDatabricksConnectionSchema.options,
|
...SanitizedDatabricksConnectionSchema.options,
|
||||||
...SanitizedHumanitecConnectionSchema.options,
|
...SanitizedHumanitecConnectionSchema.options,
|
||||||
...SanitizedPostgresConnectionSchema.options,
|
...SanitizedPostgresConnectionSchema.options,
|
||||||
...SanitizedMsSqlConnectionSchema.options
|
...SanitizedMsSqlConnectionSchema.options,
|
||||||
|
...SanitizedCamundaConnectionSchema.options
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
||||||
@@ -51,7 +56,8 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
|||||||
DatabricksConnectionListItemSchema,
|
DatabricksConnectionListItemSchema,
|
||||||
HumanitecConnectionListItemSchema,
|
HumanitecConnectionListItemSchema,
|
||||||
PostgresConnectionListItemSchema,
|
PostgresConnectionListItemSchema,
|
||||||
MsSqlConnectionListItemSchema
|
MsSqlConnectionListItemSchema,
|
||||||
|
CamundaConnectionListItemSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const registerAppConnectionRouter = async (server: FastifyZodProvider) => {
|
export const registerAppConnectionRouter = async (server: FastifyZodProvider) => {
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { readLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
import {
|
||||||
|
CreateCamundaConnectionSchema,
|
||||||
|
SanitizedCamundaConnectionSchema,
|
||||||
|
UpdateCamundaConnectionSchema
|
||||||
|
} from "@app/services/app-connection/camunda";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
|
||||||
|
|
||||||
|
export const registerCamundaConnectionRouter = async (server: FastifyZodProvider) => {
|
||||||
|
registerAppConnectionEndpoints({
|
||||||
|
app: AppConnection.Camunda,
|
||||||
|
server,
|
||||||
|
sanitizedResponseSchema: SanitizedCamundaConnectionSchema,
|
||||||
|
createSchema: CreateCamundaConnectionSchema,
|
||||||
|
updateSchema: UpdateCamundaConnectionSchema
|
||||||
|
});
|
||||||
|
|
||||||
|
// The below endpoints are not exposed and for Infisical App use
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: `/:connectionId/clusters`,
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
connectionId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
clusters: z.object({ uuid: z.string(), name: z.string() }).array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { connectionId } = req.params;
|
||||||
|
|
||||||
|
const clusters = await server.services.appConnection.camunda.listClusters(connectionId, req.permission);
|
||||||
|
|
||||||
|
return { clusters };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@ import { AppConnection } from "@app/services/app-connection/app-connection-enums
|
|||||||
import { registerAwsConnectionRouter } from "./aws-connection-router";
|
import { registerAwsConnectionRouter } from "./aws-connection-router";
|
||||||
import { registerAzureAppConfigurationConnectionRouter } from "./azure-app-configuration-connection-router";
|
import { registerAzureAppConfigurationConnectionRouter } from "./azure-app-configuration-connection-router";
|
||||||
import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router";
|
import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router";
|
||||||
|
import { registerCamundaConnectionRouter } from "./camunda-connection-router";
|
||||||
import { registerDatabricksConnectionRouter } from "./databricks-connection-router";
|
import { registerDatabricksConnectionRouter } from "./databricks-connection-router";
|
||||||
import { registerGcpConnectionRouter } from "./gcp-connection-router";
|
import { registerGcpConnectionRouter } from "./gcp-connection-router";
|
||||||
import { registerGitHubConnectionRouter } from "./github-connection-router";
|
import { registerGitHubConnectionRouter } from "./github-connection-router";
|
||||||
@@ -22,5 +23,6 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record<AppConnection, (server:
|
|||||||
[AppConnection.Databricks]: registerDatabricksConnectionRouter,
|
[AppConnection.Databricks]: registerDatabricksConnectionRouter,
|
||||||
[AppConnection.Humanitec]: registerHumanitecConnectionRouter,
|
[AppConnection.Humanitec]: registerHumanitecConnectionRouter,
|
||||||
[AppConnection.Postgres]: registerPostgresConnectionRouter,
|
[AppConnection.Postgres]: registerPostgresConnectionRouter,
|
||||||
[AppConnection.MsSql]: registerMsSqlConnectionRouter
|
[AppConnection.MsSql]: registerMsSqlConnectionRouter,
|
||||||
|
[AppConnection.Camunda]: registerCamundaConnectionRouter
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ export enum AppConnection {
|
|||||||
AzureAppConfiguration = "azure-app-configuration",
|
AzureAppConfiguration = "azure-app-configuration",
|
||||||
Humanitec = "humanitec",
|
Humanitec = "humanitec",
|
||||||
Postgres = "postgres",
|
Postgres = "postgres",
|
||||||
MsSql = "mssql"
|
MsSql = "mssql",
|
||||||
|
Camunda = "camunda"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AWSRegion {
|
export enum AWSRegion {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
getAzureKeyVaultConnectionListItem,
|
getAzureKeyVaultConnectionListItem,
|
||||||
validateAzureKeyVaultConnectionCredentials
|
validateAzureKeyVaultConnectionCredentials
|
||||||
} from "./azure-key-vault";
|
} from "./azure-key-vault";
|
||||||
|
import { CamundaConnectionMethod, getCamundaConnectionListItem, validateCamundaConnectionCredentials } from "./camunda";
|
||||||
import {
|
import {
|
||||||
DatabricksConnectionMethod,
|
DatabricksConnectionMethod,
|
||||||
getDatabricksConnectionListItem,
|
getDatabricksConnectionListItem,
|
||||||
@@ -52,7 +53,8 @@ export const listAppConnectionOptions = () => {
|
|||||||
getDatabricksConnectionListItem(),
|
getDatabricksConnectionListItem(),
|
||||||
getHumanitecConnectionListItem(),
|
getHumanitecConnectionListItem(),
|
||||||
getPostgresConnectionListItem(),
|
getPostgresConnectionListItem(),
|
||||||
getMsSqlConnectionListItem()
|
getMsSqlConnectionListItem(),
|
||||||
|
getCamundaConnectionListItem()
|
||||||
].sort((a, b) => a.name.localeCompare(b.name));
|
].sort((a, b) => a.name.localeCompare(b.name));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -108,7 +110,8 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TAppConnect
|
|||||||
validateAzureAppConfigurationConnectionCredentials as TAppConnectionCredentialsValidator,
|
validateAzureAppConfigurationConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
[AppConnection.Humanitec]: validateHumanitecConnectionCredentials as TAppConnectionCredentialsValidator,
|
[AppConnection.Humanitec]: validateHumanitecConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
[AppConnection.Postgres]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator,
|
[AppConnection.Postgres]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
[AppConnection.MsSql]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator
|
[AppConnection.MsSql]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
|
[AppConnection.Camunda]: validateCamundaConnectionCredentials as TAppConnectionCredentialsValidator
|
||||||
};
|
};
|
||||||
|
|
||||||
export const validateAppConnectionCredentials = async (
|
export const validateAppConnectionCredentials = async (
|
||||||
@@ -131,6 +134,8 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
|
|||||||
return "Service Account Impersonation";
|
return "Service Account Impersonation";
|
||||||
case DatabricksConnectionMethod.ServicePrincipal:
|
case DatabricksConnectionMethod.ServicePrincipal:
|
||||||
return "Service Principal";
|
return "Service Principal";
|
||||||
|
case CamundaConnectionMethod.ClientCredentials:
|
||||||
|
return "Client Credentials";
|
||||||
case HumanitecConnectionMethod.ApiToken:
|
case HumanitecConnectionMethod.ApiToken:
|
||||||
return "API Token";
|
return "API Token";
|
||||||
case PostgresConnectionMethod.UsernameAndPassword:
|
case PostgresConnectionMethod.UsernameAndPassword:
|
||||||
@@ -175,5 +180,6 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record<
|
|||||||
[AppConnection.AzureAppConfiguration]: platformManagedCredentialsNotSupported,
|
[AppConnection.AzureAppConfiguration]: platformManagedCredentialsNotSupported,
|
||||||
[AppConnection.Humanitec]: platformManagedCredentialsNotSupported,
|
[AppConnection.Humanitec]: platformManagedCredentialsNotSupported,
|
||||||
[AppConnection.Postgres]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform,
|
[AppConnection.Postgres]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform,
|
||||||
[AppConnection.MsSql]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform
|
[AppConnection.MsSql]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform,
|
||||||
|
[AppConnection.Camunda]: platformManagedCredentialsNotSupported
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ import { ValidateAwsConnectionCredentialsSchema } from "./aws";
|
|||||||
import { awsConnectionService } from "./aws/aws-connection-service";
|
import { awsConnectionService } from "./aws/aws-connection-service";
|
||||||
import { ValidateAzureAppConfigurationConnectionCredentialsSchema } from "./azure-app-configuration";
|
import { ValidateAzureAppConfigurationConnectionCredentialsSchema } from "./azure-app-configuration";
|
||||||
import { ValidateAzureKeyVaultConnectionCredentialsSchema } from "./azure-key-vault";
|
import { ValidateAzureKeyVaultConnectionCredentialsSchema } from "./azure-key-vault";
|
||||||
|
import { ValidateCamundaConnectionCredentialsSchema } from "./camunda";
|
||||||
|
import { camundaConnectionService } from "./camunda/camunda-connection-service";
|
||||||
import { ValidateDatabricksConnectionCredentialsSchema } from "./databricks";
|
import { ValidateDatabricksConnectionCredentialsSchema } from "./databricks";
|
||||||
import { databricksConnectionService } from "./databricks/databricks-connection-service";
|
import { databricksConnectionService } from "./databricks/databricks-connection-service";
|
||||||
import { ValidateGcpConnectionCredentialsSchema } from "./gcp";
|
import { ValidateGcpConnectionCredentialsSchema } from "./gcp";
|
||||||
@@ -59,7 +61,8 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TValidateAp
|
|||||||
[AppConnection.Databricks]: ValidateDatabricksConnectionCredentialsSchema,
|
[AppConnection.Databricks]: ValidateDatabricksConnectionCredentialsSchema,
|
||||||
[AppConnection.Humanitec]: ValidateHumanitecConnectionCredentialsSchema,
|
[AppConnection.Humanitec]: ValidateHumanitecConnectionCredentialsSchema,
|
||||||
[AppConnection.Postgres]: ValidatePostgresConnectionCredentialsSchema,
|
[AppConnection.Postgres]: ValidatePostgresConnectionCredentialsSchema,
|
||||||
[AppConnection.MsSql]: ValidateMsSqlConnectionCredentialsSchema
|
[AppConnection.MsSql]: ValidateMsSqlConnectionCredentialsSchema,
|
||||||
|
[AppConnection.Camunda]: ValidateCamundaConnectionCredentialsSchema
|
||||||
};
|
};
|
||||||
|
|
||||||
export const appConnectionServiceFactory = ({
|
export const appConnectionServiceFactory = ({
|
||||||
@@ -430,6 +433,7 @@ export const appConnectionServiceFactory = ({
|
|||||||
gcp: gcpConnectionService(connectAppConnectionById),
|
gcp: gcpConnectionService(connectAppConnectionById),
|
||||||
databricks: databricksConnectionService(connectAppConnectionById, appConnectionDAL, kmsService),
|
databricks: databricksConnectionService(connectAppConnectionById, appConnectionDAL, kmsService),
|
||||||
aws: awsConnectionService(connectAppConnectionById),
|
aws: awsConnectionService(connectAppConnectionById),
|
||||||
humanitec: humanitecConnectionService(connectAppConnectionById)
|
humanitec: humanitecConnectionService(connectAppConnectionById),
|
||||||
|
camunda: camundaConnectionService(connectAppConnectionById, appConnectionDAL, kmsService)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ import {
|
|||||||
TAzureKeyVaultConnectionInput,
|
TAzureKeyVaultConnectionInput,
|
||||||
TValidateAzureKeyVaultConnectionCredentialsSchema
|
TValidateAzureKeyVaultConnectionCredentialsSchema
|
||||||
} from "./azure-key-vault";
|
} from "./azure-key-vault";
|
||||||
|
import {
|
||||||
|
TCamundaConnection,
|
||||||
|
TCamundaConnectionConfig,
|
||||||
|
TCamundaConnectionInput,
|
||||||
|
TValidateCamundaConnectionCredentialsSchema
|
||||||
|
} from "./camunda";
|
||||||
import {
|
import {
|
||||||
TDatabricksConnection,
|
TDatabricksConnection,
|
||||||
TDatabricksConnectionConfig,
|
TDatabricksConnectionConfig,
|
||||||
@@ -62,6 +68,7 @@ export type TAppConnection = { id: string } & (
|
|||||||
| THumanitecConnection
|
| THumanitecConnection
|
||||||
| TPostgresConnection
|
| TPostgresConnection
|
||||||
| TMsSqlConnection
|
| TMsSqlConnection
|
||||||
|
| TCamundaConnection
|
||||||
);
|
);
|
||||||
|
|
||||||
export type TAppConnectionRaw = NonNullable<Awaited<ReturnType<TAppConnectionDALFactory["findById"]>>>;
|
export type TAppConnectionRaw = NonNullable<Awaited<ReturnType<TAppConnectionDALFactory["findById"]>>>;
|
||||||
@@ -78,6 +85,7 @@ export type TAppConnectionInput = { id: string } & (
|
|||||||
| THumanitecConnectionInput
|
| THumanitecConnectionInput
|
||||||
| TPostgresConnectionInput
|
| TPostgresConnectionInput
|
||||||
| TMsSqlConnectionInput
|
| TMsSqlConnectionInput
|
||||||
|
| TCamundaConnectionInput
|
||||||
);
|
);
|
||||||
|
|
||||||
export type TSqlConnectionInput = TPostgresConnectionInput | TMsSqlConnectionInput;
|
export type TSqlConnectionInput = TPostgresConnectionInput | TMsSqlConnectionInput;
|
||||||
@@ -99,7 +107,8 @@ export type TAppConnectionConfig =
|
|||||||
| TAzureAppConfigurationConnectionConfig
|
| TAzureAppConfigurationConnectionConfig
|
||||||
| TDatabricksConnectionConfig
|
| TDatabricksConnectionConfig
|
||||||
| THumanitecConnectionConfig
|
| THumanitecConnectionConfig
|
||||||
| TSqlConnectionConfig;
|
| TSqlConnectionConfig
|
||||||
|
| TCamundaConnectionConfig;
|
||||||
|
|
||||||
export type TValidateAppConnectionCredentialsSchema =
|
export type TValidateAppConnectionCredentialsSchema =
|
||||||
| TValidateAwsConnectionCredentialsSchema
|
| TValidateAwsConnectionCredentialsSchema
|
||||||
@@ -110,7 +119,8 @@ export type TValidateAppConnectionCredentialsSchema =
|
|||||||
| TValidateDatabricksConnectionCredentialsSchema
|
| TValidateDatabricksConnectionCredentialsSchema
|
||||||
| TValidateHumanitecConnectionCredentialsSchema
|
| TValidateHumanitecConnectionCredentialsSchema
|
||||||
| TValidatePostgresConnectionCredentialsSchema
|
| TValidatePostgresConnectionCredentialsSchema
|
||||||
| TValidateMsSqlConnectionCredentialsSchema;
|
| TValidateMsSqlConnectionCredentialsSchema
|
||||||
|
| TValidateCamundaConnectionCredentialsSchema;
|
||||||
|
|
||||||
export type TListAwsConnectionKmsKeys = {
|
export type TListAwsConnectionKmsKeys = {
|
||||||
connectionId: string;
|
connectionId: string;
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export enum CamundaConnectionMethod {
|
||||||
|
ClientCredentials = "client-credentials"
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import { request } from "@app/lib/config/request";
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
import { encryptAppConnectionCredentials } from "@app/services/app-connection/app-connection-fns";
|
||||||
|
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||||
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
|
||||||
|
import { TAppConnectionDALFactory } from "../app-connection-dal";
|
||||||
|
import { CamundaConnectionMethod } from "./camunda-connection-enums";
|
||||||
|
import { TAuthorizeCamundaConnection, TCamundaConnection, TCamundaConnectionConfig } from "./camunda-connection-types";
|
||||||
|
|
||||||
|
export const getCamundaConnectionListItem = () => {
|
||||||
|
return {
|
||||||
|
name: "Camunda" as const,
|
||||||
|
app: AppConnection.Camunda as const,
|
||||||
|
methods: Object.values(CamundaConnectionMethod) as [CamundaConnectionMethod.ClientCredentials]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const authorizeCamundaConnection = async ({
|
||||||
|
clientId,
|
||||||
|
clientSecret
|
||||||
|
}: Pick<TCamundaConnection["credentials"], "clientId" | "clientSecret">) => {
|
||||||
|
const { data } = await request.post<TAuthorizeCamundaConnection>(
|
||||||
|
IntegrationUrls.CAMUNDA_TOKEN_URL,
|
||||||
|
{
|
||||||
|
grant_type: "client_credentials",
|
||||||
|
client_id: clientId,
|
||||||
|
client_secret: clientSecret,
|
||||||
|
audience: "api.cloud.camunda.io"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return { accessToken: data.access_token, expiresAt: data.expires_in * 1000 + Date.now() };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getCamundaConnectionAccessToken = async (
|
||||||
|
{ id, orgId, credentials }: TCamundaConnection,
|
||||||
|
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
|
||||||
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
||||||
|
) => {
|
||||||
|
const { clientSecret, clientId, accessToken, expiresAt } = credentials;
|
||||||
|
|
||||||
|
// get new token if less than 10 minutes from expiry
|
||||||
|
if (Date.now() < expiresAt - 10_000) {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authData = await authorizeCamundaConnection({ clientId, clientSecret });
|
||||||
|
|
||||||
|
const updatedCredentials: TCamundaConnection["credentials"] = {
|
||||||
|
...credentials,
|
||||||
|
...authData
|
||||||
|
};
|
||||||
|
|
||||||
|
const encryptedCredentials = await encryptAppConnectionCredentials({
|
||||||
|
credentials: updatedCredentials,
|
||||||
|
orgId,
|
||||||
|
kmsService
|
||||||
|
});
|
||||||
|
|
||||||
|
await appConnectionDAL.updateById(id, { encryptedCredentials });
|
||||||
|
|
||||||
|
return authData.accessToken;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const validateCamundaConnectionCredentials = async (appConnection: TCamundaConnectionConfig) => {
|
||||||
|
const { credentials } = appConnection;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { accessToken, expiresAt } = await authorizeCamundaConnection(appConnection.credentials);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...credentials,
|
||||||
|
accessToken,
|
||||||
|
expiresAt
|
||||||
|
};
|
||||||
|
} catch (e: unknown) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Unable to validate connection: verify credentials`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { AppConnections } from "@app/lib/api-docs";
|
||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
import {
|
||||||
|
BaseAppConnectionSchema,
|
||||||
|
GenericCreateAppConnectionFieldsSchema,
|
||||||
|
GenericUpdateAppConnectionFieldsSchema
|
||||||
|
} from "@app/services/app-connection/app-connection-schemas";
|
||||||
|
|
||||||
|
import { CamundaConnectionMethod } from "./camunda-connection-enums";
|
||||||
|
|
||||||
|
const BaseCamundaConnectionSchema = BaseAppConnectionSchema.extend({ app: z.literal(AppConnection.Camunda) });
|
||||||
|
|
||||||
|
export const CamundaConnectionClientCredentialsInputCredentialsSchema = z.object({
|
||||||
|
clientId: z.string().trim().min(1, "Client ID required"),
|
||||||
|
clientSecret: z.string().trim().min(1, "Client Secret required")
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CamundaConnectionClientCredentialsOutputCredentialsSchema = z
|
||||||
|
.object({
|
||||||
|
accessToken: z.string(),
|
||||||
|
expiresAt: z.number()
|
||||||
|
})
|
||||||
|
.merge(CamundaConnectionClientCredentialsInputCredentialsSchema);
|
||||||
|
|
||||||
|
export const CamundaConnectionSchema = z.intersection(
|
||||||
|
BaseCamundaConnectionSchema,
|
||||||
|
z.discriminatedUnion("method", [
|
||||||
|
z.object({
|
||||||
|
method: z.literal(CamundaConnectionMethod.ClientCredentials),
|
||||||
|
credentials: CamundaConnectionClientCredentialsOutputCredentialsSchema
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SanitizedCamundaConnectionSchema = z.discriminatedUnion("method", [
|
||||||
|
BaseCamundaConnectionSchema.extend({
|
||||||
|
method: z.literal(CamundaConnectionMethod.ClientCredentials),
|
||||||
|
credentials: CamundaConnectionClientCredentialsOutputCredentialsSchema.pick({
|
||||||
|
clientId: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const ValidateCamundaConnectionCredentialsSchema = z.discriminatedUnion("method", [
|
||||||
|
z.object({
|
||||||
|
method: z
|
||||||
|
.literal(CamundaConnectionMethod.ClientCredentials)
|
||||||
|
.describe(AppConnections.CREATE(AppConnection.Camunda).method),
|
||||||
|
credentials: CamundaConnectionClientCredentialsInputCredentialsSchema.describe(
|
||||||
|
AppConnections.CREATE(AppConnection.Camunda).credentials
|
||||||
|
)
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const CreateCamundaConnectionSchema = ValidateCamundaConnectionCredentialsSchema.and(
|
||||||
|
GenericCreateAppConnectionFieldsSchema(AppConnection.Camunda)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const UpdateCamundaConnectionSchema = z
|
||||||
|
.object({
|
||||||
|
credentials: CamundaConnectionClientCredentialsInputCredentialsSchema.optional().describe(
|
||||||
|
AppConnections.UPDATE(AppConnection.Camunda).credentials
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.Camunda));
|
||||||
|
|
||||||
|
export const CamundaConnectionListItemSchema = z.object({
|
||||||
|
name: z.literal("Camunda"),
|
||||||
|
app: z.literal(AppConnection.Camunda),
|
||||||
|
methods: z.nativeEnum(CamundaConnectionMethod).array()
|
||||||
|
});
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { request } from "@app/lib/config/request";
|
||||||
|
import { OrgServiceActor } from "@app/lib/types";
|
||||||
|
import { TAppConnectionDALFactory } from "@app/services/app-connection/app-connection-dal";
|
||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||||
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
|
|
||||||
|
import { getCamundaConnectionAccessToken } from "./camunda-connection-fns";
|
||||||
|
import { TCamundaConnection, TCamundaListClustersResponse } from "./camunda-connection-types";
|
||||||
|
|
||||||
|
type TGetAppConnectionFunc = (
|
||||||
|
app: AppConnection,
|
||||||
|
connectionId: string,
|
||||||
|
actor: OrgServiceActor
|
||||||
|
) => Promise<TCamundaConnection>;
|
||||||
|
|
||||||
|
const listCamundaClusters = async (
|
||||||
|
appConnection: TCamundaConnection,
|
||||||
|
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
|
||||||
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
||||||
|
) => {
|
||||||
|
const accessToken = await getCamundaConnectionAccessToken(appConnection, appConnectionDAL, kmsService);
|
||||||
|
|
||||||
|
const { data } = await request.get<TCamundaListClustersResponse>(`${IntegrationUrls.CAMUNDA_API_URL}/clusters`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
"Accept-Encoding": "application/json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return data ?? [];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const camundaConnectionService = (
|
||||||
|
getAppConnection: TGetAppConnectionFunc,
|
||||||
|
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
|
||||||
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
||||||
|
) => {
|
||||||
|
const listClusters = async (connectionId: string, actor: OrgServiceActor) => {
|
||||||
|
const appConnection = await getAppConnection(AppConnection.Camunda, connectionId, actor);
|
||||||
|
|
||||||
|
const clusters = await listCamundaClusters(appConnection, appConnectionDAL, kmsService);
|
||||||
|
|
||||||
|
return clusters;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
listClusters
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { DiscriminativePick } from "@app/lib/types";
|
||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
|
||||||
|
import {
|
||||||
|
CamundaConnectionSchema,
|
||||||
|
CreateCamundaConnectionSchema,
|
||||||
|
ValidateCamundaConnectionCredentialsSchema
|
||||||
|
} from "./camunda-connection-schema";
|
||||||
|
|
||||||
|
export type TCamundaConnection = z.infer<typeof CamundaConnectionSchema>;
|
||||||
|
|
||||||
|
export type TCamundaConnectionInput = z.infer<typeof CreateCamundaConnectionSchema> & {
|
||||||
|
app: AppConnection.Camunda;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TValidateCamundaConnectionCredentialsSchema = typeof ValidateCamundaConnectionCredentialsSchema;
|
||||||
|
|
||||||
|
export type TCamundaConnectionConfig = DiscriminativePick<TCamundaConnectionInput, "method" | "app" | "credentials"> & {
|
||||||
|
orgId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TAuthorizeCamundaConnection = {
|
||||||
|
access_token: string;
|
||||||
|
scope: string;
|
||||||
|
token_type: string;
|
||||||
|
expires_in: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TCamundaListClustersResponse = { uuid: string; name: string }[];
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export * from "./camunda-connection-enums";
|
||||||
|
export * from "./camunda-connection-fns";
|
||||||
|
export * from "./camunda-connection-schema";
|
||||||
|
export * from "./camunda-connection-types";
|
||||||
@@ -63,6 +63,7 @@ export enum IntegrationUrls {
|
|||||||
GITHUB_TOKEN_URL = "https://github.com/login/oauth/access_token",
|
GITHUB_TOKEN_URL = "https://github.com/login/oauth/access_token",
|
||||||
GITLAB_TOKEN_URL = "https://gitlab.com/oauth/token",
|
GITLAB_TOKEN_URL = "https://gitlab.com/oauth/token",
|
||||||
BITBUCKET_TOKEN_URL = "https://bitbucket.org/site/oauth2/access_token",
|
BITBUCKET_TOKEN_URL = "https://bitbucket.org/site/oauth2/access_token",
|
||||||
|
CAMUNDA_TOKEN_URL = "https://login.cloud.camunda.io/oauth/token",
|
||||||
|
|
||||||
// integration apps endpoints
|
// integration apps endpoints
|
||||||
GCP_API_URL = "https://cloudresourcemanager.googleapis.com",
|
GCP_API_URL = "https://cloudresourcemanager.googleapis.com",
|
||||||
@@ -94,6 +95,7 @@ export enum IntegrationUrls {
|
|||||||
HASURA_CLOUD_API_URL = "https://data.pro.hasura.io/v1/graphql",
|
HASURA_CLOUD_API_URL = "https://data.pro.hasura.io/v1/graphql",
|
||||||
AZURE_DEVOPS_API_URL = "https://dev.azure.com",
|
AZURE_DEVOPS_API_URL = "https://dev.azure.com",
|
||||||
HUMANITEC_API_URL = "https://api.humanitec.io",
|
HUMANITEC_API_URL = "https://api.humanitec.io",
|
||||||
|
CAMUNDA_API_URL = "https://api.cloud.camunda.io",
|
||||||
|
|
||||||
GCP_SECRET_MANAGER_SERVICE_NAME = "secretmanager.googleapis.com",
|
GCP_SECRET_MANAGER_SERVICE_NAME = "secretmanager.googleapis.com",
|
||||||
GCP_SECRET_MANAGER_URL = `https://${GCP_SECRET_MANAGER_SERVICE_NAME}`,
|
GCP_SECRET_MANAGER_URL = `https://${GCP_SECRET_MANAGER_SERVICE_NAME}`,
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -6,6 +6,7 @@ import {
|
|||||||
AwsConnectionMethod,
|
AwsConnectionMethod,
|
||||||
AzureAppConfigurationConnectionMethod,
|
AzureAppConfigurationConnectionMethod,
|
||||||
AzureKeyVaultConnectionMethod,
|
AzureKeyVaultConnectionMethod,
|
||||||
|
CamundaConnectionMethod,
|
||||||
DatabricksConnectionMethod,
|
DatabricksConnectionMethod,
|
||||||
GcpConnectionMethod,
|
GcpConnectionMethod,
|
||||||
GitHubConnectionMethod,
|
GitHubConnectionMethod,
|
||||||
@@ -30,7 +31,8 @@ export const APP_CONNECTION_MAP: Record<AppConnection, { name: string; image: st
|
|||||||
[AppConnection.Databricks]: { name: "Databricks", image: "Databricks.png" },
|
[AppConnection.Databricks]: { name: "Databricks", image: "Databricks.png" },
|
||||||
[AppConnection.Humanitec]: { name: "Humanitec", image: "Humanitec.png" },
|
[AppConnection.Humanitec]: { name: "Humanitec", image: "Humanitec.png" },
|
||||||
[AppConnection.Postgres]: { name: "PostgreSQL", image: "Postgres.png" },
|
[AppConnection.Postgres]: { name: "PostgreSQL", image: "Postgres.png" },
|
||||||
[AppConnection.MsSql]: { name: "Microsoft SQL Server", image: "MsSql.png" }
|
[AppConnection.MsSql]: { name: "Microsoft SQL Server", image: "MsSql.png" },
|
||||||
|
[AppConnection.Camunda]: { name: "Camunda", image: "Camunda.png" }
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAppConnectionMethodDetails = (method: TAppConnection["method"]) => {
|
export const getAppConnectionMethodDetails = (method: TAppConnection["method"]) => {
|
||||||
@@ -49,6 +51,8 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"])
|
|||||||
return { name: "Service Account Impersonation", icon: faUser };
|
return { name: "Service Account Impersonation", icon: faUser };
|
||||||
case DatabricksConnectionMethod.ServicePrincipal:
|
case DatabricksConnectionMethod.ServicePrincipal:
|
||||||
return { name: "Service Principal", icon: faUser };
|
return { name: "Service Principal", icon: faUser };
|
||||||
|
case CamundaConnectionMethod.ClientCredentials:
|
||||||
|
return { name: "Client Credentials", icon: faKey };
|
||||||
case HumanitecConnectionMethod.ApiToken:
|
case HumanitecConnectionMethod.ApiToken:
|
||||||
return { name: "API Token", icon: faKey };
|
return { name: "API Token", icon: faKey };
|
||||||
case PostgresConnectionMethod.UsernameAndPassword:
|
case PostgresConnectionMethod.UsernameAndPassword:
|
||||||
|
|||||||
@@ -7,5 +7,6 @@ export enum AppConnection {
|
|||||||
Databricks = "databricks",
|
Databricks = "databricks",
|
||||||
Humanitec = "humanitec",
|
Humanitec = "humanitec",
|
||||||
Postgres = "postgres",
|
Postgres = "postgres",
|
||||||
MsSql = "mssql"
|
MsSql = "mssql",
|
||||||
|
Camunda = "camunda"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ export type TMsSqlConnectionOption = TAppConnectionOptionBase & {
|
|||||||
app: AppConnection.MsSql;
|
app: AppConnection.MsSql;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TCamundaConnectionOption = TAppConnectionOptionBase & {
|
||||||
|
app: AppConnection.Camunda;
|
||||||
|
};
|
||||||
|
|
||||||
export type TAppConnectionOption =
|
export type TAppConnectionOption =
|
||||||
| TAwsConnectionOption
|
| TAwsConnectionOption
|
||||||
| TGitHubConnectionOption
|
| TGitHubConnectionOption
|
||||||
@@ -56,7 +60,8 @@ export type TAppConnectionOption =
|
|||||||
| TDatabricksConnectionOption
|
| TDatabricksConnectionOption
|
||||||
| THumanitecConnectionOption
|
| THumanitecConnectionOption
|
||||||
| TPostgresConnectionOption
|
| TPostgresConnectionOption
|
||||||
| TMsSqlConnectionOption;
|
| TMsSqlConnectionOption
|
||||||
|
| TCamundaConnectionOption;
|
||||||
|
|
||||||
export type TAppConnectionOptionMap = {
|
export type TAppConnectionOptionMap = {
|
||||||
[AppConnection.AWS]: TAwsConnectionOption;
|
[AppConnection.AWS]: TAwsConnectionOption;
|
||||||
@@ -68,4 +73,5 @@ export type TAppConnectionOptionMap = {
|
|||||||
[AppConnection.Humanitec]: THumanitecConnectionOption;
|
[AppConnection.Humanitec]: THumanitecConnectionOption;
|
||||||
[AppConnection.Postgres]: TPostgresConnectionOption;
|
[AppConnection.Postgres]: TPostgresConnectionOption;
|
||||||
[AppConnection.MsSql]: TMsSqlConnectionOption;
|
[AppConnection.MsSql]: TMsSqlConnectionOption;
|
||||||
|
[AppConnection.Camunda]: TCamundaConnectionOption;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { AppConnection } from "../enums";
|
||||||
|
import { TRootAppConnection } from "./root-connection";
|
||||||
|
|
||||||
|
export enum CamundaConnectionMethod {
|
||||||
|
ClientCredentials = "client-credentials"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TCamundaConnection = TRootAppConnection & { app: AppConnection.Camunda } & {
|
||||||
|
method: CamundaConnectionMethod.ClientCredentials;
|
||||||
|
credentials: {
|
||||||
|
clientId: string;
|
||||||
|
clientSecret: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@ import { TAppConnectionOption } from "./app-options";
|
|||||||
import { TAwsConnection } from "./aws-connection";
|
import { TAwsConnection } from "./aws-connection";
|
||||||
import { TAzureAppConfigurationConnection } from "./azure-app-configuration-connection";
|
import { TAzureAppConfigurationConnection } from "./azure-app-configuration-connection";
|
||||||
import { TAzureKeyVaultConnection } from "./azure-key-vault-connection";
|
import { TAzureKeyVaultConnection } from "./azure-key-vault-connection";
|
||||||
|
import { TCamundaConnection } from "./camunda-connection";
|
||||||
import { TDatabricksConnection } from "./databricks-connection";
|
import { TDatabricksConnection } from "./databricks-connection";
|
||||||
import { TGcpConnection } from "./gcp-connection";
|
import { TGcpConnection } from "./gcp-connection";
|
||||||
import { TGitHubConnection } from "./github-connection";
|
import { TGitHubConnection } from "./github-connection";
|
||||||
@@ -13,6 +14,7 @@ import { TPostgresConnection } from "./postgres-connection";
|
|||||||
export * from "./aws-connection";
|
export * from "./aws-connection";
|
||||||
export * from "./azure-app-configuration-connection";
|
export * from "./azure-app-configuration-connection";
|
||||||
export * from "./azure-key-vault-connection";
|
export * from "./azure-key-vault-connection";
|
||||||
|
export * from "./camunda-connection";
|
||||||
export * from "./databricks-connection";
|
export * from "./databricks-connection";
|
||||||
export * from "./gcp-connection";
|
export * from "./gcp-connection";
|
||||||
export * from "./github-connection";
|
export * from "./github-connection";
|
||||||
@@ -29,7 +31,8 @@ export type TAppConnection =
|
|||||||
| TDatabricksConnection
|
| TDatabricksConnection
|
||||||
| THumanitecConnection
|
| THumanitecConnection
|
||||||
| TPostgresConnection
|
| TPostgresConnection
|
||||||
| TMsSqlConnection;
|
| TMsSqlConnection
|
||||||
|
| TCamundaConnection;
|
||||||
|
|
||||||
export type TAvailableAppConnection = Pick<TAppConnection, "name" | "id">;
|
export type TAvailableAppConnection = Pick<TAppConnection, "name" | "id">;
|
||||||
|
|
||||||
@@ -66,4 +69,5 @@ export type TAppConnectionMap = {
|
|||||||
[AppConnection.Humanitec]: THumanitecConnection;
|
[AppConnection.Humanitec]: THumanitecConnection;
|
||||||
[AppConnection.Postgres]: TPostgresConnection;
|
[AppConnection.Postgres]: TPostgresConnection;
|
||||||
[AppConnection.MsSql]: TMsSqlConnection;
|
[AppConnection.MsSql]: TMsSqlConnection;
|
||||||
|
[AppConnection.Camunda]: TCamundaConnection;
|
||||||
};
|
};
|
||||||
|
|||||||
+5
@@ -12,6 +12,7 @@ import { AppConnectionHeader } from "../AppConnectionHeader";
|
|||||||
import { AwsConnectionForm } from "./AwsConnectionForm";
|
import { AwsConnectionForm } from "./AwsConnectionForm";
|
||||||
import { AzureAppConfigurationConnectionForm } from "./AzureAppConfigurationConnectionForm";
|
import { AzureAppConfigurationConnectionForm } from "./AzureAppConfigurationConnectionForm";
|
||||||
import { AzureKeyVaultConnectionForm } from "./AzureKeyVaultConnectionForm";
|
import { AzureKeyVaultConnectionForm } from "./AzureKeyVaultConnectionForm";
|
||||||
|
import { CamundaConnectionForm } from "./CamundaConnectionForm";
|
||||||
import { DatabricksConnectionForm } from "./DatabricksConnectionForm";
|
import { DatabricksConnectionForm } from "./DatabricksConnectionForm";
|
||||||
import { GcpConnectionForm } from "./GcpConnectionForm";
|
import { GcpConnectionForm } from "./GcpConnectionForm";
|
||||||
import { GitHubConnectionForm } from "./GitHubConnectionForm";
|
import { GitHubConnectionForm } from "./GitHubConnectionForm";
|
||||||
@@ -74,6 +75,8 @@ const CreateForm = ({ app, onComplete }: CreateFormProps) => {
|
|||||||
return <PostgresConnectionForm onSubmit={onSubmit} />;
|
return <PostgresConnectionForm onSubmit={onSubmit} />;
|
||||||
case AppConnection.MsSql:
|
case AppConnection.MsSql:
|
||||||
return <MsSqlConnectionForm onSubmit={onSubmit} />;
|
return <MsSqlConnectionForm onSubmit={onSubmit} />;
|
||||||
|
case AppConnection.Camunda:
|
||||||
|
return <CamundaConnectionForm onSubmit={onSubmit} />;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled App ${app}`);
|
throw new Error(`Unhandled App ${app}`);
|
||||||
}
|
}
|
||||||
@@ -128,6 +131,8 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => {
|
|||||||
return <PostgresConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
return <PostgresConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
||||||
case AppConnection.MsSql:
|
case AppConnection.MsSql:
|
||||||
return <MsSqlConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
return <MsSqlConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
||||||
|
case AppConnection.Camunda:
|
||||||
|
return <CamundaConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled App ${(appConnection as TAppConnection).app}`);
|
throw new Error(`Unhandled App ${(appConnection as TAppConnection).app}`);
|
||||||
}
|
}
|
||||||
|
|||||||
+148
@@ -0,0 +1,148 @@
|
|||||||
|
import { Controller, FormProvider, useForm } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
FormControl,
|
||||||
|
Input,
|
||||||
|
ModalClose,
|
||||||
|
SecretInput,
|
||||||
|
Select,
|
||||||
|
SelectItem
|
||||||
|
} from "@app/components/v2";
|
||||||
|
import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections";
|
||||||
|
import { CamundaConnectionMethod, TCamundaConnection } from "@app/hooks/api/appConnections";
|
||||||
|
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||||
|
|
||||||
|
import {
|
||||||
|
genericAppConnectionFieldsSchema,
|
||||||
|
GenericAppConnectionsFields
|
||||||
|
} from "./GenericAppConnectionFields";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
appConnection?: TCamundaConnection;
|
||||||
|
onSubmit: (formData: FormData) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||||
|
app: z.literal(AppConnection.Camunda)
|
||||||
|
});
|
||||||
|
|
||||||
|
const formSchema = z.discriminatedUnion("method", [
|
||||||
|
rootSchema.extend({
|
||||||
|
method: z.literal(CamundaConnectionMethod.ClientCredentials),
|
||||||
|
credentials: z.object({
|
||||||
|
clientId: z.string().trim().min(1, "Client ID required"),
|
||||||
|
clientSecret: z.string().trim().min(1, "Client secret required")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
type FormData = z.infer<typeof formSchema>;
|
||||||
|
|
||||||
|
export const CamundaConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||||
|
const isUpdate = Boolean(appConnection);
|
||||||
|
|
||||||
|
const form = useForm<FormData>({
|
||||||
|
resolver: zodResolver(formSchema),
|
||||||
|
defaultValues: appConnection ?? {
|
||||||
|
app: AppConnection.Camunda,
|
||||||
|
method: CamundaConnectionMethod.ClientCredentials
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
handleSubmit,
|
||||||
|
control,
|
||||||
|
formState: { isSubmitting, isDirty }
|
||||||
|
} = form;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormProvider {...form}>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
{!isUpdate && <GenericAppConnectionsFields />}
|
||||||
|
<Controller
|
||||||
|
name="method"
|
||||||
|
control={control}
|
||||||
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
tooltipText={`The method you would like to use to connect with ${
|
||||||
|
APP_CONNECTION_MAP[AppConnection.Camunda].name
|
||||||
|
}. This field cannot be changed after creation.`}
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Method"
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
isDisabled={isUpdate}
|
||||||
|
value={value}
|
||||||
|
onValueChange={(val) => onChange(val)}
|
||||||
|
className="w-full border border-mineshaft-500"
|
||||||
|
position="popper"
|
||||||
|
dropdownContainerClassName="max-w-none"
|
||||||
|
>
|
||||||
|
{Object.values(CamundaConnectionMethod).map((method) => {
|
||||||
|
return (
|
||||||
|
<SelectItem value={method} key={method}>
|
||||||
|
{getAppConnectionMethodDetails(method).name}
|
||||||
|
</SelectItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="credentials.clientId"
|
||||||
|
control={control}
|
||||||
|
shouldUnregister
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Client ID"
|
||||||
|
>
|
||||||
|
<Input {...field} placeholder="05810c8f-c44d-4bd0-a327-aab6dd77719b" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="credentials.clientSecret"
|
||||||
|
control={control}
|
||||||
|
shouldUnregister
|
||||||
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Client Secret"
|
||||||
|
>
|
||||||
|
<SecretInput
|
||||||
|
containerClassName="text-gray-400 group-focus-within:!border-primary-400/50 border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => onChange(e.target.value)}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div className="mt-8 flex items-center">
|
||||||
|
<Button
|
||||||
|
className="mr-4"
|
||||||
|
size="sm"
|
||||||
|
type="submit"
|
||||||
|
colorSchema="secondary"
|
||||||
|
isLoading={isSubmitting}
|
||||||
|
isDisabled={isSubmitting || !isDirty}
|
||||||
|
>
|
||||||
|
{isUpdate ? "Update Credentials" : "Connect to Camunda"}
|
||||||
|
</Button>
|
||||||
|
<ModalClose asChild>
|
||||||
|
<Button colorSchema="secondary" variant="plain">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</ModalClose>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</FormProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user