From 4c5f3859d655e4412f3c6156d9a6e1a9f2c73dd8 Mon Sep 17 00:00:00 2001
From: carlosmonastyrski
Date: Fri, 14 Mar 2025 11:59:13 -0300
Subject: [PATCH 1/5] Add dynamic secrets modal form on secrets overview page
---
.../OverviewPage/OverviewPage.tsx | 54 ++++++++-
.../components/ActionBar/ActionBar.tsx | 2 +-
.../AwsElastiCacheInputForm.tsx | 80 ++++++++++----
.../AwsIamInputForm.tsx | 84 ++++++++++----
.../AzureEntraIdInputForm.tsx | 101 +++++++++++------
.../CassandraInputForm.tsx | 81 ++++++++++----
.../CreateDynamicSecretForm.tsx | 35 +++---
.../ElasticSearchInputForm.tsx | 81 ++++++++++----
.../CreateDynamicSecretForm/LdapInputForm.tsx | 90 +++++++++++----
.../MongoAtlasInputForm.tsx | 81 ++++++++++----
.../MongoDBInputForm.tsx | 104 +++++++++++++-----
.../RabbitMqInputForm.tsx | 90 +++++++++++----
.../RedisInputForm.tsx | 81 ++++++++++----
.../SapAseInputForm.tsx | 81 ++++++++++----
.../SapHanaInputForm.tsx | 81 ++++++++++----
.../SnowflakeInputForm.tsx | 81 ++++++++++----
.../SqlDatabaseInputForm.tsx | 81 ++++++++++----
.../CreateDynamicSecretForm/TotpInputForm.tsx | 87 +++++++++++----
18 files changed, 1002 insertions(+), 373 deletions(-)
diff --git a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
index 78a2380d0..a611eb030 100644
--- a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
+++ b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
@@ -19,6 +19,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, useNavigate, useRouter, useSearch } from "@tanstack/react-router";
import { twMerge } from "tailwind-merge";
+import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { createNotification } from "@app/components/notifications";
import { ProjectPermissionCan } from "@app/components/permissions";
import {
@@ -49,8 +50,10 @@ import {
import { ROUTE_PATHS } from "@app/const/routes";
import {
ProjectPermissionActions,
+ ProjectPermissionDynamicSecretActions,
ProjectPermissionSub,
useProjectPermission,
+ useSubscription,
useWorkspace
} from "@app/context";
import { useDebounce, usePagination, usePopUp, useResetPageHelper } from "@app/hooks";
@@ -71,6 +74,7 @@ import { SecretType, SecretV3RawSanitized, TSecretFolder } from "@app/hooks/api/
import { ProjectType, ProjectVersion } from "@app/hooks/api/workspace/types";
import { useDynamicSecretOverview, useFolderOverview, useSecretOverview } from "@app/hooks/utils";
+import { CreateDynamicSecretForm } from "../SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm";
import { FolderForm } from "../SecretDashboardPage/components/ActionBar/FolderForm";
import { CreateSecretForm } from "./components/CreateSecretForm";
import { FolderBreadCrumbs } from "./components/FolderBreadCrumbs";
@@ -131,6 +135,7 @@ export const OverviewPage = () => {
const [searchFilter, setSearchFilter] = useState("");
const [debouncedSearchFilter, setDebouncedSearchFilter] = useDebounce(searchFilter);
const secretPath = (routerSearch?.secretPath as string) || "/";
+ const { subscription } = useSubscription();
const [filter, setFilter] = useState(DEFAULT_FILTER_STATE);
const [filterHistory, setFilterHistory] = useState<
@@ -178,6 +183,17 @@ export const OverviewPage = () => {
}, []);
const userAvailableEnvs = currentWorkspace?.environments || [];
+ const userAvailableDynamicSecretEnvs = userAvailableEnvs.filter((env) =>
+ permission.can(
+ ProjectPermissionDynamicSecretActions.CreateRootCredential,
+ subject(ProjectPermissionSub.DynamicSecrets, {
+ environment: env.id,
+ secretPath,
+ secretName: "*",
+ secretTags: ["*"]
+ })
+ )
+ );
const [visibleEnvs, setVisibleEnvs] = useState(userAvailableEnvs);
@@ -249,7 +265,9 @@ export const OverviewPage = () => {
"addSecretsInAllEnvs",
"addFolder",
"misc",
- "updateFolder"
+ "updateFolder",
+ "addDynamicSecret",
+ "upgradePlan"
] as const);
const handleFolderCreate = async (folderName: string, description: string | null) => {
@@ -845,6 +863,22 @@ export const OverviewPage = () => {
+
}
+ onClick={() => {
+ if (subscription && subscription.dynamicSecret) {
+ handlePopUpOpen("addDynamicSecret");
+ return;
+ }
+ handlePopUpOpen("upgradePlan");
+ }}
+ isDisabled={userAvailableDynamicSecretEnvs.length === 0}
+ variant="outline_bg"
+ className="h-10 text-left"
+ isFullWidth
+ >
+ Add Dynamic Secret
+
{
/>
+ handlePopUpToggle("addDynamicSecret", isOpen)}
+ projectSlug={projectSlug}
+ environments={userAvailableDynamicSecretEnvs}
+ secretPath={secretPath}
+ />
+ {subscription && (
+ handlePopUpToggle("upgradePlan", isOpen)}
+ text={
+ subscription.slug === null
+ ? "You can perform this action under an Enterprise license"
+ : "You can perform this action if you switch to Infisical's Team plan"
+ }
+ />
+ )}
);
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx
index d545ba748..28c58ec5f 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx
@@ -655,7 +655,7 @@ export const ActionBar = ({
isOpen={popUp.addDynamicSecret.isOpen}
onToggle={(isOpen) => handlePopUpToggle("addDynamicSecret", isOpen)}
projectSlug={projectSlug}
- environment={environment}
+ environments={[{ slug: environment, name: "not-used", id: "not-used" }]}
secretPath={secretPath}
/>
24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -59,13 +62,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const AwsElastiCacheInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -87,32 +90,42 @@ export const AwsElastiCacheInputForm = ({
revocationStatement: `{
"UserId": "{{username}}"
}`
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.AwsElastiCache, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (env) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.AwsElastiCache, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: env.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -299,6 +312,29 @@ export const AwsElastiCacheInputForm = ({
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
index 1acb24e8f..f0590a4e1 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
@@ -5,9 +5,10 @@ import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
-import { Button, FormControl, Input, TextArea } from "@app/components/v2";
+import { Button, FilterableSelect, FormControl, Input, TextArea } from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const formSchema = z.object({
provider: z.object({
@@ -40,7 +41,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -49,13 +51,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const AwsIamInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -64,31 +66,43 @@ export const AwsIamInputForm = ({
formState: { isSubmitting },
handleSubmit
} = useForm({
- resolver: zodResolver(formSchema)
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ environments: environments.length === 1 ? environments : []
+ }
});
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.AwsIam, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.AwsIam, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -286,6 +300,30 @@ export const AwsIamInputForm = ({
)}
/>
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
index 55cebe173..4ab20c064 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
@@ -12,7 +12,7 @@ import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
-import { Button, FormControl, Input } from "@app/components/v2";
+import { Button, FilterableSelect, FormControl, Input } from "@app/components/v2";
import {
DropdownMenu,
DropdownMenuContent,
@@ -23,6 +23,7 @@ import { Tooltip } from "@app/components/v2/Tooltip";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { useGetDynamicSecretProviderData } from "@app/hooks/api/dynamicSecret/queries";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const formSchema = z.object({
selectedUsers: z.array(
@@ -60,7 +61,8 @@ const formSchema = z.object({
name: z
.string()
.min(1)
- .refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ .refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -69,13 +71,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const AzureEntraIdInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -85,7 +87,10 @@ export const AzureEntraIdInputForm = ({
watch,
handleSubmit
} = useForm({
- resolver: zodResolver(formSchema)
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ environments: environments.length === 1 ? environments : []
+ }
});
const tenantId = watch("provider.tenantId");
const applicationId = watch("provider.applicationId");
@@ -107,38 +112,42 @@ export const AzureEntraIdInputForm = ({
selectedUsers,
provider,
maxTTL,
- defaultTTL
+ defaultTTL,
+ environments: selectedEnvs
}: TForm) => {
// wait till previous request is finished
- if (createDynamicSecret.isPending) return;
- try {
- selectedUsers.map(async (user: { id: string; name: string; email: string }) => {
- await createDynamicSecret.mutateAsync({
- provider: {
- type: DynamicSecretProviders.AzureEntraId,
- inputs: {
- userId: user.id,
- tenantId: provider.tenantId,
- email: user.email,
- applicationId: provider.applicationId,
- clientSecret: provider.clientSecret
- }
- },
- maxTTL,
- name: `${name}-${user.name}`,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
+ const promises = selectedEnvs.map(async (environment) => {
+ if (createDynamicSecret.isPending) return;
+ try {
+ selectedUsers.map(async (user: { id: string; name: string; email: string }) => {
+ await createDynamicSecret.mutateAsync({
+ provider: {
+ type: DynamicSecretProviders.AzureEntraId,
+ inputs: {
+ userId: user.id,
+ tenantId: provider.tenantId,
+ email: user.email,
+ applicationId: provider.applicationId,
+ clientSecret: provider.clientSecret
+ }
+ },
+ maxTTL,
+ name: `${name}-${user.name}`,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
});
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -373,6 +382,30 @@ export const AzureEntraIdInputForm = ({
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CreateDynamicSecretForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CreateDynamicSecretForm.tsx
index c8389fb38..a49ab620e 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CreateDynamicSecretForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CreateDynamicSecretForm.tsx
@@ -17,6 +17,7 @@ import { AnimatePresence, motion } from "framer-motion";
import { Modal, ModalContent } from "@app/components/v2";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
import { AwsElastiCacheInputForm } from "./AwsElastiCacheInputForm";
import { AwsIamInputForm } from "./AwsIamInputForm";
@@ -38,7 +39,7 @@ type Props = {
isOpen?: boolean;
onToggle: (isOpen: boolean) => void;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
secretPath: string;
};
@@ -129,7 +130,7 @@ export const CreateDynamicSecretForm = ({
isOpen,
onToggle,
projectSlug,
- environment,
+ environments,
secretPath
}: Props) => {
const [wizardStep, setWizardStep] = useState(WizardSteps.SelectProvider);
@@ -197,7 +198,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -215,7 +216,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -233,7 +234,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -251,7 +252,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -269,7 +270,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -287,7 +288,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -305,7 +306,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -323,7 +324,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -341,7 +342,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -359,7 +360,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -377,7 +378,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -395,7 +396,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -413,7 +414,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -432,7 +433,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
@@ -450,7 +451,7 @@ export const CreateDynamicSecretForm = ({
onCancel={handleFormReset}
projectSlug={projectSlug}
secretPath={secretPath}
- environment={environment}
+ environments={environments}
/>
)}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
index eb0a7008f..828f98110 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
@@ -9,6 +9,7 @@ import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Button,
+ FilterableSelect,
FormControl,
FormLabel,
IconButton,
@@ -19,6 +20,7 @@ import {
} from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const authMethods = [
{
@@ -73,7 +75,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -82,13 +85,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const ElasticSearchInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -107,32 +110,42 @@ export const ElasticSearchInputForm = ({
},
roles: ["superuser"],
port: 443
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.ElasticSearch, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.ElasticSearch, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
const selectedAuthType = watch("provider.auth.type");
@@ -406,6 +419,30 @@ export const ElasticSearchInputForm = ({
)}
/>
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
index ef74db5b8..361067d1b 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
@@ -7,9 +7,18 @@ import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
-import { Button, FormControl, Input, Select, SelectItem, TextArea } from "@app/components/v2";
+import {
+ Button,
+ FilterableSelect,
+ FormControl,
+ Input,
+ Select,
+ SelectItem,
+ TextArea
+} from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
enum CredentialType {
Dynamic = "dynamic",
@@ -69,7 +78,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -79,7 +89,7 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const LdapInputForm = ({
@@ -87,7 +97,7 @@ export const LdapInputForm = ({
onCancel,
secretPath,
projectSlug,
- environment
+ environments
}: Props) => {
const {
control,
@@ -107,7 +117,8 @@ export const LdapInputForm = ({
revocationLdif: "",
rollbackLdif: "",
credentialType: CredentialType.Dynamic
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
@@ -115,26 +126,35 @@ export const LdapInputForm = ({
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.Ldap, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.Ldap, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -369,6 +389,30 @@ export const LdapInputForm = ({
)}
/>
)}
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
index 4de9b8acc..a6725b652 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
@@ -13,6 +13,7 @@ import {
AccordionItem,
AccordionTrigger,
Button,
+ FilterableSelect,
FormControl,
FormLabel,
IconButton,
@@ -22,6 +23,7 @@ import {
} from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const formSchema = z.object({
provider: z.object({
@@ -63,7 +65,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -72,7 +75,7 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
const ATLAS_SCOPE_TYPES = [
@@ -93,7 +96,7 @@ const ATLAS_SCOPE_TYPES = [
export const MongoAtlasInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -108,7 +111,8 @@ export const MongoAtlasInputForm = ({
defaultValues: {
provider: {
roles: [{ databaseName: "", roleName: "" }]
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
@@ -124,26 +128,35 @@ export const MongoAtlasInputForm = ({
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.MongoAtlas, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.MongoAtlas, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -438,6 +451,30 @@ export const MongoAtlasInputForm = ({
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
index b2418f629..0a28a6913 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
@@ -7,9 +7,18 @@ import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
-import { Button, FormControl, FormLabel, IconButton, Input, SecretInput } from "@app/components/v2";
+import {
+ Button,
+ FilterableSelect,
+ FormControl,
+ FormLabel,
+ IconButton,
+ Input,
+ SecretInput
+} from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const formSchema = z.object({
provider: z.object({
@@ -46,7 +55,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -55,13 +65,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const MongoDBDatabaseInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -76,7 +86,8 @@ export const MongoDBDatabaseInputForm = ({
defaultValues: {
provider: {
roles: [{ roleName: "readWrite" }]
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
@@ -87,33 +98,42 @@ export const MongoDBDatabaseInputForm = ({
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: {
- type: DynamicSecretProviders.MongoDB,
- inputs: {
- ...provider,
- port: provider?.port ? provider.port : undefined,
- roles: provider.roles.map((el) => el.roleName)
- }
- },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: {
+ type: DynamicSecretProviders.MongoDB,
+ inputs: {
+ ...provider,
+ port: provider?.port ? provider.port : undefined,
+ roles: provider.roles.map((el) => el.roleName)
+ }
+ },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -321,6 +341,30 @@ export const MongoDBDatabaseInputForm = ({
)}
/>
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
index 21f8b40de..0a6b84d41 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
@@ -7,9 +7,18 @@ import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
-import { Button, FormControl, FormLabel, IconButton, Input, SecretInput } from "@app/components/v2";
+import {
+ Button,
+ FilterableSelect,
+ FormControl,
+ FormLabel,
+ IconButton,
+ Input,
+ SecretInput
+} from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const formSchema = z.object({
provider: z.object({
@@ -50,7 +59,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -59,13 +69,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const RabbitMqInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -89,32 +99,42 @@ export const RabbitMqInputForm = ({
}
},
tags: []
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.RabbitMq, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.RabbitMq, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
const selectedTags = watch("provider.tags");
@@ -405,6 +425,30 @@ export const RabbitMqInputForm = ({
)}
/>
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
index 9d9933b44..35f165056 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
@@ -11,6 +11,7 @@ import {
AccordionItem,
AccordionTrigger,
Button,
+ FilterableSelect,
FormControl,
Input,
SecretInput,
@@ -18,6 +19,7 @@ import {
} from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const formSchema = z.object({
provider: z.object({
@@ -50,7 +52,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -59,13 +62,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const RedisInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -81,32 +84,42 @@ export const RedisInputForm = ({
port: 6379,
creationStatement: "ACL SETUSER {{username}} on >{{password}} ~* &* +@all",
revocationStatement: "ACL DELUSER {{username}}"
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.Redis, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.Redis, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -313,6 +326,30 @@ export const RedisInputForm = ({
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
index efe6e0269..de32565da 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
@@ -11,12 +11,14 @@ import {
AccordionItem,
AccordionTrigger,
Button,
+ FilterableSelect,
FormControl,
Input,
TextArea
} from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const formSchema = z.object({
provider: z.object({
@@ -48,7 +50,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -57,13 +60,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const SapAseInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -82,32 +85,42 @@ sp_adduser '{{username}}', '{{username}}', null;
sp_role 'grant', 'mon_role', '{{username}}';`,
revocationStatement: `sp_dropuser '{{username}}';
sp_droplogin '{{username}}';`
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.SapAse, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.SapAse, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -291,6 +304,30 @@ sp_droplogin '{{username}}';`
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
index 1b0bd64b8..d31464665 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
@@ -11,6 +11,7 @@ import {
AccordionItem,
AccordionTrigger,
Button,
+ FilterableSelect,
FormControl,
Input,
SecretInput,
@@ -18,6 +19,7 @@ import {
} from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const formSchema = z.object({
provider: z.object({
@@ -50,7 +52,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -59,13 +62,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const SapHanaInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -82,32 +85,42 @@ GRANT "MONITORING" TO {{username}};`,
revocationStatement: `REVOKE "MONITORING" FROM {{username}};
DROP USER {{username}};`,
renewStatement: "ALTER USER {{username}} VALID UNTIL '{{expiration}}';"
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.SapHana, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.SapHana, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -311,6 +324,30 @@ DROP USER {{username}};`,
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
index a5f8b25d9..c5077f2ad 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
@@ -13,12 +13,14 @@ import {
AccordionItem,
AccordionTrigger,
Button,
+ FilterableSelect,
FormControl,
Input,
TextArea
} from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const formSchema = z.object({
provider: z.object({
@@ -54,7 +56,8 @@ const formSchema = z.object({
.string()
.trim()
.min(1)
- .refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ .refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -63,13 +66,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const SnowflakeInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -85,32 +88,42 @@ export const SnowflakeInputForm = ({
"CREATE USER {{username}} PASSWORD = '{{password}}' DEFAULT_ROLE = public DEFAULT_SECONDARY_ROLES = ('ALL') MUST_CHANGE_PASSWORD = FALSE DAYS_TO_EXPIRY = {{expiration}};",
revocationStatement: "DROP USER {{username}};",
renewStatement: "ALTER USER {{username}} SET DAYS_TO_EXPIRY = {{expiration}};"
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.Snowflake, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch (err) {
- createNotification({
- type: "error",
- text: err instanceof Error ? err.message : "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.Snowflake, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch (err) {
+ createNotification({
+ type: "error",
+ text: err instanceof Error ? err.message : "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -314,6 +327,30 @@ export const SnowflakeInputForm = ({
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
index 4af92b210..416d9c35b 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
@@ -12,6 +12,7 @@ import {
AccordionItem,
AccordionTrigger,
Button,
+ FilterableSelect,
FormControl,
Input,
SecretInput,
@@ -22,6 +23,7 @@ import {
import { useWorkspace } from "@app/context";
import { gatewaysQueryKeys, useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders, SqlProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
const passwordRequirementsSchema = z
.object({
@@ -79,7 +81,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
- name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -88,7 +91,7 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
const getSqlStatements = (provider: SqlProviders) => {
@@ -145,7 +148,7 @@ const getDefaultPort = (provider: SqlProviders) => {
export const SqlDatabaseInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -172,7 +175,8 @@ export const SqlDatabaseInputForm = ({
},
allowedSymbols: "-_.~!*"
}
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
@@ -181,26 +185,35 @@ export const SqlDatabaseInputForm = ({
gatewaysQueryKeys.listProjectGateways({ projectId: currentWorkspace.id })
);
- const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ maxTTL,
+ provider,
+ defaultTTL,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.SqlDatabase, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch {
- createNotification({
- type: "error",
- text: "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (env) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.SqlDatabase, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: env.slug
+ });
+ onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
const handleDatabaseChange = (type: SqlProviders) => {
@@ -649,6 +662,30 @@ export const SqlDatabaseInputForm = ({
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
index 01d5398f0..4ff83a741 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
@@ -5,9 +5,17 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
-import { Button, FormControl, Input, Select, SelectItem } from "@app/components/v2";
+import {
+ Button,
+ FilterableSelect,
+ FormControl,
+ Input,
+ Select,
+ SelectItem
+} from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
+import { WorkspaceEnv } from "@app/hooks/api/types";
enum ConfigType {
URL = "url",
@@ -52,7 +60,8 @@ const formSchema = z.object({
.string()
.trim()
.min(1)
- .refine((val) => val.toLowerCase() === val, "Must be lowercase")
+ .refine((val) => val.toLowerCase() === val, "Must be lowercase"),
+ environments: z.object({ name: z.string(), slug: z.string() }).array()
});
type TForm = z.infer;
@@ -62,13 +71,13 @@ type Props = {
onCancel: () => void;
secretPath: string;
projectSlug: string;
- environment: string;
+ environments: WorkspaceEnv[];
};
export const TotpInputForm = ({
onCompleted,
onCancel,
- environment,
+ environments,
secretPath,
projectSlug
}: Props) => {
@@ -82,7 +91,8 @@ export const TotpInputForm = ({
defaultValues: {
provider: {
configType: ConfigType.URL
- }
+ },
+ environments: environments.length === 1 ? environments : []
}
});
@@ -90,26 +100,33 @@ export const TotpInputForm = ({
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({ name, provider }: TForm) => {
+ const handleCreateDynamicSecret = async ({
+ name,
+ provider,
+ environments: selectedEnvs
+ }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.Totp, inputs: provider },
- maxTTL: "24h",
- name,
- path: secretPath,
- defaultTTL: "1m",
- projectSlug,
- environmentSlug: environment
- });
- onCompleted();
- } catch (err) {
- createNotification({
- type: "error",
- text: err instanceof Error ? err.message : "Failed to create dynamic secret"
- });
- }
+ const promises = selectedEnvs.map(async (environment) => {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.Totp, inputs: provider },
+ maxTTL: "24h",
+ name,
+ path: secretPath,
+ defaultTTL: "1m",
+ projectSlug,
+ environmentSlug: environment.slug
+ });
+ onCompleted();
+ } catch (err) {
+ createNotification({
+ type: "error",
+ text: err instanceof Error ? err.message : "Failed to create dynamic secret"
+ });
+ }
+ });
+ await Promise.all(promises);
};
return (
@@ -295,6 +312,30 @@ export const TotpInputForm = ({
>
)}
+ {environments.length > 1 && (
+ (
+
+ option.name}
+ getOptionValue={(option) => option.slug}
+ menuPlacement="top"
+ />
+
+ )}
+ />
+ )}
From e39d1a053081e98b5eaeede8abb40d517de9f5b9 Mon Sep 17 00:00:00 2001
From: carlosmonastyrski
Date: Fri, 14 Mar 2025 12:26:20 -0300
Subject: [PATCH 2/5] Fix call of onCompleted after all promises are resolved
---
.../secret-manager/OverviewPage/OverviewPage.tsx | 2 +-
.../components/ActionBar/ActionBar.tsx | 2 +-
.../AwsElastiCacheInputForm.tsx | 8 ++++++--
.../CreateDynamicSecretForm/AwsIamInputForm.tsx | 12 ++++++++----
.../AzureEntraIdInputForm.tsx | 14 +++++++++-----
.../CreateDynamicSecretForm/CassandraInputForm.tsx | 12 ++++++++----
.../ElasticSearchInputForm.tsx | 12 ++++++++----
.../CreateDynamicSecretForm/LdapInputForm.tsx | 12 ++++++++----
.../MongoAtlasInputForm.tsx | 12 ++++++++----
.../CreateDynamicSecretForm/MongoDBInputForm.tsx | 12 ++++++++----
.../CreateDynamicSecretForm/RabbitMqInputForm.tsx | 12 ++++++++----
.../CreateDynamicSecretForm/RedisInputForm.tsx | 12 ++++++++----
.../CreateDynamicSecretForm/SapAseInputForm.tsx | 12 ++++++++----
.../CreateDynamicSecretForm/SapHanaInputForm.tsx | 12 ++++++++----
.../CreateDynamicSecretForm/SnowflakeInputForm.tsx | 10 +++++++---
.../SqlDatabaseInputForm.tsx | 8 ++++++--
.../CreateDynamicSecretForm/TotpInputForm.tsx | 10 +++++++---
17 files changed, 117 insertions(+), 57 deletions(-)
diff --git a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
index a611eb030..12e0100b6 100644
--- a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
+++ b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
@@ -866,7 +866,7 @@ export const OverviewPage = () => {
}
onClick={() => {
- if (subscription && subscription.dynamicSecret) {
+ if (subscription?.dynamicSecret) {
handlePopUpOpen("addDynamicSecret");
return;
}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx
index 28c58ec5f..0cf131ba8 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx
@@ -655,7 +655,7 @@ export const ActionBar = ({
isOpen={popUp.addDynamicSecret.isOpen}
onToggle={(isOpen) => handlePopUpToggle("addDynamicSecret", isOpen)}
projectSlug={projectSlug}
- environments={[{ slug: environment, name: "not-used", id: "not-used" }]}
+ environments={[{ slug: environment, name: environment, id: "not-used" }]}
secretPath={secretPath}
/>
{
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
+ let hasErrors = false;
const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
@@ -117,15 +118,18 @@ export const AwsElastiCacheInputForm = ({
projectSlug,
environmentSlug: env.slug
});
- onCompleted();
} catch {
+ hasErrors = true;
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
index f0590a4e1..7b9996075 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
@@ -83,7 +83,8 @@ export const AwsIamInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.AwsIam, inputs: provider },
@@ -92,17 +93,20 @@ export const AwsIamInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch {
+ hasErrors = true;
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
index 4ab20c064..80ce5b361 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
@@ -116,8 +116,9 @@ export const AzureEntraIdInputForm = ({
environments: selectedEnvs
}: TForm) => {
// wait till previous request is finished
- const promises = selectedEnvs.map(async (environment) => {
- if (createDynamicSecret.isPending) return;
+ if (createDynamicSecret.isPending) return;
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
selectedUsers.map(async (user: { id: string; name: string; email: string }) => {
await createDynamicSecret.mutateAsync({
@@ -136,18 +137,21 @@ export const AzureEntraIdInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx
index f86a4728b..96c7958ee 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx
@@ -106,7 +106,8 @@ export const CassandraInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Cassandra, inputs: provider },
@@ -115,17 +116,20 @@ export const CassandraInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
index 828f98110..fbdd7ec75 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
@@ -126,7 +126,8 @@ export const ElasticSearchInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.ElasticSearch, inputs: provider },
@@ -135,17 +136,20 @@ export const ElasticSearchInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
const selectedAuthType = watch("provider.auth.type");
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
index 361067d1b..88a9a41b6 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
@@ -135,7 +135,8 @@ export const LdapInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Ldap, inputs: provider },
@@ -144,17 +145,20 @@ export const LdapInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
index a6725b652..e015f7f99 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
@@ -137,7 +137,8 @@ export const MongoAtlasInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.MongoAtlas, inputs: provider },
@@ -146,17 +147,20 @@ export const MongoAtlasInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
index 0a28a6913..729c6934d 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
@@ -107,7 +107,8 @@ export const MongoDBDatabaseInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: {
@@ -123,17 +124,20 @@ export const MongoDBDatabaseInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
index 0a6b84d41..7d8265662 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
@@ -115,7 +115,8 @@ export const RabbitMqInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.RabbitMq, inputs: provider },
@@ -124,17 +125,20 @@ export const RabbitMqInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
const selectedTags = watch("provider.tags");
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
index 35f165056..f19095cb1 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
@@ -100,7 +100,8 @@ export const RedisInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Redis, inputs: provider },
@@ -109,17 +110,20 @@ export const RedisInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
index de32565da..1fd2f63c0 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
@@ -101,7 +101,8 @@ sp_droplogin '{{username}}';`
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SapAse, inputs: provider },
@@ -110,17 +111,20 @@ sp_droplogin '{{username}}';`
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
index d31464665..ab86c67a2 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
@@ -101,7 +101,8 @@ DROP USER {{username}};`,
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SapHana, inputs: provider },
@@ -110,17 +111,20 @@ DROP USER {{username}};`,
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret in environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
index c5077f2ad..7c12e23f6 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
@@ -104,7 +104,8 @@ export const SnowflakeInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Snowflake, inputs: provider },
@@ -113,17 +114,20 @@ export const SnowflakeInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch (err) {
createNotification({
type: "error",
text: err instanceof Error ? err.message : "Failed to create dynamic secret"
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
index 416d9c35b..9632f4063 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
@@ -194,6 +194,7 @@ export const SqlDatabaseInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
+ let hasErrors = false;
const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
@@ -205,15 +206,18 @@ export const SqlDatabaseInputForm = ({
projectSlug,
environmentSlug: env.slug
});
- onCompleted();
} catch {
createNotification({
type: "error",
- text: "Failed to create dynamic secret"
+ text: `Failed to create dynamic secret for environment ${env.name}`
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
const handleDatabaseChange = (type: SqlProviders) => {
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
index 4ff83a741..a774c6c78 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
@@ -107,7 +107,8 @@ export const TotpInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- const promises = selectedEnvs.map(async (environment) => {
+ let hasErrors = false;
+ const promises = selectedEnvs.map(async (env) => {
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Totp, inputs: provider },
@@ -116,17 +117,20 @@ export const TotpInputForm = ({
path: secretPath,
defaultTTL: "1m",
projectSlug,
- environmentSlug: environment.slug
+ environmentSlug: env.slug
});
- onCompleted();
} catch (err) {
createNotification({
type: "error",
text: err instanceof Error ? err.message : "Failed to create dynamic secret"
});
+ hasErrors = true;
}
});
await Promise.all(promises);
+ if (hasErrors) {
+ onCompleted();
+ }
};
return (
From 94d7d2b0293a9d4aa6b12ceacdea98c8ab352208 Mon Sep 17 00:00:00 2001
From: carlosmonastyrski
Date: Fri, 14 Mar 2025 12:44:49 -0300
Subject: [PATCH 3/5] Fix call of onCompleted after all promises are resolved
---
.../CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx | 2 +-
.../CreateDynamicSecretForm/ElasticSearchInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx | 2 +-
.../ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx | 2 +-
15 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx
index 008c24165..ae3ddac05 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx
@@ -127,7 +127,7 @@ export const AwsElastiCacheInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
index 7b9996075..1f2e5b0a8 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
@@ -104,7 +104,7 @@ export const AwsIamInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
index 80ce5b361..f681a75a9 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
@@ -149,7 +149,7 @@ export const AzureEntraIdInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx
index 96c7958ee..a770d67b2 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx
@@ -127,7 +127,7 @@ export const CassandraInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
index fbdd7ec75..0fddf332c 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
@@ -147,7 +147,7 @@ export const ElasticSearchInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
index 88a9a41b6..cfa9fd45f 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
@@ -156,7 +156,7 @@ export const LdapInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
index e015f7f99..53c716200 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
@@ -158,7 +158,7 @@ export const MongoAtlasInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
index 729c6934d..46597291a 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
@@ -135,7 +135,7 @@ export const MongoDBDatabaseInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
index 7d8265662..ffe2164e8 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
@@ -136,7 +136,7 @@ export const RabbitMqInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
index f19095cb1..82a5f2bdf 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
@@ -121,7 +121,7 @@ export const RedisInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
index 1fd2f63c0..126b95712 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
@@ -122,7 +122,7 @@ sp_droplogin '{{username}}';`
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
index ab86c67a2..d4d45ea75 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
@@ -122,7 +122,7 @@ DROP USER {{username}};`,
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
index 7c12e23f6..d7e55c183 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
@@ -125,7 +125,7 @@ export const SnowflakeInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
index 9632f4063..d80d92c4a 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
@@ -215,7 +215,7 @@ export const SqlDatabaseInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
index a774c6c78..4609d2604 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
@@ -128,7 +128,7 @@ export const TotpInputForm = ({
}
});
await Promise.all(promises);
- if (hasErrors) {
+ if (!hasErrors) {
onCompleted();
}
};
From 6905029455550879c08b32ccbb18036d16e75d2a Mon Sep 17 00:00:00 2001
From: carlosmonastyrski
Date: Fri, 14 Mar 2025 14:59:19 -0300
Subject: [PATCH 4/5] Change overview dynamic secret creation modal to set only
one env
---
.../AwsElastiCacheInputForm.tsx | 50 ++++++-------
.../AwsIamInputForm.tsx | 51 ++++++--------
.../AzureEntraIdInputForm.tsx | 70 ++++++++-----------
.../CassandraInputForm.tsx | 51 ++++++--------
.../ElasticSearchInputForm.tsx | 50 ++++++-------
.../CreateDynamicSecretForm/LdapInputForm.tsx | 50 ++++++-------
.../MongoAtlasInputForm.tsx | 50 ++++++-------
.../MongoDBInputForm.tsx | 64 ++++++++---------
.../RabbitMqInputForm.tsx | 50 ++++++-------
.../RedisInputForm.tsx | 50 ++++++-------
.../SapAseInputForm.tsx | 50 ++++++-------
.../SapHanaInputForm.tsx | 50 ++++++-------
.../SnowflakeInputForm.tsx | 50 ++++++-------
.../SqlDatabaseInputForm.tsx | 51 ++++++--------
.../CreateDynamicSecretForm/TotpInputForm.tsx | 54 ++++++--------
15 files changed, 335 insertions(+), 456 deletions(-)
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx
index ae3ddac05..c326f9dbe 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx
@@ -53,7 +53,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -91,7 +91,7 @@ export const AwsElastiCacheInputForm = ({
"UserId": "{{username}}"
}`
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -102,33 +102,26 @@ export const AwsElastiCacheInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.AwsElastiCache, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- hasErrors = true;
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.AwsElastiCache, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -319,19 +312,18 @@ export const AwsElastiCacheInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
/>
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
index 1f2e5b0a8..ad8cd1b0e 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx
@@ -42,7 +42,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -68,7 +68,7 @@ export const AwsIamInputForm = ({
} = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -79,33 +79,27 @@ export const AwsIamInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.AwsIam, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- hasErrors = true;
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.AwsIam, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -307,19 +301,18 @@ export const AwsIamInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
index f681a75a9..4df6d7b5a 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx
@@ -62,7 +62,7 @@ const formSchema = z.object({
.string()
.min(1)
.refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -89,7 +89,7 @@ export const AzureEntraIdInputForm = ({
} = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
const tenantId = watch("provider.tenantId");
@@ -113,44 +113,37 @@ export const AzureEntraIdInputForm = ({
provider,
maxTTL,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- selectedUsers.map(async (user: { id: string; name: string; email: string }) => {
- await createDynamicSecret.mutateAsync({
- provider: {
- type: DynamicSecretProviders.AzureEntraId,
- inputs: {
- userId: user.id,
- tenantId: provider.tenantId,
- email: user.email,
- applicationId: provider.applicationId,
- clientSecret: provider.clientSecret
- }
- },
- maxTTL,
- name: `${name}-${user.name}`,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
+ try {
+ selectedUsers.map(async (user: { id: string; name: string; email: string }) => {
+ await createDynamicSecret.mutateAsync({
+ provider: {
+ type: DynamicSecretProviders.AzureEntraId,
+ inputs: {
+ userId: user.id,
+ tenantId: provider.tenantId,
+ email: user.email,
+ applicationId: provider.applicationId,
+ clientSecret: provider.clientSecret
+ }
+ },
+ maxTTL,
+ name: `${name}-${user.name}`,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
});
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -389,19 +382,18 @@ export const AzureEntraIdInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx
index a770d67b2..cd8486337 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx
@@ -55,7 +55,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -91,7 +91,7 @@ export const CassandraInputForm = ({
resolver: zodResolver(formSchema),
defaultValues: {
provider: getSqlStatements(),
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -102,33 +102,27 @@ export const CassandraInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.Cassandra, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.Cassandra, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -365,19 +359,18 @@ export const CassandraInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
index 0fddf332c..eea23a2e5 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
@@ -76,7 +76,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -111,7 +111,7 @@ export const ElasticSearchInputForm = ({
roles: ["superuser"],
port: 443
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -122,33 +122,26 @@ export const ElasticSearchInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.ElasticSearch, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.ElasticSearch, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -426,19 +419,18 @@ export const ElasticSearchInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
index cfa9fd45f..ca0e1befb 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx
@@ -79,7 +79,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -118,7 +118,7 @@ export const LdapInputForm = ({
rollbackLdif: "",
credentialType: CredentialType.Dynamic
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -131,33 +131,26 @@ export const LdapInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.Ldap, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.Ldap, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -396,19 +389,18 @@ export const LdapInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
index 53c716200..524f086d4 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx
@@ -66,7 +66,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -112,7 +112,7 @@ export const MongoAtlasInputForm = ({
provider: {
roles: [{ databaseName: "", roleName: "" }]
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -133,33 +133,26 @@ export const MongoAtlasInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.MongoAtlas, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.MongoAtlas, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -458,19 +451,18 @@ export const MongoAtlasInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
index 46597291a..87747c4db 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx
@@ -56,7 +56,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -87,7 +87,7 @@ export const MongoDBDatabaseInputForm = ({
provider: {
roles: [{ roleName: "readWrite" }]
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -103,40 +103,33 @@ export const MongoDBDatabaseInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: {
- type: DynamicSecretProviders.MongoDB,
- inputs: {
- ...provider,
- port: provider?.port ? provider.port : undefined,
- roles: provider.roles.map((el) => el.roleName)
- }
- },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: {
+ type: DynamicSecretProviders.MongoDB,
+ inputs: {
+ ...provider,
+ port: provider?.port ? provider.port : undefined,
+ roles: provider.roles.map((el) => el.roleName)
+ }
+ },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -348,19 +341,18 @@ export const MongoDBDatabaseInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
index ffe2164e8..fdecd23ab 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx
@@ -60,7 +60,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -100,7 +100,7 @@ export const RabbitMqInputForm = ({
},
tags: []
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -111,33 +111,26 @@ export const RabbitMqInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.RabbitMq, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.RabbitMq, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -432,19 +425,18 @@ export const RabbitMqInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
index 82a5f2bdf..b0f7bd5d6 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx
@@ -53,7 +53,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -85,7 +85,7 @@ export const RedisInputForm = ({
creationStatement: "ACL SETUSER {{username}} on >{{password}} ~* &* +@all",
revocationStatement: "ACL DELUSER {{username}}"
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -96,33 +96,26 @@ export const RedisInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.Redis, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.Redis, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -333,19 +326,18 @@ export const RedisInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
index 126b95712..0d8aad9b8 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx
@@ -51,7 +51,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -86,7 +86,7 @@ sp_role 'grant', 'mon_role', '{{username}}';`,
revocationStatement: `sp_dropuser '{{username}}';
sp_droplogin '{{username}}';`
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -97,33 +97,26 @@ sp_droplogin '{{username}}';`
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.SapAse, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.SapAse, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -311,19 +304,18 @@ sp_droplogin '{{username}}';`
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
index d4d45ea75..565dc849f 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx
@@ -53,7 +53,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -86,7 +86,7 @@ GRANT "MONITORING" TO {{username}};`,
DROP USER {{username}};`,
renewStatement: "ALTER USER {{username}} VALID UNTIL '{{expiration}}';"
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -97,33 +97,26 @@ DROP USER {{username}};`,
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.SapHana, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret in environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.SapHana, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -331,19 +324,18 @@ DROP USER {{username}};`,
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
index d7e55c183..e9442cbc3 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx
@@ -57,7 +57,7 @@ const formSchema = z.object({
.trim()
.min(1)
.refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -89,7 +89,7 @@ export const SnowflakeInputForm = ({
revocationStatement: "DROP USER {{username}};",
renewStatement: "ALTER USER {{username}} SET DAYS_TO_EXPIRY = {{expiration}};"
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -100,33 +100,26 @@ export const SnowflakeInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.Snowflake, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch (err) {
- createNotification({
- type: "error",
- text: err instanceof Error ? err.message : "Failed to create dynamic secret"
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.Snowflake, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch (err) {
+ createNotification({
+ type: "error",
+ text: err instanceof Error ? err.message : "Failed to create dynamic secret"
+ });
}
};
@@ -334,19 +327,18 @@ export const SnowflakeInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
index d80d92c4a..d5088f364 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx
@@ -82,7 +82,7 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -176,7 +176,7 @@ export const SqlDatabaseInputForm = ({
allowedSymbols: "-_.~!*"
}
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : undefined
}
});
@@ -190,33 +190,27 @@ export const SqlDatabaseInputForm = ({
maxTTL,
provider,
defaultTTL,
- environments: selectedEnvs
+ environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.SqlDatabase, inputs: provider },
- maxTTL,
- name,
- path: secretPath,
- defaultTTL,
- projectSlug,
- environmentSlug: env.slug
- });
- } catch {
- createNotification({
- type: "error",
- text: `Failed to create dynamic secret for environment ${env.name}`
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.SqlDatabase, inputs: provider },
+ maxTTL,
+ name,
+ path: secretPath,
+ defaultTTL,
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch {
+ createNotification({
+ type: "error",
+ text: "Failed to create dynamic secret"
+ });
}
};
@@ -669,19 +663,18 @@ export const SqlDatabaseInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
index 4609d2604..8207a117e 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx
@@ -61,7 +61,7 @@ const formSchema = z.object({
.trim()
.min(1)
.refine((val) => val.toLowerCase() === val, "Must be lowercase"),
- environments: z.object({ name: z.string(), slug: z.string() }).array()
+ environment: z.object({ name: z.string(), slug: z.string() })
});
type TForm = z.infer;
@@ -92,7 +92,7 @@ export const TotpInputForm = ({
provider: {
configType: ConfigType.URL
},
- environments: environments.length === 1 ? environments : []
+ environment: environments.length === 1 ? environments[0] : environments[0]
}
});
@@ -100,36 +100,25 @@ export const TotpInputForm = ({
const createDynamicSecret = useCreateDynamicSecret();
- const handleCreateDynamicSecret = async ({
- name,
- provider,
- environments: selectedEnvs
- }: TForm) => {
+ const handleCreateDynamicSecret = async ({ name, provider, environment }: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
- let hasErrors = false;
- const promises = selectedEnvs.map(async (env) => {
- try {
- await createDynamicSecret.mutateAsync({
- provider: { type: DynamicSecretProviders.Totp, inputs: provider },
- maxTTL: "24h",
- name,
- path: secretPath,
- defaultTTL: "1m",
- projectSlug,
- environmentSlug: env.slug
- });
- } catch (err) {
- createNotification({
- type: "error",
- text: err instanceof Error ? err.message : "Failed to create dynamic secret"
- });
- hasErrors = true;
- }
- });
- await Promise.all(promises);
- if (!hasErrors) {
+ try {
+ await createDynamicSecret.mutateAsync({
+ provider: { type: DynamicSecretProviders.Totp, inputs: provider },
+ maxTTL: "24h",
+ name,
+ path: secretPath,
+ defaultTTL: "1m",
+ projectSlug,
+ environmentSlug: environment.slug
+ });
onCompleted();
+ } catch (err) {
+ createNotification({
+ type: "error",
+ text: err instanceof Error ? err.message : "Failed to create dynamic secret"
+ });
}
};
@@ -319,19 +308,18 @@ export const TotpInputForm = ({
{environments.length > 1 && (
(
option.name}
getOptionValue={(option) => option.slug}
menuPlacement="top"
From e53439d586c24413182c57520ddbb1a11d556a08 Mon Sep 17 00:00:00 2001
From: carlosmonastyrski
Date: Fri, 14 Mar 2025 23:18:57 -0300
Subject: [PATCH 5/5] Improvements on dynamic secrets overview
---
.../OverviewPage/OverviewPage.tsx | 49 ++++++++++---------
.../components/ActionBar/ActionBar.tsx | 1 +
.../AwsElastiCacheInputForm.tsx | 8 +--
.../AwsIamInputForm.tsx | 8 +--
.../AzureEntraIdInputForm.tsx | 8 +--
.../CassandraInputForm.tsx | 8 +--
.../CreateDynamicSecretForm.tsx | 19 ++++++-
.../ElasticSearchInputForm.tsx | 8 +--
.../CreateDynamicSecretForm/LdapInputForm.tsx | 8 +--
.../MongoAtlasInputForm.tsx | 8 +--
.../MongoDBInputForm.tsx | 8 +--
.../RabbitMqInputForm.tsx | 8 +--
.../RedisInputForm.tsx | 8 +--
.../SapAseInputForm.tsx | 8 +--
.../SapHanaInputForm.tsx | 8 +--
.../SnowflakeInputForm.tsx | 8 +--
.../SqlDatabaseInputForm.tsx | 8 +--
.../CreateDynamicSecretForm/TotpInputForm.tsx | 8 +--
18 files changed, 121 insertions(+), 68 deletions(-)
diff --git a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
index 12e0100b6..34012bb2f 100644
--- a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
+++ b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx
@@ -187,10 +187,8 @@ export const OverviewPage = () => {
permission.can(
ProjectPermissionDynamicSecretActions.CreateRootCredential,
subject(ProjectPermissionSub.DynamicSecrets, {
- environment: env.id,
- secretPath,
- secretName: "*",
- secretTags: ["*"]
+ environment: env.slug,
+ secretPath
})
)
);
@@ -863,42 +861,49 @@ export const OverviewPage = () => {
-
}
- onClick={() => {
- if (subscription?.dynamicSecret) {
- handlePopUpOpen("addDynamicSecret");
- return;
- }
- handlePopUpOpen("upgradePlan");
- }}
- isDisabled={userAvailableDynamicSecretEnvs.length === 0}
- variant="outline_bg"
- className="h-10 text-left"
- isFullWidth
- >
- Add Dynamic Secret
-
{(isAllowed) => (
}
+ leftIcon={}
onClick={() => {
handlePopUpOpen("addFolder");
handlePopUpClose("misc");
}}
isDisabled={!isAllowed}
variant="outline_bg"
- className="h-10"
+ className="h-10 text-left"
isFullWidth
>
Add Folder
)}
+
+ }
+ onClick={() => {
+ if (subscription?.dynamicSecret) {
+ handlePopUpOpen("addDynamicSecret");
+ handlePopUpClose("misc");
+ return;
+ }
+ handlePopUpOpen("upgradePlan");
+ }}
+ isDisabled={userAvailableDynamicSecretEnvs.length === 0}
+ variant="outline_bg"
+ className="h-10 text-left"
+ isFullWidth
+ >
+ Add Dynamic Secret
+
+
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx
index 0cf131ba8..681ad99e3 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx
@@ -657,6 +657,7 @@ export const ActionBar = ({
projectSlug={projectSlug}
environments={[{ slug: environment, name: environment, id: "not-used" }]}
secretPath={secretPath}
+ isSingleEnvironmentMode
/>
{
const {
control,
@@ -91,7 +93,7 @@ export const AwsElastiCacheInputForm = ({
"UserId": "{{username}}"
}`
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -309,7 +311,7 @@ export const AwsElastiCacheInputForm = ({
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -68,7 +70,7 @@ export const AwsIamInputForm = ({
} = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -298,7 +300,7 @@ export const AwsIamInputForm = ({
)}
/>
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -89,7 +91,7 @@ export const AzureEntraIdInputForm = ({
} = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
const tenantId = watch("provider.tenantId");
@@ -379,7 +381,7 @@ export const AzureEntraIdInputForm = ({
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
@@ -81,7 +82,8 @@ export const CassandraInputForm = ({
onCancel,
environments,
secretPath,
- projectSlug
+ projectSlug,
+ isSingleEnvironmentMode
}: Props) => {
const {
control,
@@ -91,7 +93,7 @@ export const CassandraInputForm = ({
resolver: zodResolver(formSchema),
defaultValues: {
provider: getSqlStatements(),
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -356,7 +358,7 @@ export const CassandraInputForm = ({
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const [wizardStep, setWizardStep] = useState(WizardSteps.SelectProvider);
const [selectedProvider, setSelectedProvider] = useState(null);
@@ -199,6 +201,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -217,6 +220,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -235,6 +239,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -253,6 +258,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -271,6 +277,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -289,6 +296,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -307,6 +315,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -325,6 +334,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -343,6 +353,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -361,6 +372,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -379,6 +391,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -397,6 +410,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -415,6 +429,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -434,6 +449,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
@@ -452,6 +468,7 @@ export const CreateDynamicSecretForm = ({
projectSlug={projectSlug}
secretPath={secretPath}
environments={environments}
+ isSingleEnvironmentMode={isSingleEnvironmentMode}
/>
)}
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
index eea23a2e5..a7c84cb50 100644
--- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
+++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx
@@ -86,6 +86,7 @@ type Props = {
secretPath: string;
projectSlug: string;
environments: WorkspaceEnv[];
+ isSingleEnvironmentMode?: boolean;
};
export const ElasticSearchInputForm = ({
@@ -93,7 +94,8 @@ export const ElasticSearchInputForm = ({
onCancel,
environments,
secretPath,
- projectSlug
+ projectSlug,
+ isSingleEnvironmentMode
}: Props) => {
const {
control,
@@ -111,7 +113,7 @@ export const ElasticSearchInputForm = ({
roles: ["superuser"],
port: 443
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -416,7 +418,7 @@ export const ElasticSearchInputForm = ({
)}
/>
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -118,7 +120,7 @@ export const LdapInputForm = ({
rollbackLdif: "",
credentialType: CredentialType.Dynamic
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -386,7 +388,7 @@ export const LdapInputForm = ({
)}
/>
)}
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -112,7 +114,7 @@ export const MongoAtlasInputForm = ({
provider: {
roles: [{ databaseName: "", roleName: "" }]
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -448,7 +450,7 @@ export const MongoAtlasInputForm = ({
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -87,7 +89,7 @@ export const MongoDBDatabaseInputForm = ({
provider: {
roles: [{ roleName: "readWrite" }]
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -338,7 +340,7 @@ export const MongoDBDatabaseInputForm = ({
)}
/>
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -100,7 +102,7 @@ export const RabbitMqInputForm = ({
},
tags: []
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -422,7 +424,7 @@ export const RabbitMqInputForm = ({
)}
/>
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -85,7 +87,7 @@ export const RedisInputForm = ({
creationStatement: "ACL SETUSER {{username}} on >{{password}} ~* &* +@all",
revocationStatement: "ACL DELUSER {{username}}"
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -323,7 +325,7 @@ export const RedisInputForm = ({
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -86,7 +88,7 @@ sp_role 'grant', 'mon_role', '{{username}}';`,
revocationStatement: `sp_dropuser '{{username}}';
sp_droplogin '{{username}}';`
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -301,7 +303,7 @@ sp_droplogin '{{username}}';`
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -86,7 +88,7 @@ GRANT "MONITORING" TO {{username}};`,
DROP USER {{username}};`,
renewStatement: "ALTER USER {{username}} VALID UNTIL '{{expiration}}';"
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -321,7 +323,7 @@ DROP USER {{username}};`,
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -89,7 +91,7 @@ export const SnowflakeInputForm = ({
revocationStatement: "DROP USER {{username}};",
renewStatement: "ALTER USER {{username}} SET DAYS_TO_EXPIRY = {{expiration}};"
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -324,7 +326,7 @@ export const SnowflakeInputForm = ({
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
@@ -150,7 +151,8 @@ export const SqlDatabaseInputForm = ({
onCancel,
environments,
secretPath,
- projectSlug
+ projectSlug,
+ isSingleEnvironmentMode
}: Props) => {
const { currentWorkspace } = useWorkspace();
@@ -176,7 +178,7 @@ export const SqlDatabaseInputForm = ({
allowedSymbols: "-_.~!*"
}
},
- environment: environments.length === 1 ? environments[0] : undefined
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -660,7 +662,7 @@ export const SqlDatabaseInputForm = ({
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (
{
const {
control,
@@ -92,7 +94,7 @@ export const TotpInputForm = ({
provider: {
configType: ConfigType.URL
},
- environment: environments.length === 1 ? environments[0] : environments[0]
+ environment: isSingleEnvironmentMode ? environments[0] : undefined
}
});
@@ -305,7 +307,7 @@ export const TotpInputForm = ({
>
)}
- {environments.length > 1 && (
+ {!isSingleEnvironmentMode && (