Merge branch 'main' into feature/slack-secret-sync-error-notification

This commit is contained in:
Victor Santos
2025-11-07 10:03:56 -03:00
419 changed files with 7889 additions and 10146 deletions
@@ -140,22 +140,15 @@ export const RollbackPreviewTab = (): JSX.Element => {
);
const handleRollback = async (): Promise<void> => {
try {
await rollback(message);
await rollback(message);
createNotification({
type: "success",
text: "Rollback completed successfully"
});
createNotification({
type: "success",
text: "Rollback completed successfully"
});
handlePopUpClose("rollbackConfirm");
goBackToHistory();
} catch (error) {
createNotification({
type: "error",
text: error instanceof Error ? error.message : "Failed to rollback changes"
});
}
handlePopUpClose("rollbackConfirm");
goBackToHistory();
};
const folderChanges: FolderChanges[] = rollbackChangesNested || [];
@@ -64,39 +64,32 @@ export const IPAllowlistModal = ({ popUp, handlePopUpClose, handlePopUpToggle }:
}, [popUp?.trustedIp?.data]);
const onIPAllowlistModalSubmit = async ({ ipAddress, comment }: FormData) => {
try {
if (!currentProject?.id) return;
if (!currentProject?.id) return;
if (popUp?.trustedIp?.data) {
await updateTrustedIp.mutateAsync({
projectId: currentProject.id,
trustedIpId: (popUp?.trustedIp?.data as { trustedIpId: string })?.trustedIpId,
ipAddress,
comment,
isActive: true
});
} else {
await addTrustedIp.mutateAsync({
projectId: currentProject.id,
ipAddress,
comment,
isActive: true
});
}
createNotification({
text: `Successfully ${popUp?.trustedIp?.data ? "updated" : "added"} trusted IP`,
type: "success"
if (popUp?.trustedIp?.data) {
await updateTrustedIp.mutateAsync({
projectId: currentProject.id,
trustedIpId: (popUp?.trustedIp?.data as { trustedIpId: string })?.trustedIpId,
ipAddress,
comment,
isActive: true
});
reset();
handlePopUpClose("trustedIp");
} catch {
createNotification({
text: `Failed to ${popUp?.trustedIp?.data ? "update" : "add"} trusted IP`,
type: "error"
} else {
await addTrustedIp.mutateAsync({
projectId: currentProject.id,
ipAddress,
comment,
isActive: true
});
}
createNotification({
text: `Successfully ${popUp?.trustedIp?.data ? "updated" : "added"} trusted IP`,
type: "success"
});
reset();
handlePopUpClose("trustedIp");
};
return (
@@ -29,27 +29,19 @@ export const IPAllowlistSection = () => {
] as const);
const onDeleteTrustedIpSubmit = async (trustedIpId: string) => {
try {
if (!currentProject?.id) return;
if (!currentProject?.id) return;
await mutateAsync({
projectId: currentProject.id,
trustedIpId
});
await mutateAsync({
projectId: currentProject.id,
trustedIpId
});
createNotification({
text: "Successfully deleted IP access range",
type: "success"
});
createNotification({
text: "Successfully deleted IP access range",
type: "success"
});
handlePopUpClose("deleteTrustedIp");
} catch (err) {
console.log(err);
createNotification({
text: "Failed to delete IP access range",
type: "error"
});
}
handlePopUpClose("deleteTrustedIp");
};
return (
@@ -53,28 +53,20 @@ export const IntegrationDetailsByIDPage = () => {
const navigate = useNavigate();
const handleIntegrationDelete = async (shouldDeleteIntegrationSecrets: boolean) => {
try {
await deleteIntegration({
id: integrationId,
workspaceId: currentProject.id,
shouldDeleteIntegrationSecrets
});
await deleteIntegration({
id: integrationId,
workspaceId: currentProject.id,
shouldDeleteIntegrationSecrets
});
createNotification({
type: "success",
text: "Deleted integration"
});
createNotification({
type: "success",
text: "Deleted integration"
});
await navigate({
to: `/${ProjectType.SecretManager}/${projectId}/integrations`
});
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to delete integration"
});
}
await navigate({
to: `/${ProjectType.SecretManager}/${projectId}/integrations`
});
};
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
@@ -108,43 +108,27 @@ export const NativeIntegrationsTab = () => {
shouldDeleteIntegrationSecrets: boolean,
cb: () => void
) => {
try {
await deleteIntegration({ id: integrationId, workspaceId, shouldDeleteIntegrationSecrets });
if (cb) cb();
createNotification({
type: "success",
text: "Deleted integration"
});
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to delete integration"
});
}
await deleteIntegration({ id: integrationId, workspaceId, shouldDeleteIntegrationSecrets });
if (cb) cb();
createNotification({
type: "success",
text: "Deleted integration"
});
};
const handleIntegrationAuthRevoke = async (provider: string, cb?: () => void) => {
const integrationAuthForProvider = integrationAuths?.[provider];
if (!integrationAuthForProvider) return;
try {
await deleteIntegrationAuths({
integration: provider,
workspaceId
});
if (cb) cb();
createNotification({
type: "success",
text: "Revoked provider authentication"
});
} catch (err) {
console.error(err);
createNotification({
type: "error",
text: "Failed to revoke provider authentication"
});
}
await deleteIntegrationAuths({
integration: provider,
workspaceId
});
if (cb) cb();
createNotification({
type: "success",
text: "Revoked provider authentication"
});
};
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
@@ -235,46 +235,32 @@ export const SecretSyncsTable = ({ secretSyncs }: Props) => {
const isAutoSyncEnabled = !secretSync.isAutoSyncEnabled;
try {
await updateSync.mutateAsync({
syncId: secretSync.id,
destination: secretSync.destination,
isAutoSyncEnabled,
projectId: secretSync.projectId
});
await updateSync.mutateAsync({
syncId: secretSync.id,
destination: secretSync.destination,
isAutoSyncEnabled,
projectId: secretSync.projectId
});
createNotification({
text: `Successfully ${isAutoSyncEnabled ? "enabled" : "disabled"} auto-sync for ${destinationName} Sync`,
type: "success"
});
} catch {
createNotification({
text: `Failed to ${isAutoSyncEnabled ? "enable" : "disable"} auto-sync for ${destinationName} Sync`,
type: "error"
});
}
createNotification({
text: `Successfully ${isAutoSyncEnabled ? "enabled" : "disabled"} auto-sync for ${destinationName} Sync`,
type: "success"
});
};
const handleTriggerSync = async (secretSync: TSecretSync) => {
const destinationName = SECRET_SYNC_MAP[secretSync.destination].name;
try {
await triggerSync.mutateAsync({
syncId: secretSync.id,
destination: secretSync.destination,
projectId: secretSync.projectId
});
await triggerSync.mutateAsync({
syncId: secretSync.id,
destination: secretSync.destination,
projectId: secretSync.projectId
});
createNotification({
text: `Successfully triggered ${destinationName} Sync`,
type: "success"
});
} catch {
createNotification({
text: `Failed to trigger ${destinationName} Sync`,
type: "error"
});
}
createNotification({
text: `Successfully triggered ${destinationName} Sync`,
type: "success"
});
};
return (
@@ -488,55 +488,47 @@ export const OverviewPage = () => {
};
const handleSecretCreate = async (env: string, key: string, value: string) => {
try {
// create folder if not existing
if (secretPath !== "/") {
// /hello/world -> [hello","world"]
const pathSegment = secretPath.split("/").filter(Boolean);
const parentPath = `/${pathSegment.slice(0, -1).join("/")}`;
const folderName = pathSegment.at(-1);
const canCreateFolder = permission.can(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.SecretFolders, {
environment: env,
secretPath: parentPath
})
);
if (folderName && parentPath && canCreateFolder) {
await getOrCreateFolder({
projectId,
path: parentPath,
environment: env,
name: folderName
});
}
// create folder if not existing
if (secretPath !== "/") {
// /hello/world -> [hello","world"]
const pathSegment = secretPath.split("/").filter(Boolean);
const parentPath = `/${pathSegment.slice(0, -1).join("/")}`;
const folderName = pathSegment.at(-1);
const canCreateFolder = permission.can(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.SecretFolders, {
environment: env,
secretPath: parentPath
})
);
if (folderName && parentPath && canCreateFolder) {
await getOrCreateFolder({
projectId,
path: parentPath,
environment: env,
name: folderName
});
}
const result = await createSecretV3({
environment: env,
projectId,
secretPath,
secretKey: key,
secretValue: value,
secretComment: "",
type: SecretType.Shared
});
}
const result = await createSecretV3({
environment: env,
projectId,
secretPath,
secretKey: key,
secretValue: value,
secretComment: "",
type: SecretType.Shared
});
if ("approval" in result) {
createNotification({
type: "info",
text: "Requested change has been sent for review"
});
} else {
createNotification({
type: "success",
text: "Successfully created secret"
});
}
} catch (error) {
console.log(error);
if ("approval" in result) {
createNotification({
type: "error",
text: "Failed to create secret"
type: "info",
text: "Requested change has been sent for review"
});
} else {
createNotification({
type: "success",
text: "Successfully created secret"
});
}
};
@@ -565,63 +557,47 @@ export const OverviewPage = () => {
secretValue = undefined;
}
try {
const result = await updateSecretV3({
environment: env,
projectId,
secretPath,
secretKey: key,
secretValue,
type
});
const result = await updateSecretV3({
environment: env,
projectId,
secretPath,
secretKey: key,
secretValue,
type
});
if ("approval" in result) {
createNotification({
type: "info",
text: "Requested change has been sent for review"
});
} else {
createNotification({
type: "success",
text: "Successfully updated secret"
});
}
} catch (error) {
console.log(error);
if ("approval" in result) {
createNotification({
type: "error",
text: "Failed to update secret"
type: "info",
text: "Requested change has been sent for review"
});
} else {
createNotification({
type: "success",
text: "Successfully updated secret"
});
}
};
const handleSecretDelete = async (env: string, key: string, secretId?: string) => {
try {
const result = await deleteSecretV3({
environment: env,
projectId,
secretPath,
secretKey: key,
secretId,
type: SecretType.Shared
});
const result = await deleteSecretV3({
environment: env,
projectId,
secretPath,
secretKey: key,
secretId,
type: SecretType.Shared
});
if ("approval" in result) {
createNotification({
type: "info",
text: "Requested change has been sent for review"
});
} else {
createNotification({
type: "success",
text: "Successfully deleted secret"
});
}
} catch (error) {
console.log(error);
if ("approval" in result) {
createNotification({
type: "error",
text: "Failed to delete secret"
type: "info",
text: "Requested change has been sent for review"
});
} else {
createNotification({
type: "success",
text: "Successfully deleted secret"
});
}
};
@@ -193,19 +193,12 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => {
const slugSchema = z.string().trim().toLowerCase().min(1);
const createNewTag = async (slug: string) => {
// TODO: Replace with slugSchema generic
try {
const parsedSlug = slugSchema.parse(slug);
await createWsTag.mutateAsync({
projectId,
tagSlug: parsedSlug,
tagColor: ""
});
} catch {
createNotification({
type: "error",
text: "Failed to create new tag"
});
}
const parsedSlug = slugSchema.parse(slug);
await createWsTag.mutateAsync({
projectId,
tagSlug: parsedSlug,
tagColor: ""
});
};
return (
@@ -65,20 +65,13 @@ export const SecretV2MigrationSection = () => {
const didProjectUpgradeFailed = workspaceDetails?.upgradeStatus === ProjectUpgradeStatus.Failed;
const handleMigrationSecretV2 = async () => {
try {
handlePopUpToggle("migrationInfo");
await migrateProjectToV3.mutateAsync({ projectId: currentProject?.id || "" });
refetch();
createNotification({
text: "Project upgrade started",
type: "success"
});
} catch {
createNotification({
text: "Failed to upgrade project",
type: "error"
});
}
handlePopUpToggle("migrationInfo");
await migrateProjectToV3.mutateAsync({ projectId: currentProject?.id || "" });
refetch();
createNotification({
text: "Project upgrade started",
type: "success"
});
};
const isAdmin = hasProjectRole(ProjectMembershipRole.Admin);
@@ -65,28 +65,20 @@ const Content = ({ accessRequest, onComplete, projectSlug }: ContentProps) => {
});
const onSubmit = async (form: FormData) => {
try {
const request = await update.mutateAsync({
requestId: accessRequest.id,
projectSlug,
...form
});
await queryClient.refetchQueries({
queryKey: accessApprovalKeys.getAccessApprovalPolicies(projectSlug)
});
const request = await update.mutateAsync({
requestId: accessRequest.id,
projectSlug,
...form
});
await queryClient.refetchQueries({
queryKey: accessApprovalKeys.getAccessApprovalPolicies(projectSlug)
});
createNotification({
type: "success",
text: "Access request updated successfully."
});
onComplete(request);
} catch (e) {
console.error(e);
createNotification({
type: "error",
text: "Failed to update access request"
});
}
createNotification({
type: "success",
text: "Access request updated successfully."
});
onComplete(request);
};
return (
@@ -178,8 +178,7 @@ export const ReviewAccessRequestModal = ({
text: `The request has been ${status}`,
type: status === "approved" ? "success" : "info"
});
} catch (error) {
console.error(error);
} catch {
setIsLoading(null);
return;
}
@@ -237,48 +237,40 @@ const Form = ({
}: TFormSchema) => {
if (!projectId) return;
try {
const bypassers = [...userBypassers, ...groupBypassers];
const bypassers = [...userBypassers, ...groupBypassers];
if (data.policyType === PolicyType.ChangePolicy) {
await createSecretApprovalPolicy({
...data,
approvers: [...userApprovers, ...groupApprovers],
bypassers: bypassers.length > 0 ? bypassers : undefined,
environments: environments.map((env) => env.slug),
projectId: currentProject?.id || ""
});
} else {
await createAccessApprovalPolicy({
...data,
approvers: sequenceApprovers?.flatMap((approvers, index) =>
approvers.user
.map(
(el) => ({ ...el, sequence: index + 1 }) as Omit<Approver, "isOrgMembershipActive">
)
.concat(approvers.group.map((el) => ({ ...el, sequence: index + 1 })))
),
approvalsRequired: sequenceApprovers?.map((el, index) => ({
stepNumber: index + 1,
numberOfApprovals: el.approvals
})),
bypassers: bypassers.length > 0 ? bypassers : undefined,
environments: environments.map((env) => env.slug),
projectSlug
});
}
createNotification({
type: "success",
text: "Successfully created policy"
if (data.policyType === PolicyType.ChangePolicy) {
await createSecretApprovalPolicy({
...data,
approvers: [...userApprovers, ...groupApprovers],
bypassers: bypassers.length > 0 ? bypassers : undefined,
environments: environments.map((env) => env.slug),
projectId: currentProject?.id || ""
});
onToggle(false);
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to create policy"
} else {
await createAccessApprovalPolicy({
...data,
approvers: sequenceApprovers?.flatMap((approvers, index) =>
approvers.user
.map(
(el) => ({ ...el, sequence: index + 1 }) as Omit<Approver, "isOrgMembershipActive">
)
.concat(approvers.group.map((el) => ({ ...el, sequence: index + 1 })))
),
approvalsRequired: sequenceApprovers?.map((el, index) => ({
stepNumber: index + 1,
numberOfApprovals: el.approvals
})),
bypassers: bypassers.length > 0 ? bypassers : undefined,
environments: environments.map((env) => env.slug),
projectSlug
});
}
createNotification({
type: "success",
text: "Successfully created policy"
});
onToggle(false);
};
const handleUpdatePolicy = async ({
@@ -293,50 +285,42 @@ const Form = ({
if (!projectId || !projectSlug) return;
if (!editValues?.id) return;
try {
const bypassers = [...userBypassers, ...groupBypassers];
const bypassers = [...userBypassers, ...groupBypassers];
if (data.policyType === PolicyType.ChangePolicy) {
await updateSecretApprovalPolicy({
id: editValues?.id,
...data,
approvers: [...userApprovers, ...groupApprovers],
bypassers: bypassers.length > 0 ? bypassers : undefined,
projectId: currentProject?.id || "",
environments: environments.map((env) => env.slug)
});
} else {
await updateAccessApprovalPolicy({
id: editValues?.id,
...data,
approvers: sequenceApprovers?.flatMap((approvers, index) =>
approvers.user
.map(
(el) => ({ ...el, sequence: index + 1 }) as Omit<Approver, "isOrgMembershipActive">
)
.concat(approvers.group.map((el) => ({ ...el, sequence: index + 1 })))
),
approvalsRequired: sequenceApprovers?.map((el, index) => ({
stepNumber: index + 1,
numberOfApprovals: el.approvals
})),
bypassers: bypassers.length > 0 ? bypassers : undefined,
environments: environments.map((env) => env.slug),
projectSlug
});
}
createNotification({
type: "success",
text: "Successfully updated policy"
if (data.policyType === PolicyType.ChangePolicy) {
await updateSecretApprovalPolicy({
id: editValues?.id,
...data,
approvers: [...userApprovers, ...groupApprovers],
bypassers: bypassers.length > 0 ? bypassers : undefined,
projectId: currentProject?.id || "",
environments: environments.map((env) => env.slug)
});
onToggle(false);
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "failed to update policy"
} else {
await updateAccessApprovalPolicy({
id: editValues?.id,
...data,
approvers: sequenceApprovers?.flatMap((approvers, index) =>
approvers.user
.map(
(el) => ({ ...el, sequence: index + 1 }) as Omit<Approver, "isOrgMembershipActive">
)
.concat(approvers.group.map((el) => ({ ...el, sequence: index + 1 })))
),
approvalsRequired: sequenceApprovers?.map((el, index) => ({
stepNumber: index + 1,
numberOfApprovals: el.approvals
})),
bypassers: bypassers.length > 0 ? bypassers : undefined,
environments: environments.map((env) => env.slug),
projectSlug
});
}
createNotification({
type: "success",
text: "Successfully updated policy"
});
onToggle(false);
};
const handleFormSubmit = async (data: TFormSchema) => {
@@ -32,29 +32,22 @@ export const RemoveApprovalPolicyModal = ({
const { currentProject } = useProject();
const handleDeletePolicy = async () => {
try {
if (policyType === PolicyType.ChangePolicy) {
await deleteSecretApprovalPolicy({
projectId: currentProject.id,
id: policyId
});
} else {
await deleteAccessApprovalPolicy({
projectSlug: currentProject.slug,
id: policyId
});
}
createNotification({
type: "success",
text: "Successfully deleted policy"
if (policyType === PolicyType.ChangePolicy) {
await deleteSecretApprovalPolicy({
projectId: currentProject.id,
id: policyId
});
onOpenChange(false);
} catch {
createNotification({
type: "error",
text: "Failed to delete policy"
} else {
await deleteAccessApprovalPolicy({
projectSlug: currentProject.slug,
id: policyId
});
}
createNotification({
type: "success",
text: "Successfully deleted policy"
});
onOpenChange(false);
};
const deleteSecretApprovalData = useGetSecretApprovalRequestCount({
@@ -40,7 +40,7 @@ import {
PreferenceKey,
setUserTablePreference
} from "@app/helpers/userTablePreferences";
import { usePagination } from "@app/hooks";
import { usePagination, useResetPageHelper } from "@app/hooks";
import {
useGetSecretApprovalRequestCount,
useGetSecretApprovalRequests,
@@ -99,6 +99,12 @@ export const SecretApprovalRequest = () => {
const totalApprovalCount = data?.totalCount ?? 0;
const secretApprovalRequests = data?.approvals ?? [];
useResetPageHelper({
totalCount: totalApprovalCount,
offset,
setPage
});
const { data: secretApprovalRequestCount, isSuccess: isSecretApprovalReqCountSuccess } =
useGetSecretApprovalRequestCount({ projectId });
const { user: userSession } = useUser();
@@ -107,7 +113,7 @@ export const SecretApprovalRequest = () => {
});
const { permission } = useProjectPermission();
const { data: members } = useGetWorkspaceUsers(projectId);
const { data: members } = useGetWorkspaceUsers(projectId, true);
const isSecretApprovalScreen = Boolean(selectedApprovalId);
const { requestId } = search;
@@ -59,43 +59,27 @@ export const SecretApprovalRequestAction = ({
};
const handleSecretApprovalRequestMerge = async () => {
try {
await performSecretApprovalMerge({
id: approvalRequestId,
projectId,
bypassReason: byPassApproval ? bypassReason : undefined
});
createNotification({
type: "success",
text: "Successfully merged the request"
});
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to update the request status"
});
}
await performSecretApprovalMerge({
id: approvalRequestId,
projectId,
bypassReason: byPassApproval ? bypassReason : undefined
});
createNotification({
type: "success",
text: "Successfully merged the request"
});
};
const handleSecretApprovalStatusChange = async (reqState: "open" | "close") => {
try {
await updateSecretStatusChange({
id: approvalRequestId,
status: reqState,
projectId
});
createNotification({
type: "success",
text: "Successfully updated the request"
});
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to update the request status"
});
}
await updateSecretStatusChange({
id: approvalRequestId,
status: reqState,
projectId
});
createNotification({
type: "success",
text: "Successfully updated the request"
});
};
const isSoftEnforcement = enforcementLevel === EnforcementLevel.Soft;
@@ -221,9 +221,7 @@ export const SecretApprovalRequestChangeItem = ({
<div className="mb-2">
<div className="text-sm font-medium text-mineshaft-300">Multi-line Encoding</div>
<div className="text-sm">
{secretVersion?.skipMultilineEncoding?.toString() || (
<span className="text-sm text-mineshaft-300">-</span>
)}{" "}
{secretVersion?.skipMultilineEncoding?.toString() || "false"}
</div>
</div>
</div>
@@ -366,9 +364,8 @@ export const SecretApprovalRequestChangeItem = ({
<div className="text-sm font-medium text-mineshaft-300">Multi-line Encoding</div>
<div className="text-sm">
{newVersion?.skipMultilineEncoding?.toString() ??
secretVersion?.skipMultilineEncoding?.toString() ?? (
<span className="text-sm text-mineshaft-300">-</span>
)}{" "}
secretVersion?.skipMultilineEncoding?.toString() ??
"false"}
</div>
</div>
</div>
@@ -174,23 +174,15 @@ export const SecretApprovalRequestChanges = ({ approvalRequestId, onGoBack }: Pr
);
const handleSecretApprovalStatusUpdate = async (status: ApprovalStatus, comment: string) => {
try {
await updateSecretApprovalRequestStatus({
id: approvalRequestId,
status,
comment
});
createNotification({
type: "success",
text: `Successfully ${status} the request`
});
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to update the request status"
});
}
await updateSecretApprovalRequestStatus({
id: approvalRequestId,
status,
comment
});
createNotification({
type: "success",
text: `Successfully ${status} the request`
});
handlePopUpToggle("reviewChanges", false);
reset({
@@ -338,45 +338,37 @@ const Page = () => {
const isProtectedBranch = Boolean(boardPolicy);
const handleCreateCommit = async (changes: PendingChanges, message: string) => {
try {
await createCommit({
projectId,
environment,
secretPath,
pendingChanges: changes,
message
});
await createCommit({
projectId,
environment,
secretPath,
pendingChanges: changes,
message
});
if (!isProtectedBranch) {
pendingChanges.secrets.forEach((secret) => {
if (secret.type === "update" && secret.secretValue !== undefined) {
queryClient.setQueryData(
dashboardKeys.getSecretValue({
projectId,
environment,
secretPath,
secretKey: secret.newSecretName ?? secret.secretKey,
isOverride: false
}),
{ value: secret.secretValue }
);
}
});
}
createNotification({
text: isProtectedBranch
? "Requested changes have been sent for review"
: "Changes saved successfully",
type: "success"
if (!isProtectedBranch) {
pendingChanges.secrets.forEach((secret) => {
if (secret.type === "update" && secret.secretValue !== undefined) {
queryClient.setQueryData(
dashboardKeys.getSecretValue({
projectId,
environment,
secretPath,
secretKey: secret.newSecretName ?? secret.secretKey,
isOverride: false
}),
{ value: secret.secretValue }
);
}
});
} catch (error) {
createNotification({
text: "Failed to save changes",
type: "error"
});
console.error(error);
}
createNotification({
text: isProtectedBranch
? "Requested changes have been sent for review"
: "Changes saved successfully",
type: "success"
});
};
const {
@@ -209,48 +209,40 @@ export const ActionBar = ({
const isOrgAdmin = hasOrgRole(OrgMembershipRole.Admin);
const handleFolderCreate = async (folderName: string, description: string | null) => {
try {
if (isBatchMode) {
const folderId = `${folderName}`;
const pendingFolderCreate: PendingFolderCreate = {
id: folderId,
resourceType: "folder",
type: PendingAction.Create,
folderName,
description: description || undefined,
parentPath: secretPath,
timestamp: Date.now()
};
if (isBatchMode) {
const folderId = `${folderName}`;
const pendingFolderCreate: PendingFolderCreate = {
id: folderId,
resourceType: "folder",
type: PendingAction.Create,
folderName,
description: description || undefined,
parentPath: secretPath,
timestamp: Date.now()
};
addPendingChange(pendingFolderCreate, {
projectId,
environment,
secretPath
});
handlePopUpClose("addFolder");
return;
}
await createFolder({
name: folderName,
path: secretPath,
environment,
addPendingChange(pendingFolderCreate, {
projectId,
description
environment,
secretPath
});
handlePopUpClose("addFolder");
createNotification({
type: "success",
text: "Successfully created folder"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to create folder"
});
return;
}
await createFolder({
name: folderName,
path: secretPath,
environment,
projectId,
description
});
handlePopUpClose("addFolder");
createNotification({
type: "success",
text: "Successfully created folder"
});
};
const handleSecretDownload = async () => {
@@ -323,26 +315,18 @@ export const ActionBar = ({
const handleSecretBulkDelete = async () => {
const bulkDeletedSecrets = Object.values(selectedSecrets);
try {
await deleteBatchSecretV3({
secretPath,
projectId,
environment,
secrets: bulkDeletedSecrets.map(({ key }) => ({ secretKey: key, type: SecretType.Shared }))
});
resetSelectedSecret();
handlePopUpClose("bulkDeleteSecrets");
createNotification({
type: "success",
text: "Successfully deleted secrets"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to delete secrets"
});
}
await deleteBatchSecretV3({
secretPath,
projectId,
environment,
secrets: bulkDeletedSecrets.map(({ key }) => ({ secretKey: key, type: SecretType.Shared }))
});
resetSelectedSecret();
handlePopUpClose("bulkDeleteSecrets");
createNotification({
type: "success",
text: "Successfully deleted secrets"
});
};
const handleSecretsMove = async ({
@@ -678,35 +662,23 @@ export const ActionBar = ({
};
const handleVaultImport = async (vaultPath: string, namespace: string) => {
try {
const result = await importVaultSecrets({
projectId,
environment,
secretPath,
vaultNamespace: namespace,
vaultSecretPath: vaultPath
});
if (result.status === VaultImportStatus.ApprovalRequired) {
createNotification({
type: "info",
text: "Secret change request created successfully. Awaiting approval."
});
} else {
createNotification({
type: "success",
text: "Successfully imported secrets from HashiCorp Vault"
});
}
} catch (err) {
console.error("Vault import error:", err);
const error = err as AxiosError<{ message?: string }>;
const errorMessage =
error.response?.data?.message || "Failed to import secrets from Vault. Please try again.";
const result = await importVaultSecrets({
projectId,
environment,
secretPath,
vaultNamespace: namespace,
vaultSecretPath: vaultPath
});
if (result.status === VaultImportStatus.ApprovalRequired) {
createNotification({
type: "error",
text: errorMessage
type: "info",
text: "Secret change request created successfully. Awaiting approval."
});
} else {
createNotification({
type: "success",
text: "Successfully imported secrets from HashiCorp Vault"
});
}
};
@@ -4,7 +4,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Accordion,
AccordionContent,
@@ -111,25 +110,18 @@ export const AwsElastiCacheInputForm = ({
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.AwsElastiCache, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.AwsElastiCache, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -4,7 +4,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Button,
FilterableSelect,
@@ -166,26 +165,19 @@ export const AwsIamInputForm = ({
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.AwsIam, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.AwsIam, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -6,7 +6,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import { Button, FilterableSelect, FormControl, Input } from "@app/components/v2";
import {
DropdownMenu,
@@ -112,34 +111,27 @@ export const AzureEntraIdInputForm = ({
}: 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.slug
});
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();
};
return (
@@ -5,7 +5,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import {
Accordion,
@@ -171,29 +170,22 @@ export const AzureSqlDatabaseInputForm = ({
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: {
type: DynamicSecretProviders.AzureSqlDatabase,
inputs: { ...provider, masterDatabase: "master" }
},
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
metadata,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: {
type: DynamicSecretProviders.AzureSqlDatabase,
inputs: { ...provider, masterDatabase: "master" }
},
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
metadata,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -4,7 +4,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Accordion,
AccordionContent,
@@ -112,25 +111,18 @@ export const CassandraInputForm = ({
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Cassandra, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Cassandra, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -7,7 +7,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Accordion,
AccordionContent,
@@ -386,25 +385,18 @@ export const CouchbaseInputForm = ({
const { useAdvancedBuckets, ...finalProvider } = transformedProvider;
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Couchbase, inputs: finalProvider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Couchbase, inputs: finalProvider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -6,7 +6,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Button,
FilterableSelect,
@@ -131,25 +130,18 @@ export const ElasticSearchInputForm = ({
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.ElasticSearch, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.ElasticSearch, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
const selectedAuthType = watch("provider.auth.type");
@@ -4,7 +4,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import { Button, FilterableSelect, FormControl, Input } from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
@@ -83,28 +82,21 @@ export const GcpIamInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
await createDynamicSecret.mutateAsync({
provider: {
type: DynamicSecretProviders.GcpIam,
inputs: {
...provider
}
},
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: {
type: DynamicSecretProviders.GcpIam,
inputs: {
...provider
}
},
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
});
onCompleted();
};
return (
@@ -4,7 +4,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import {
Button,
FilterableSelect,
@@ -71,27 +70,20 @@ export const GithubInputForm = ({
const handleCreateDynamicSecret = async ({ name, provider, environment }: TForm) => {
if (createDynamicSecret.isPending) return;
try {
await createDynamicSecret.mutateAsync({
provider: {
type: DynamicSecretProviders.Github,
inputs: {
...provider
}
},
defaultTTL: "1h", // Github is limited to 1 hour tokens
name,
path: secretPath,
projectSlug,
environmentSlug: environment.slug
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: {
type: DynamicSecretProviders.Github,
inputs: {
...provider
}
},
defaultTTL: "1h", // Github is limited to 1 hour tokens
name,
path: secretPath,
projectSlug,
environmentSlug: environment.slug
});
onCompleted();
};
return (
@@ -283,33 +283,26 @@ export const KubernetesInputForm = ({
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: {
type: DynamicSecretProviders.Kubernetes,
inputs: {
...provider,
url: provider.url || undefined
}
},
maxTTL: rest.maxTTL,
name: rest.name,
path: secretPath,
defaultTTL: rest.defaultTTL,
projectSlug,
environmentSlug: rest.environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: {
type: DynamicSecretProviders.Kubernetes,
inputs: {
...provider,
url: provider.url || undefined
}
},
maxTTL: rest.maxTTL,
name: rest.name,
path: secretPath,
defaultTTL: rest.defaultTTL,
projectSlug,
environmentSlug: rest.environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
onCompleted();
};
return (
@@ -4,7 +4,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Button,
FilterableSelect,
@@ -139,25 +138,18 @@ export const LdapInputForm = ({
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Ldap, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate,
environmentSlug: environment.slug
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Ldap, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate,
environmentSlug: environment.slug
});
onCompleted();
};
return (
@@ -6,7 +6,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Accordion,
AccordionContent,
@@ -143,25 +142,18 @@ export const MongoAtlasInputForm = ({
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.MongoAtlas, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.MongoAtlas, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -6,7 +6,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Button,
FilterableSelect,
@@ -113,32 +112,25 @@ export const MongoDBDatabaseInputForm = ({
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
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,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
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,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -6,7 +6,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Button,
FilterableSelect,
@@ -121,25 +120,18 @@ export const RabbitMqInputForm = ({
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.RabbitMq, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.RabbitMq, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
const selectedTags = watch("provider.tags");
@@ -4,7 +4,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Accordion,
AccordionContent,
@@ -104,26 +103,19 @@ export const RedisInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Redis, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Redis, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -4,7 +4,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Accordion,
AccordionContent,
@@ -105,26 +104,19 @@ sp_droplogin '{{username}}';`
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SapAse, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SapAse, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -4,7 +4,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Accordion,
AccordionContent,
@@ -105,26 +104,19 @@ DROP USER {{username}};`,
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SapHana, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate,
environmentSlug: environment.slug
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SapHana, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate,
environmentSlug: environment.slug
});
onCompleted();
};
return (
@@ -4,7 +4,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import {
Accordion,
AccordionContent,
@@ -102,26 +101,19 @@ export const SnowflakeInputForm = ({
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Snowflake, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch (err) {
createNotification({
type: "error",
text: err instanceof Error ? err.message : "Failed to create dynamic secret"
});
}
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Snowflake, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -5,7 +5,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import {
Accordion,
@@ -215,26 +214,19 @@ export const SqlDatabaseInputForm = ({
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SqlDatabase, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
metadata,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SqlDatabase, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
metadata,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
const handleDatabaseChange = (type: SqlProviders) => {
@@ -2,7 +2,6 @@ import { Controller, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import {
Button,
FilterableSelect,
@@ -100,23 +99,16 @@ export const TotpInputForm = ({
const handleCreateDynamicSecret = async ({ name, provider, environment }: 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.slug
});
onCompleted();
} catch (err) {
createNotification({
type: "error",
text: err instanceof Error ? err.message : "Failed to create dynamic secret"
});
}
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Totp, inputs: provider },
maxTTL: "24h",
name,
path: secretPath,
defaultTTL: "1m",
projectSlug,
environmentSlug: environment.slug
});
onCompleted();
};
return (
@@ -5,7 +5,6 @@ import ms from "ms";
import { z } from "zod";
import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import {
Accordion,
@@ -145,26 +144,19 @@ GRANT CREATE ON SCHEMA public TO {{username}};`,
usernameTemplate
}: TForm) => {
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Vertica, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
createNotification({
type: "error",
text: "Failed to create dynamic secret"
});
}
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Vertica, inputs: provider },
maxTTL,
name,
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
};
return (
@@ -101,11 +101,6 @@ export const CreateSecretImportForm = ({
text: "You do not have access to the selected environment/path",
type: "error"
});
} else {
createNotification({
type: "error",
text: "Failed to link secrets"
});
}
}
};
@@ -77,70 +77,55 @@ export const CreateSecretForm = ({
const slugSchema = z.string().trim().toLowerCase().min(1);
const createNewTag = async (slug: string) => {
// TODO: Replace with slugSchema generic
try {
const parsedSlug = slugSchema.parse(slug);
await createWsTag.mutateAsync({
projectId,
tagSlug: parsedSlug,
tagColor: ""
});
} catch {
createNotification({
type: "error",
text: "Failed to create new tag"
});
}
const parsedSlug = slugSchema.parse(slug);
await createWsTag.mutateAsync({
projectId,
tagSlug: parsedSlug,
tagColor: ""
});
};
const handleFormSubmit = async ({ key, value, tags }: TFormSchema) => {
try {
if (isBatchMode) {
const pendingSecretCreate: PendingSecretCreate = {
id: key,
type: PendingAction.Create,
secretKey: key,
secretValue: value || "",
secretComment: "",
tags: tags?.map((el) => ({ id: el.value, slug: el.label })),
timestamp: Date.now(),
resourceType: "secret"
};
addPendingChange(pendingSecretCreate, {
projectId,
environment,
secretPath
});
closePopUp(PopUpNames.CreateSecretForm);
reset();
return;
}
await createSecretV3({
environment,
projectId,
secretPath,
if (isBatchMode) {
const pendingSecretCreate: PendingSecretCreate = {
id: key,
type: PendingAction.Create,
secretKey: key,
secretValue: value || "",
secretComment: "",
type: SecretType.Shared,
tagIds: tags?.map((el) => el.value)
tags: tags?.map((el) => ({ id: el.value, slug: el.label })),
timestamp: Date.now(),
resourceType: "secret"
};
addPendingChange(pendingSecretCreate, {
projectId,
environment,
secretPath
});
closePopUp(PopUpNames.CreateSecretForm);
reset();
createNotification({
type: isProtectedBranch ? "info" : "success",
text: isProtectedBranch
? "Requested changes have been sent for review"
: "Successfully created secret"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to create secret"
});
return;
}
await createSecretV3({
environment,
projectId,
secretPath,
secretKey: key,
secretValue: value || "",
secretComment: "",
type: SecretType.Shared,
tagIds: tags?.map((el) => el.value)
});
closePopUp(PopUpNames.CreateSecretForm);
reset();
createNotification({
type: isProtectedBranch ? "info" : "success",
text: isProtectedBranch
? "Requested changes have been sent for review"
: "Successfully created secret"
});
};
const handlePaste = (e: ClipboardEvent<HTMLInputElement>) => {
@@ -441,30 +441,22 @@ export const CreateKubernetesDynamicSecretLease = ({
const handleDynamicSecretLeaseCreate = async ({ ttl, namespace }: TKubernetesForm) => {
if (createDynamicSecretLease.isPending) return;
try {
await createDynamicSecretLease.mutateAsync({
environmentSlug: environment,
projectSlug,
path: secretPath,
ttl,
dynamicSecretName,
config: {
namespace: namespace || undefined
},
provider
});
await createDynamicSecretLease.mutateAsync({
environmentSlug: environment,
projectSlug,
path: secretPath,
ttl,
dynamicSecretName,
config: {
namespace: namespace || undefined
},
provider
});
createNotification({
type: "success",
text: "Successfully leased dynamic secret"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to lease dynamic secret"
});
}
createNotification({
type: "success",
text: "Successfully leased dynamic secret"
});
};
const handleLeaseRegeneration = async (data: { ttl?: string }) => {
@@ -590,29 +582,21 @@ export const CreateDynamicSecretLease = ({
const handleDynamicSecretLeaseCreate = async ({ ttl }: TForm) => {
if (createDynamicSecretLease.isPending) return;
try {
await createDynamicSecretLease.mutateAsync({
environmentSlug: environment,
projectSlug,
path: secretPath,
ttl,
dynamicSecretName,
provider
});
await createDynamicSecretLease.mutateAsync({
environmentSlug: environment,
projectSlug,
path: secretPath,
ttl,
dynamicSecretName,
provider
});
createNotification({
type: "success",
text: "Successfully leased dynamic secret"
});
createNotification({
type: "success",
text: "Successfully leased dynamic secret"
});
setIsPreloading.off();
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to lease dynamic secret"
});
}
setIsPreloading.off();
};
const handleLeaseRegeneration = async (data: { ttl?: string }) => {
@@ -69,31 +69,23 @@ export const DynamicSecretLease = ({
const deleteDynamicSecretLease = useRevokeDynamicSecretLease();
const handleDynamicSecretDeleteLease = async () => {
try {
const { leaseId, isForced } = popUp.deleteSecret.data as {
leaseId: string;
isForced?: boolean;
};
await deleteDynamicSecretLease.mutateAsync({
environmentSlug: environment,
projectSlug,
path: secretPath,
dynamicSecretName,
leaseId,
isForced
});
handlePopUpClose("deleteSecret");
createNotification({
type: "success",
text: "Successfully deleted lease"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to delete lease"
});
}
const { leaseId, isForced } = popUp.deleteSecret.data as {
leaseId: string;
isForced?: boolean;
};
await deleteDynamicSecretLease.mutateAsync({
environmentSlug: environment,
projectSlug,
path: secretPath,
dynamicSecretName,
leaseId,
isForced
});
handlePopUpClose("deleteSecret");
createNotification({
type: "success",
text: "Successfully deleted lease"
});
};
const canRenew = !DYNAMIC_SECRETS_WITHOUT_RENEWAL.includes(dynamicSecret.type);
@@ -54,29 +54,21 @@ export const DynamicSecretListView = ({
const deleteDynamicSecret = useDeleteDynamicSecret();
const handleDynamicSecretDelete = async () => {
try {
const { name, isForced } = popUp.deleteDynamicSecret.data as TDynamicSecret & {
isForced?: boolean;
};
await deleteDynamicSecret.mutateAsync({
environmentSlug: environment,
projectSlug,
path: secretPath,
name,
isForced
});
handlePopUpClose("deleteDynamicSecret");
createNotification({
type: "success",
text: "Successfully deleted dynamic secret"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to delete dynamic secret"
});
}
const { name, isForced } = popUp.deleteDynamicSecret.data as TDynamicSecret & {
isForced?: boolean;
};
await deleteDynamicSecret.mutateAsync({
environmentSlug: environment,
projectSlug,
path: secretPath,
name,
isForced
});
handlePopUpClose("deleteDynamicSecret");
createNotification({
type: "success",
text: "Successfully deleted dynamic secret"
});
};
return (
@@ -101,31 +101,24 @@ export const EditDynamicSecretAwsElastiCacheProviderForm = ({
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -141,31 +141,24 @@ export const EditDynamicSecretAwsIamForm = ({
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -76,30 +76,23 @@ export const EditDynamicSecretAzureEntraIdForm = ({
const handleUpdateDynamicSecret = async ({ maxTTL, defaultTTL, newName, inputs }: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
newName: newName === dynamicSecret.name ? undefined : newName,
inputs
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
newName: newName === dynamicSecret.name ? undefined : newName,
inputs
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -162,33 +162,26 @@ export const EditDynamicSecretAzureSqlDatabaseForm = ({
}: TForm) => {
if (updateDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await updateDynamicSecret.mutateAsync({
projectSlug,
environmentSlug: environment,
path: secretPath,
name: dynamicSecret.name,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs: inputs ? { ...inputs, masterDatabase: "master" } : undefined,
newName: newName === dynamicSecret.name ? undefined : newName,
metadata,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await updateDynamicSecret.mutateAsync({
projectSlug,
environmentSlug: environment,
path: secretPath,
name: dynamicSecret.name,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs: inputs ? { ...inputs, masterDatabase: "master" } : undefined,
newName: newName === dynamicSecret.name ? undefined : newName,
metadata,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -103,31 +103,24 @@ export const EditDynamicSecretCassandraForm = ({
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -386,37 +386,30 @@ export const EditDynamicSecretCouchbaseForm = ({
})()
: transformedInputs;
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
defaultTTL,
maxTTL: maxTTL || undefined,
newName: newName === dynamicSecret.name ? undefined : newName,
metadata,
usernameTemplate:
!usernameTemplate || usernameTemplate === "{{randomUsername}}"
? undefined
: usernameTemplate,
inputs: finalInputs
}
});
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
defaultTTL,
maxTTL: maxTTL || undefined,
newName: newName === dynamicSecret.name ? undefined : newName,
metadata,
usernameTemplate:
!usernameTemplate || usernameTemplate === "{{randomUsername}}"
? undefined
: usernameTemplate,
inputs: finalInputs
}
});
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
onClose();
} catch (err) {
createNotification({
type: "error",
text: `Failed to update dynamic secret: ${err}`
});
}
onClose();
};
return (
@@ -123,31 +123,24 @@ export const EditDynamicSecretElasticSearchForm = ({
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
const selectedAuthType = watch("inputs.auth.type");
@@ -77,30 +77,23 @@ export const EditDynamicSecretGcpIamForm = ({
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -61,28 +61,21 @@ export const EditDynamicSecretGithubForm = ({
const handleUpdateDynamicSecret = async ({ inputs, newName }: TForm) => {
if (updateDynamicSecret.isPending) return;
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -189,38 +189,29 @@ export const EditDynamicSecretKubernetesForm = ({
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = formData.usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
inputs: {
...formData.inputs,
url: formData.inputs.url || undefined
},
newName: formData.newName === dynamicSecret.name ? undefined : formData.newName,
defaultTTL: formData.defaultTTL,
maxTTL: formData.maxTTL,
usernameTemplate:
!formData.usernameTemplate || isDefaultUsernameTemplate
? null
: formData.usernameTemplate
}
});
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
inputs: {
...formData.inputs,
url: formData.inputs.url || undefined
},
newName: formData.newName === dynamicSecret.name ? undefined : formData.newName,
defaultTTL: formData.defaultTTL,
maxTTL: formData.maxTTL,
usernameTemplate:
!formData.usernameTemplate || isDefaultUsernameTemplate ? null : formData.usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch (err) {
createNotification({
type: "error",
text: err instanceof Error ? err.message : "Failed to update dynamic secret"
});
}
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -119,31 +119,24 @@ export const EditDynamicSecretLdapForm = ({
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -142,31 +142,24 @@ export const EditDynamicSecretMongoAtlasForm = ({
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -108,36 +108,28 @@ export const EditDynamicSecretMongoDBForm = ({
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs: {
...inputs,
port: inputs?.port ? inputs.port : undefined,
roles: inputs?.roles?.map((el) => el.roleName)
},
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs: {
...inputs,
port: inputs?.port ? inputs.port : undefined,
roles: inputs?.roles?.map((el) => el.roleName)
},
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -100,31 +100,24 @@ export const EditDynamicSecretRabbitMqForm = ({
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
const selectedTags = watch("inputs.tags");
@@ -102,32 +102,24 @@ export const EditDynamicSecretRedisProviderForm = ({
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate,
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate,
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -101,31 +101,24 @@ export const EditDynamicSecretSapAseForm = ({
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -101,31 +101,24 @@ export const EditDynamicSecretSapHanaForm = ({
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -97,32 +97,25 @@ export const EditDynamicSecretSnowflakeForm = ({
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch (err) {
createNotification({
type: "error",
text: err instanceof Error ? err.message : "Failed to update dynamic secret"
});
}
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -167,36 +167,29 @@ export const EditDynamicSecretSqlProviderForm = ({
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs: {
...inputs,
gatewayId: isGatewayInActive ? null : inputs.gatewayId
},
newName: newName === dynamicSecret.name ? undefined : newName,
metadata,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs: {
...inputs,
gatewayId: isGatewayInActive ? null : inputs.gatewayId
},
newName: newName === dynamicSecret.name ? undefined : newName,
metadata,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -87,28 +87,21 @@ export const EditDynamicSecretTotpForm = ({
const handleUpdateDynamicSecret = async ({ inputs, newName }: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch (err) {
createNotification({
type: "error",
text: err instanceof Error ? err.message : "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -146,34 +146,28 @@ export const EditDynamicSecretVerticaForm = ({
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs: {
...inputs,
gatewayId: isGatewayInActive ? null : inputs.gatewayId
},
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
} catch {
createNotification({
type: "error",
text: "Failed to update dynamic secret"
});
}
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
projectSlug,
environmentSlug: environment,
data: {
maxTTL: maxTTL || undefined,
defaultTTL,
inputs: {
...inputs,
gatewayId: isGatewayInActive ? null : inputs.gatewayId
},
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
createNotification({
type: "success",
text: "Successfully updated dynamic secret"
});
};
return (
@@ -64,27 +64,19 @@ export const RenewDynamicSecretLease = ({
const handleDynamicSecretLeaseCreate = async ({ ttl }: TForm) => {
if (renewDynamicSecretLease.isPending) return;
try {
await renewDynamicSecretLease.mutateAsync({
environmentSlug: environment,
projectSlug,
path: secretPath,
ttl,
dynamicSecretName,
leaseId
});
onClose();
createNotification({
type: "success",
text: "Successfully renewed lease"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to renew lease"
});
}
await renewDynamicSecretLease.mutateAsync({
environmentSlug: environment,
projectSlug,
path: secretPath,
ttl,
dynamicSecretName,
leaseId
});
onClose();
createNotification({
type: "success",
text: "Successfully renewed lease"
});
};
return (
@@ -69,73 +69,65 @@ export const FolderListView = ({
oldFolderName?: string,
oldFolderDescription?: string
) => {
try {
const updateFolderData = popUp.updateFolder.data;
if (!updateFolderData) throw new Error("Update folder data is required");
const { id: folderId, pendingAction, isPending } = updateFolderData as TSecretFolder;
const updateFolderData = popUp.updateFolder.data;
if (!updateFolderData) throw new Error("Update folder data is required");
const { id: folderId, pendingAction, isPending } = updateFolderData as TSecretFolder;
if (isBatchMode) {
const isEditingPendingCreation = isPending && pendingAction === PendingAction.Create;
if (isBatchMode) {
const isEditingPendingCreation = isPending && pendingAction === PendingAction.Create;
if (isEditingPendingCreation) {
const updatedCreate: PendingFolderCreate = {
id: folderId,
type: PendingAction.Create,
folderName: newFolderName,
description: newFolderDescription || undefined,
parentPath: secretPath,
timestamp: Date.now(),
resourceType: "folder"
};
if (isEditingPendingCreation) {
const updatedCreate: PendingFolderCreate = {
id: folderId,
type: PendingAction.Create,
folderName: newFolderName,
description: newFolderDescription || undefined,
parentPath: secretPath,
timestamp: Date.now(),
resourceType: "folder"
};
addPendingChange(updatedCreate, {
projectId,
environment,
secretPath
});
} else {
const updateChange: PendingFolderUpdate = {
id: folderId,
type: PendingAction.Update,
originalFolderName: oldFolderName || "",
folderName: newFolderName,
originalDescription: oldFolderDescription,
description: newFolderDescription || undefined,
timestamp: Date.now(),
resourceType: "folder"
};
addPendingChange(updatedCreate, {
projectId,
environment,
secretPath
});
} else {
const updateChange: PendingFolderUpdate = {
id: folderId,
type: PendingAction.Update,
originalFolderName: oldFolderName || "",
folderName: newFolderName,
originalDescription: oldFolderDescription,
description: newFolderDescription || undefined,
timestamp: Date.now(),
resourceType: "folder"
};
addPendingChange(updateChange, {
projectId,
environment,
secretPath
});
}
handlePopUpClose("updateFolder");
return;
addPendingChange(updateChange, {
projectId,
environment,
secretPath
});
}
await updateFolder({
folderId,
name: newFolderName,
path: secretPath,
environment,
projectId,
description: newFolderDescription
});
handlePopUpClose("updateFolder");
createNotification({
type: "success",
text: "Successfully saved folder"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to save folder"
});
return;
}
await updateFolder({
folderId,
name: newFolderName,
path: secretPath,
environment,
projectId,
description: newFolderDescription
});
handlePopUpClose("updateFolder");
createNotification({
type: "success",
text: "Successfully saved folder"
});
};
const handleDeletePending = (id: string) => {
@@ -147,48 +139,40 @@ export const FolderListView = ({
};
const handleFolderDelete = async () => {
try {
const folderData = popUp.deleteFolder?.data as TSecretFolder;
const folderData = popUp.deleteFolder?.data as TSecretFolder;
if (isBatchMode) {
const pendingFolderDelete: PendingFolderDelete = {
id: folderData.id,
folderName: folderData.name,
folderPath: secretPath,
resourceType: "folder",
type: PendingAction.Delete,
timestamp: Date.now()
};
if (isBatchMode) {
const pendingFolderDelete: PendingFolderDelete = {
id: folderData.id,
folderName: folderData.name,
folderPath: secretPath,
resourceType: "folder",
type: PendingAction.Delete,
timestamp: Date.now()
};
addPendingChange(pendingFolderDelete, {
projectId,
environment,
secretPath
});
handlePopUpClose("deleteFolder");
return;
}
await deleteFolder({
folderId: folderData.id,
path: secretPath,
addPendingChange(pendingFolderDelete, {
projectId,
environment,
projectId
secretPath
});
handlePopUpClose("deleteFolder");
createNotification({
type: "success",
text: "Successfully deleted folder"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to delete folder"
});
return;
}
await deleteFolder({
folderId: folderData.id,
path: secretPath,
environment,
projectId
});
handlePopUpClose("deleteFolder");
createNotification({
type: "success",
text: "Successfully deleted folder"
});
};
const handleFolderClick = (name: string, isPending?: boolean) => {
@@ -118,24 +118,16 @@ export const SecretImportItem = ({
const handleResyncSecretReplication = async () => {
if (resyncSecretReplication.isPending) return;
try {
await resyncSecretReplication.mutateAsync({
id,
environment,
path: secretPath,
projectId: currentProject?.id || ""
});
createNotification({
text: "Please refresh the dashboard to view changes",
type: "success"
});
} catch (error) {
console.error(error);
createNotification({
text: "Failed to resync replication",
type: "error"
});
}
await resyncSecretReplication.mutateAsync({
id,
environment,
path: secretPath,
projectId: currentProject?.id || ""
});
createNotification({
text: "Please refresh the dashboard to view changes",
type: "success"
});
};
const handleRowClick = () => {
@@ -147,25 +147,17 @@ export const SecretImportListView = ({
const handleSecretImportDelete = async () => {
const { id: secretImportId } = popUp.deleteSecretImport?.data as { id: string };
try {
await deleteSecretImport({
projectId,
environment,
path: secretPath,
id: secretImportId
});
handlePopUpClose("deleteSecretImport");
createNotification({
type: "success",
text: "Successfully removed secret link"
});
} catch (err) {
console.error(err);
createNotification({
text: "Failed to remove secret link",
type: "error"
});
}
await deleteSecretImport({
projectId,
environment,
path: secretPath,
id: secretImportId
});
handlePopUpClose("deleteSecretImport");
createNotification({
type: "success",
text: "Successfully removed secret link"
});
};
const handleSecretImportReorder = ({ over, active }: DragEndEvent) => {
@@ -199,53 +199,37 @@ export const CreateReminderForm = ({
// Form submission handler
const handleFormSubmit = async (data: TReminderFormSchema) => {
try {
await createReminder({
repeatDays: data.repeatDays,
message: data.message,
recipients: data.recipients?.map((r) => r.value) || [],
secretId,
nextReminderDate: data.nextReminderDate,
fromDate: data.fromDate
});
await createReminder({
repeatDays: data.repeatDays,
message: data.message,
recipients: data.recipients?.map((r) => r.value) || [],
secretId,
nextReminderDate: data.nextReminderDate,
fromDate: data.fromDate
});
invalidateQueries();
invalidateQueries();
createNotification({
type: "success",
text: `Successfully ${isEditMode ? "updated" : "created"} secret reminder`
});
createNotification({
type: "success",
text: `Successfully ${isEditMode ? "updated" : "created"} secret reminder`
});
reset();
onOpenChange();
} catch (error) {
console.error("Failed to save reminder:", error);
createNotification({
type: "error",
text: "Failed to save reminder. Please try again."
});
}
reset();
onOpenChange();
};
// Delete reminder handler
const handleDeleteReminder = async () => {
try {
await deleteReminder({ reminderId: reminder?.id || "", secretId });
invalidateQueries();
reset();
onOpenChange();
await deleteReminder({ reminderId: reminder?.id || "", secretId });
invalidateQueries();
reset();
onOpenChange();
createNotification({
type: "success",
text: "Successfully deleted reminder"
});
} catch (error) {
console.error("Failed to delete reminder:", error);
createNotification({
type: "error",
text: "Failed to delete reminder. Please try again."
});
}
createNotification({
type: "success",
text: "Successfully deleted reminder"
});
};
// Handle reminder type change
@@ -293,174 +293,166 @@ export const SecretListView = ({
isSameTags &&
isSameRecipients;
try {
// personal secret change
let personalAction = false;
if (overrideAction === "deleted") {
await handleSecretOperation("delete", SecretType.Personal, oldKey, {
secretId: orgSecret.idOverride
});
personalAction = true;
} else if (overrideAction && idOverride) {
await handleSecretOperation("update", SecretType.Personal, oldKey, {
value: valueOverride,
newKey: hasKeyChanged ? key : undefined,
secretId: orgSecret.idOverride,
skipMultilineEncoding: modSecret.skipMultilineEncoding
});
personalAction = true;
} else if (overrideAction) {
await handleSecretOperation("create", SecretType.Personal, oldKey, {
value: valueOverride
});
personalAction = true;
}
// personal secret change
let personalAction = false;
if (overrideAction === "deleted") {
await handleSecretOperation("delete", SecretType.Personal, oldKey, {
secretId: orgSecret.idOverride
});
personalAction = true;
} else if (overrideAction && idOverride) {
await handleSecretOperation("update", SecretType.Personal, oldKey, {
value: valueOverride,
newKey: hasKeyChanged ? key : undefined,
secretId: orgSecret.idOverride,
skipMultilineEncoding: modSecret.skipMultilineEncoding
});
personalAction = true;
} else if (overrideAction) {
await handleSecretOperation("create", SecretType.Personal, oldKey, {
value: valueOverride
});
personalAction = true;
}
// shared secret change
if (!isSharedSecUnchanged && !personalAction) {
if (isBatchMode) {
const isEditingPendingCreation = isPending && pendingAction === PendingAction.Create;
// shared secret change
if (!isSharedSecUnchanged && !personalAction) {
if (isBatchMode) {
const isEditingPendingCreation = isPending && pendingAction === PendingAction.Create;
if (isEditingPendingCreation) {
const updatedCreate: PendingSecretCreate = {
id: orgSecret.id,
type: PendingAction.Create,
secretKey: key,
secretValue: value || "",
secretComment: comment || "",
skipMultilineEncoding: modSecret.skipMultilineEncoding || false,
tags: tags?.map((tag) => ({ id: tag.id, slug: tag.name || tag.slug || "" })) || [],
secretMetadata: secretMetadata || [],
timestamp: Date.now(),
resourceType: "secret",
originalKey: oldKey
};
if (isEditingPendingCreation) {
const updatedCreate: PendingSecretCreate = {
id: orgSecret.id,
type: PendingAction.Create,
secretKey: key,
secretValue: value || "",
secretComment: comment || "",
skipMultilineEncoding: modSecret.skipMultilineEncoding || false,
tags: tags?.map((tag) => ({ id: tag.id, slug: tag.name || tag.slug || "" })) || [],
secretMetadata: secretMetadata || [],
timestamp: Date.now(),
resourceType: "secret",
originalKey: oldKey
};
addPendingChange(updatedCreate, {
projectId,
environment,
secretPath
});
} else {
const trueOriginalSecret = getTrueOriginalSecret(
orgSecret,
pendingChangesRef.current.secrets
);
addPendingChange(updatedCreate, {
projectId,
environment,
secretPath
});
} else {
const trueOriginalSecret = getTrueOriginalSecret(
orgSecret,
pendingChangesRef.current.secrets
);
const updateChange: PendingSecretUpdate = {
id: orgSecret.id,
type: PendingAction.Update,
secretKey: trueOriginalSecret.key,
newSecretName: key,
originalValue: trueOriginalSecret.value,
secretValue: value,
originalComment: trueOriginalSecret.comment,
secretComment: comment,
originalSkipMultilineEncoding: trueOriginalSecret.skipMultilineEncoding,
skipMultilineEncoding: modSecret.skipMultilineEncoding,
originalTags:
trueOriginalSecret.tags?.map((tag) => ({ id: tag.id, slug: tag.slug })) || [],
tags: tags?.map((tag) => ({ id: tag.id, slug: tag.name || tag.slug || "" })) || [],
originalSecretMetadata: trueOriginalSecret.secretMetadata || [],
secretMetadata: secretMetadata || [],
timestamp: Date.now(),
resourceType: "secret",
existingSecret: orgSecret
};
const updateChange: PendingSecretUpdate = {
id: orgSecret.id,
type: PendingAction.Update,
secretKey: trueOriginalSecret.key,
newSecretName: key,
originalValue: trueOriginalSecret.value,
secretValue: value,
originalComment: trueOriginalSecret.comment,
secretComment: comment,
originalSkipMultilineEncoding: trueOriginalSecret.skipMultilineEncoding,
skipMultilineEncoding: modSecret.skipMultilineEncoding,
originalTags:
trueOriginalSecret.tags?.map((tag) => ({ id: tag.id, slug: tag.slug })) || [],
tags: tags?.map((tag) => ({ id: tag.id, slug: tag.name || tag.slug || "" })) || [],
originalSecretMetadata: trueOriginalSecret.secretMetadata || [],
secretMetadata: secretMetadata || [],
timestamp: Date.now(),
resourceType: "secret",
existingSecret: orgSecret
};
addPendingChange(updateChange, {
projectId,
environment,
secretPath
});
}
if (!isReminderEvent) {
handlePopUpClose("secretDetail");
}
if (cb) cb();
return;
addPendingChange(updateChange, {
projectId,
environment,
secretPath
});
}
await handleSecretOperation("update", SecretType.Shared, oldKey, {
value,
tags: tagIds,
comment,
reminderRepeatDays,
reminderNote,
reminderRecipients,
secretId: orgSecret.id,
newKey: hasKeyChanged ? key : undefined,
skipMultilineEncoding: modSecret.skipMultilineEncoding,
secretMetadata,
isRotatedSecret: orgSecret.isRotatedSecret,
secretValueHidden
});
if (!isReminderEvent) {
handlePopUpClose("secretDetail");
}
if (cb) cb();
}
queryClient.invalidateQueries({
queryKey: dashboardKeys.getDashboardSecrets({
projectId,
secretPath
})
});
queryClient.invalidateQueries({
queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath })
});
queryClient.invalidateQueries({
queryKey: secretSnapshotKeys.list({
projectId,
environment,
directory: secretPath
})
});
queryClient.invalidateQueries({
queryKey: secretSnapshotKeys.count({
projectId,
environment,
directory: secretPath
})
});
queryClient.invalidateQueries({
queryKey: commitKeys.count({ projectId, environment, directory: secretPath })
});
queryClient.invalidateQueries({
queryKey: commitKeys.history({
projectId,
environment,
directory: secretPath
})
});
queryClient.invalidateQueries({
queryKey: secretApprovalRequestKeys.count({ projectId })
});
if (!isReminderEvent) {
handlePopUpClose("secretDetail");
return;
}
let successMessage;
if (isReminderEvent) {
successMessage = reminderRepeatDays
? "Successfully saved secret reminder"
: "Successfully deleted secret reminder";
} else {
successMessage = "Successfully saved secrets";
}
createNotification({
type: isProtectedBranch && !personalAction ? "info" : "success",
text:
isProtectedBranch && !personalAction
? "Requested changes have been sent for review"
: successMessage
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to save secret"
await handleSecretOperation("update", SecretType.Shared, oldKey, {
value,
tags: tagIds,
comment,
reminderRepeatDays,
reminderNote,
reminderRecipients,
secretId: orgSecret.id,
newKey: hasKeyChanged ? key : undefined,
skipMultilineEncoding: modSecret.skipMultilineEncoding,
secretMetadata,
isRotatedSecret: orgSecret.isRotatedSecret,
secretValueHidden
});
if (cb) cb();
}
queryClient.invalidateQueries({
queryKey: dashboardKeys.getDashboardSecrets({
projectId,
secretPath
})
});
queryClient.invalidateQueries({
queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath })
});
queryClient.invalidateQueries({
queryKey: secretSnapshotKeys.list({
projectId,
environment,
directory: secretPath
})
});
queryClient.invalidateQueries({
queryKey: secretSnapshotKeys.count({
projectId,
environment,
directory: secretPath
})
});
queryClient.invalidateQueries({
queryKey: commitKeys.count({ projectId, environment, directory: secretPath })
});
queryClient.invalidateQueries({
queryKey: commitKeys.history({
projectId,
environment,
directory: secretPath
})
});
queryClient.invalidateQueries({
queryKey: secretApprovalRequestKeys.count({ projectId })
});
if (!isReminderEvent) {
handlePopUpClose("secretDetail");
}
let successMessage;
if (isReminderEvent) {
successMessage = reminderRepeatDays
? "Successfully saved secret reminder"
: "Successfully deleted secret reminder";
} else {
successMessage = "Successfully saved secrets";
}
createNotification({
type: isProtectedBranch && !personalAction ? "info" : "success",
text:
isProtectedBranch && !personalAction
? "Requested changes have been sent for review"
: successMessage
});
},
[environment, secretPath, isProtectedBranch, isBatchMode, projectId, addPendingChange]
);
@@ -488,75 +480,67 @@ export const SecretListView = ({
value,
secretValueHidden
} = popUp.deleteSecret?.data as SecretV3RawSanitized;
try {
if (isBatchMode) {
const deleteChange: PendingSecretDelete = {
id: `${secretId}`,
type: PendingAction.Delete,
secretKey: key,
secretValue: value || "",
timestamp: Date.now(),
resourceType: "secret",
secretValueHidden
};
if (isBatchMode) {
const deleteChange: PendingSecretDelete = {
id: `${secretId}`,
type: PendingAction.Delete,
secretKey: key,
secretValue: value || "",
timestamp: Date.now(),
resourceType: "secret",
secretValueHidden
};
addPendingChange(deleteChange, {
projectId,
environment,
secretPath
});
addPendingChange(deleteChange, {
projectId,
environment,
secretPath
});
handlePopUpClose("deleteSecret");
handlePopUpClose("secretDetail");
return;
}
await handleSecretOperation("delete", SecretType.Shared, key, { secretId });
// wrap this in another function and then reuse
queryClient.invalidateQueries({
queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath })
});
queryClient.invalidateQueries({
queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath })
});
queryClient.invalidateQueries({
queryKey: secretSnapshotKeys.list({
projectId,
environment,
directory: secretPath
})
});
queryClient.invalidateQueries({
queryKey: secretSnapshotKeys.count({
projectId,
environment,
directory: secretPath
})
});
queryClient.invalidateQueries({
queryKey: commitKeys.count({ projectId, environment, directory: secretPath })
});
queryClient.invalidateQueries({
queryKey: commitKeys.history({ projectId, environment, directory: secretPath })
});
queryClient.invalidateQueries({
queryKey: secretApprovalRequestKeys.count({ projectId })
});
handlePopUpClose("deleteSecret");
handlePopUpClose("secretDetail");
createNotification({
type: isProtectedBranch ? "info" : "success",
text: isProtectedBranch
? "Requested changes have been sent for review"
: "Successfully deleted secret"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to delete secret"
});
return;
}
await handleSecretOperation("delete", SecretType.Shared, key, { secretId });
// wrap this in another function and then reuse
queryClient.invalidateQueries({
queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath })
});
queryClient.invalidateQueries({
queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath })
});
queryClient.invalidateQueries({
queryKey: secretSnapshotKeys.list({
projectId,
environment,
directory: secretPath
})
});
queryClient.invalidateQueries({
queryKey: secretSnapshotKeys.count({
projectId,
environment,
directory: secretPath
})
});
queryClient.invalidateQueries({
queryKey: commitKeys.count({ projectId, environment, directory: secretPath })
});
queryClient.invalidateQueries({
queryKey: commitKeys.history({ projectId, environment, directory: secretPath })
});
queryClient.invalidateQueries({
queryKey: secretApprovalRequestKeys.count({ projectId })
});
handlePopUpClose("deleteSecret");
handlePopUpClose("secretDetail");
createNotification({
type: isProtectedBranch ? "info" : "success",
text: isProtectedBranch
? "Requested changes have been sent for review"
: "Successfully deleted secret"
});
}, [
(popUp.deleteSecret?.data as SecretV3RawSanitized)?.key,
environment,
@@ -2,6 +2,7 @@ import { useState } from "react";
import { faEye } from "@fortawesome/free-regular-svg-icons";
import {
faArrowRotateRight,
faBan,
faDesktop,
faEyeSlash,
faServer,
@@ -68,10 +69,14 @@ export const SecretVersionItem = ({
const getLinkToModifyHistoryEntity = (
actorId: string,
actorType: string,
membershipId: string | null = ""
membershipId: string | null = "",
groupId: string | null = "",
actorName: string | null = ""
) => {
switch (actorType) {
case ActorType.USER:
if (groupId)
return `/projects/secret-management/${currentProject.id}/groups/${groupId}?username=${actorName}`;
return `/projects/secret-management/${currentProject.id}/members/${membershipId}`;
case ActorType.IDENTITY:
return `/projects/secret-management/${currentProject.id}/identities/${actorId}`;
@@ -83,10 +88,26 @@ export const SecretVersionItem = ({
const onModifyHistoryClick = (
actorId: string | undefined | null,
actorType: string | undefined | null,
membershipId: string | undefined | null
membershipId: string | undefined | null,
groupId: string | undefined | null,
actorName: string | undefined | null
) => {
if (!membershipId) {
createNotification({
type: "info",
text: `This ${actorType === ActorType.USER ? "user" : "identity"} is no longer a member of this project.`
});
return;
}
if (actorType && actorId && actorType !== ActorType.PLATFORM) {
const redirectLink = getLinkToModifyHistoryEntity(actorId, actorType, membershipId);
const redirectLink = getLinkToModifyHistoryEntity(
actorId,
actorType,
membershipId,
groupId,
actorName
);
if (redirectLink) {
navigate({ to: redirectLink });
}
@@ -157,15 +178,35 @@ export const SecretVersionItem = ({
<div className="flex flex-row">
<div className="flex w-fit flex-row text-sm">
Modified by:
<Tooltip content={getModifiedByName(actor.actorType, actor.name)}>
<Tooltip
className="z-[100] max-w-sm"
content={
getModifiedByName(actor.actorType, actor.name) +
(!actor.membershipId && actor.actorId ? " (Removed from project)" : "")
}
>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<div
onClick={() =>
onModifyHistoryClick(actor.actorId, actor.actorType, actor.membershipId)
onClick={
actor.membershipId
? () =>
onModifyHistoryClick(
actor.actorId,
actor.actorType,
actor.membershipId,
actor.groupId,
actor.name
)
: undefined
}
className="cursor-pointer"
className={actor.membershipId ? "cursor-pointer" : undefined}
>
<FontAwesomeIcon icon={getModifiedByIcon(actor.actorType)} className="ml-2" />
{!actor.membershipId &&
actor.actorType &&
[ActorType.USER, ActorType.IDENTITY].includes(
actor.actorType as ActorType
) && <FontAwesomeIcon className="ml-1 text-mineshaft-400" icon={faBan} />}
</div>
</Tooltip>
</div>
@@ -128,25 +128,17 @@ export const SnapshotView = ({
});
return;
}
try {
await performRollback({
projectId,
snapshotId: snapshotData.id,
environment,
directory: secretPath
});
createNotification({
text: "Successfully rollback secrets",
type: "success"
});
onGoBack();
} catch (error) {
console.log(error);
createNotification({
text: "Failed to rollback secrets",
type: "error"
});
}
await performRollback({
projectId,
snapshotId: snapshotData.id,
environment,
directory: secretPath
});
createNotification({
text: "Successfully rollback secrets",
type: "success"
});
onGoBack();
};
if (isSnapshotLoading) {
@@ -95,42 +95,26 @@ const Page = () => {
const handleDeleteRotation = async () => {
const { id } = popUp.deleteRotation.data as { id: string };
try {
await deleteSecretRotation({
id,
workspaceId
});
handlePopUpClose("deleteRotation");
createNotification({
type: "success",
text: "Successfully removed rotation"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to remove rotation"
});
}
await deleteSecretRotation({
id,
workspaceId
});
handlePopUpClose("deleteRotation");
createNotification({
type: "success",
text: "Successfully removed rotation"
});
};
const handleRestartRotation = async (id: string) => {
try {
await restartSecretRotation({
id,
workspaceId
});
createNotification({
type: "success",
text: "Secret rotation initiated"
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to restart rotation"
});
}
await restartSecretRotation({
id,
workspaceId
});
createNotification({
type: "success",
text: "Secret rotation initiated"
});
};
const handleCreateRotation = (provider: TSecretRotationProviderTemplate) => {
@@ -1,7 +1,6 @@
import { useRef, useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { createNotification } from "@app/components/notifications";
import { Modal, ModalContent, Step, Stepper } from "@app/components/v2";
import { useCreateSecretRotation } from "@app/hooks/api";
import { TSecretRotationProviderTemplate } from "@app/hooks/api/types";
@@ -54,27 +53,19 @@ export const CreateRotationForm = ({
const handleFormSubmit = async () => {
if (!wizardData.current.input || !wizardData.current.output) return;
try {
await createSecretRotation({
workspaceId,
provider: provider.name,
customProvider,
secretPath: wizardData.current.output.secretPath,
environment: wizardData.current.output.environment,
interval: wizardData.current.output.interval,
inputs: wizardData.current.input,
outputs: wizardData.current.output.secrets
});
setWizardStep(0);
onToggle(false);
wizardData.current = {};
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to create secret rotation"
});
}
await createSecretRotation({
workspaceId,
provider: provider.name,
customProvider,
secretPath: wizardData.current.output.secretPath,
environment: wizardData.current.output.environment,
interval: wizardData.current.output.interval,
inputs: wizardData.current.input,
outputs: wizardData.current.output.secrets
});
setWizardStep(0);
onToggle(false);
wizardData.current = {};
};
return (
@@ -89,44 +89,30 @@ export const SecretSyncActionTriggers = ({ secretSync }: Props) => {
const handleToggleEnableSync = async () => {
const isAutoSyncEnabled = !secretSync.isAutoSyncEnabled;
try {
await updateSync.mutateAsync({
syncId: secretSync.id,
destination: secretSync.destination,
isAutoSyncEnabled,
projectId: secretSync.projectId
});
await updateSync.mutateAsync({
syncId: secretSync.id,
destination: secretSync.destination,
isAutoSyncEnabled,
projectId: secretSync.projectId
});
createNotification({
text: `Successfully ${isAutoSyncEnabled ? "enabled" : "disabled"} auto-sync for ${destinationName} Sync`,
type: "success"
});
} catch {
createNotification({
text: `Failed to ${isAutoSyncEnabled ? "enable" : "disable"} auto-sync for ${destinationName} Sync`,
type: "error"
});
}
createNotification({
text: `Successfully ${isAutoSyncEnabled ? "enabled" : "disabled"} auto-sync for ${destinationName} Sync`,
type: "success"
});
};
const handleTriggerSync = async () => {
try {
await triggerSyncSecrets.mutateAsync({
syncId: secretSync.id,
destination: secretSync.destination,
projectId: secretSync.projectId
});
await triggerSyncSecrets.mutateAsync({
syncId: secretSync.id,
destination: secretSync.destination,
projectId: secretSync.projectId
});
createNotification({
text: `Successfully triggered ${destinationName} Sync`,
type: "success"
});
} catch {
createNotification({
text: `Failed to trigger ${destinationName} Sync`,
type: "error"
});
}
createNotification({
text: `Successfully triggered ${destinationName} Sync`,
type: "success"
});
};
const permissionSubject =
@@ -13,26 +13,18 @@ export const AutoCapitalizationSection = () => {
const { mutateAsync } = useUpdateProject();
const handleToggleCapitalizationToggle = async (state: boolean) => {
try {
if (!currentProject?.id) return;
if (!currentProject?.id) return;
await mutateAsync({
projectId: currentProject.id,
autoCapitalization: state
});
await mutateAsync({
projectId: currentProject.id,
autoCapitalization: state
});
const text = `Successfully ${state ? "enabled" : "disabled"} auto capitalization`;
createNotification({
text,
type: "success"
});
} catch (err) {
console.error(err);
createNotification({
text: "Failed to update auto capitalization",
type: "error"
});
}
const text = `Successfully ${state ? "enabled" : "disabled"} auto capitalization`;
createNotification({
text,
type: "success"
});
};
return (
@@ -13,12 +13,8 @@ export const BackfillSecretReferenceSecretion = () => {
const handleBackfill = async () => {
if (backfillSecretReferences.isPending) return;
try {
await backfillSecretReferences.mutateAsync({ projectId: currentProject.id || "" });
createNotification({ text: "Successfully re-indexed secret references", type: "success" });
} catch {
createNotification({ text: "Failed to re-index secret references", type: "error" });
}
await backfillSecretReferences.mutateAsync({ projectId: currentProject.id || "" });
createNotification({ text: "Successfully re-indexed secret references", type: "success" });
};
const isAdmin = hasProjectRole(ProjectMembershipRole.Admin);
@@ -124,17 +124,13 @@ const LoadBackupModal = ({
return;
}
try {
await loadKmsBackup(backupContent);
createNotification({
text: "Successfully loaded KMS backup",
type: "success"
});
await loadKmsBackup(backupContent);
createNotification({
text: "Successfully loaded KMS backup",
type: "success"
});
onOpenChange(false);
} catch (err) {
console.error(err);
}
onOpenChange(false);
};
const parseFile = (file?: File) => {
@@ -245,20 +241,16 @@ export const EncryptionTab = () => {
});
const onUpdateProjectKms = async (data: TForm) => {
try {
await updateProjectKms(
data.kmsKeyId === INTERNAL_KMS_KEY_ID
? { type: KmsType.Internal }
: { type: KmsType.External, kmsId: data.kmsKeyId }
);
await updateProjectKms(
data.kmsKeyId === INTERNAL_KMS_KEY_ID
? { type: KmsType.Internal }
: { type: KmsType.External, kmsId: data.kmsKeyId }
);
createNotification({
text: "Successfully updated project KMS",
type: "success"
});
} catch (err) {
console.error(err);
}
createNotification({
text: "Successfully updated project KMS",
type: "success"
});
};
return (
@@ -36,28 +36,20 @@ const Content = ({ onComplete }: ContentProps) => {
});
const onFormSubmit = async ({ environmentName, environmentSlug }: FormData) => {
try {
if (!currentProject?.id) return;
if (!currentProject?.id) return;
const env = await mutateAsync({
projectId: currentProject.id,
name: environmentName,
slug: environmentSlug
});
const env = await mutateAsync({
projectId: currentProject.id,
name: environmentName,
slug: environmentSlug
});
createNotification({
text: "Successfully created environment",
type: "success"
});
createNotification({
text: "Successfully created environment",
type: "success"
});
onComplete(env);
} catch (err) {
console.error(err);
createNotification({
text: "Failed to create environment",
type: "error"
});
}
onComplete(env);
};
return (
@@ -39,27 +39,19 @@ export const EnvironmentSection = () => {
] as const);
const onEnvDeleteSubmit = async (id: string) => {
try {
if (!currentProject?.id) return;
if (!currentProject?.id) return;
await deleteWsEnvironment.mutateAsync({
projectId: currentProject.id,
id
});
await deleteWsEnvironment.mutateAsync({
projectId: currentProject.id,
id
});
createNotification({
text: "Successfully deleted environment",
type: "success"
});
createNotification({
text: "Successfully deleted environment",
type: "success"
});
handlePopUpClose("deleteEnv");
} catch (err) {
console.error(err);
createNotification({
text: "Failed to delete environment",
type: "error"
});
}
handlePopUpClose("deleteEnv");
};
return (
@@ -46,26 +46,18 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => {
const updateEnvironment = useUpdateWsEnvironment();
const handleReorderEnv = async (id: string, position: number) => {
try {
if (!currentProject?.id) return;
if (!currentProject?.id) return;
await updateEnvironment.mutateAsync({
projectId: currentProject.id,
id,
position
});
await updateEnvironment.mutateAsync({
projectId: currentProject.id,
id,
position
});
createNotification({
text: "Successfully re-ordered environments",
type: "success"
});
} catch (err) {
console.error(err);
createNotification({
text: "Failed to re-order environments",
type: "error"
});
}
createNotification({
text: "Successfully re-ordered environments",
type: "success"
});
};
const isMoreEnvironmentsAllowed =
@@ -33,29 +33,21 @@ export const UpdateEnvironmentModal = ({ popUp, handlePopUpClose, handlePopUpTog
const oldEnvId = (popUp?.updateEnv?.data as { id: string })?.id;
const onFormSubmit = async ({ name, slug }: FormData) => {
try {
if (!currentProject?.id) return;
if (!currentProject?.id) return;
await mutateAsync({
projectId: currentProject.id,
name,
slug,
id: oldEnvId
});
await mutateAsync({
projectId: currentProject.id,
name,
slug,
id: oldEnvId
});
createNotification({
text: "Successfully updated environment",
type: "success"
});
createNotification({
text: "Successfully updated environment",
type: "success"
});
handlePopUpClose("updateEnv");
} catch (err) {
console.error(err);
createNotification({
text: "Failed to update environment",
type: "error"
});
}
handlePopUpClose("updateEnv");
};
return (
@@ -34,22 +34,15 @@ export const PointInTimeVersionLimitSection = () => {
if (!currentProject) return null;
const handleVersionLimitSubmit = async ({ pitVersionLimit }: TForm) => {
try {
await updateProject({
pitVersionLimit,
projectId
});
await updateProject({
pitVersionLimit,
projectId
});
createNotification({
text: "Successfully updated version limit",
type: "success"
});
} catch {
createNotification({
text: "Failed updating project's version limit",
type: "error"
});
}
createNotification({
text: "Successfully updated version limit",
type: "success"
});
};
const isAdmin = hasProjectRole(ProjectMembershipRole.Admin);
@@ -55,22 +55,15 @@ export const SecretDetectionIgnoreValuesSection = () => {
}, [currentProject?.secretDetectionIgnoreValues, reset]);
const handleIgnoreValuesSubmit = async ({ ignoreValues }: TForm) => {
try {
await updateProject({
projectId: currentProject.id,
secretDetectionIgnoreValues: ignoreValues.map((item) => item.value)
});
await updateProject({
projectId: currentProject.id,
secretDetectionIgnoreValues: ignoreValues.map((item) => item.value)
});
createNotification({
text: "Successfully updated secret detection ignore values",
type: "success"
});
} catch {
createNotification({
text: "Failed updating secret detection ignore values",
type: "error"
});
}
createNotification({
text: "Successfully updated secret detection ignore values",
type: "success"
});
};
const isAdmin = hasProjectRole(ProjectMembershipRole.Admin);
@@ -15,12 +15,12 @@ export const SecretSharingSection = () => {
const handleToggle = async (state: boolean) => {
setIsLoading(true);
try {
if (!currentProject?.id) {
setIsLoading(false);
return;
}
if (!currentProject?.id) {
setIsLoading(false);
return;
}
try {
await updateProject({
projectId: currentProject.id,
secretSharing: state
@@ -30,12 +30,6 @@ export const SecretSharingSection = () => {
text: `Successfully ${state ? "enabled" : "disabled"} secret sharing for this project`,
type: "success"
});
} catch (err) {
console.error(err);
createNotification({
text: "Failed to update secret sharing for this project",
type: "error"
});
} finally {
setIsLoading(false);
}
@@ -30,12 +30,6 @@ export const SecretSnapshotsLegacySection = () => {
text: `Successfully ${state ? "enabled" : "disabled"} secret snapshots legacy for this project`,
type: "success"
});
} catch (err) {
console.error(err);
createNotification({
text: "Failed to update secret snapshots legacy for this project",
type: "error"
});
} finally {
setIsLoading(false);
}
@@ -39,29 +39,21 @@ export const AddSecretTagModal = ({ popUp, handlePopUpClose, handlePopUpToggle }
});
const onFormSubmit = async ({ slug }: FormData) => {
try {
if (!currentProject?.id) return;
if (!currentProject?.id) return;
await createWsTag.mutateAsync({
projectId: currentProject?.id,
tagSlug: slug,
tagColor: ""
});
await createWsTag.mutateAsync({
projectId: currentProject?.id,
tagSlug: slug,
tagColor: ""
});
handlePopUpClose("CreateSecretTag");
handlePopUpClose("CreateSecretTag");
createNotification({
text: "Successfully created a tag",
type: "success"
});
reset();
} catch (err) {
console.error(err);
createNotification({
text: "Failed to create a tag",
type: "error"
});
}
createNotification({
text: "Successfully created a tag",
type: "success"
});
reset();
};
return (
@@ -29,25 +29,17 @@ export const SecretTagsSection = (): JSX.Element => {
const deleteWsTag = useDeleteWsTag();
const onDeleteApproved = async () => {
try {
await deleteWsTag.mutateAsync({
projectId: currentProject?.id || "",
tagID: (popUp?.deleteTagConfirmation?.data as DeleteModalData)?.id
});
await deleteWsTag.mutateAsync({
projectId: currentProject?.id || "",
tagID: (popUp?.deleteTagConfirmation?.data as DeleteModalData)?.id
});
createNotification({
text: "Successfully deleted tag",
type: "success"
});
createNotification({
text: "Successfully deleted tag",
type: "success"
});
handlePopUpClose("deleteTagConfirmation");
} catch (err) {
console.error(err);
createNotification({
text: "Failed to delete the tag",
type: "error"
});
}
handlePopUpClose("deleteTagConfirmation");
};
return (
@@ -59,83 +59,51 @@ export const WebhooksTab = withProjectPermission(
const { mutateAsync: deleteWebhook } = useDeleteWebhook();
const handleWebhookCreate = async (data: TFormSchema) => {
try {
await createWebhook({
...data,
projectId
});
handlePopUpClose("addWebhook");
createNotification({
type: "success",
text: "Successfully created webhook"
});
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to create webhook"
});
}
await createWebhook({
...data,
projectId
});
handlePopUpClose("addWebhook");
createNotification({
type: "success",
text: "Successfully created webhook"
});
};
const handleWebhookDisable = async (webhookId: string, isDisabled: boolean) => {
try {
await updateWebhook({
webhookId,
projectId,
isDisabled
});
createNotification({
type: "success",
text: "Successfully updated webhook"
});
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to update webhook"
});
}
await updateWebhook({
webhookId,
projectId,
isDisabled
});
createNotification({
type: "success",
text: "Successfully updated webhook"
});
};
const handleWebhookDelete = async () => {
try {
const webhookId = popUp?.deleteWebhook?.data as string;
await deleteWebhook({
webhookId,
projectId
});
handlePopUpClose("deleteWebhook");
createNotification({
type: "success",
text: "Successfully deleted webhook"
});
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to delete webhook"
});
}
const webhookId = popUp?.deleteWebhook?.data as string;
await deleteWebhook({
webhookId,
projectId
});
handlePopUpClose("deleteWebhook");
createNotification({
type: "success",
text: "Successfully deleted webhook"
});
};
const handleWebhookTest = async (webhookId: string) => {
try {
await testWebhook({
webhookId,
projectId
});
createNotification({
type: "success",
text: "Successfully triggered webhook"
});
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to trigger webhook"
});
}
await testWebhook({
webhookId,
projectId
});
createNotification({
type: "success",
text: "Successfully triggered webhook"
});
};
return (
@@ -130,37 +130,30 @@ export const MicrosoftTeamsIntegrationForm = ({ onClose }: Props) => {
});
const handleIntegrationSave = async (data: TMicrosoftTeamsConfigForm) => {
try {
if (!currentProject) {
return;
}
await updateProjectMicrosoftTeamsConfig({
projectId: currentProject.id,
isAccessRequestNotificationEnabled: data.isAccessRequestNotificationEnabled,
isSecretRequestNotificationEnabled: data.isSecretRequestNotificationEnabled,
...(data.isAccessRequestNotificationEnabled && {
accessRequestChannels: data.accessRequestChannels
}),
...(data.isSecretRequestNotificationEnabled && {
secretRequestChannels: data.secretRequestChannels
}),
integration: WorkflowIntegrationPlatform.MICROSOFT_TEAMS,
integrationId: data.microsoftTeamsIntegrationId
});
createNotification({
type: "success",
text: "Successfully created microsoft teams integration"
});
onClose();
} catch {
createNotification({
type: "error",
text: "Failed to create microsoft teams integration"
});
if (!currentProject) {
return;
}
await updateProjectMicrosoftTeamsConfig({
projectId: currentProject.id,
isAccessRequestNotificationEnabled: data.isAccessRequestNotificationEnabled,
isSecretRequestNotificationEnabled: data.isSecretRequestNotificationEnabled,
...(data.isAccessRequestNotificationEnabled && {
accessRequestChannels: data.accessRequestChannels
}),
...(data.isSecretRequestNotificationEnabled && {
secretRequestChannels: data.secretRequestChannels
}),
integration: WorkflowIntegrationPlatform.MICROSOFT_TEAMS,
integrationId: data.microsoftTeamsIntegrationId
});
createNotification({
type: "success",
text: "Successfully created microsoft teams integration"
});
onClose();
};
const selectedAccessRequestTeamId = watch("accessRequestChannels.teamId");
@@ -143,33 +143,26 @@ export const SlackIntegrationForm = ({ onClose }: Props) => {
});
const handleIntegrationSave = async (data: TSlackConfigForm) => {
try {
if (!currentProject) {
return;
}
await updateProjectSlackConfig({
...data,
projectId: currentProject.id,
integration: WorkflowIntegrationPlatform.SLACK,
integrationId: data.slackIntegrationId,
accessRequestChannels: data.accessRequestChannels.filter(Boolean).join(", "),
secretRequestChannels: data.secretRequestChannels.filter(Boolean).join(", "),
secretSyncErrorChannels: data.secretSyncErrorChannels.filter(Boolean).join(", ")
});
createNotification({
type: "success",
text: "Successfully created slack integration"
});
onClose();
} catch {
createNotification({
type: "error",
text: "Failed to create slack integration"
});
if (!currentProject) {
return;
}
await updateProjectSlackConfig({
...data,
projectId: currentProject.id,
integration: WorkflowIntegrationPlatform.SLACK,
integrationId: data.slackIntegrationId,
accessRequestChannels: data.accessRequestChannels.filter(Boolean).join(", "),
secretRequestChannels: data.secretRequestChannels.filter(Boolean).join(", "),
secretSyncErrorChannels: data.secretSyncErrorChannels.filter(Boolean).join(", ")
});
createNotification({
type: "success",
text: "Successfully created slack integration"
});
onClose();
};
const secretRequestNotifState = watch("isSecretRequestNotificationEnabled");
@@ -126,43 +126,35 @@ export const BitbucketConfigurePage = () => {
}: TFormData) => {
if (!targetRepo || !targetWorkspace) return;
try {
await createIntegration.mutateAsync({
integrationAuthId,
isActive: true,
app: targetRepo.name,
appId: targetRepo.appId,
sourceEnvironment: sourceEnvironment.slug,
targetEnvironment: targetWorkspace.name,
targetEnvironmentId: targetWorkspace.slug,
...(scope.value === BitbucketScope.Env &&
targetEnvironment && {
targetService: targetEnvironment.name,
targetServiceId: targetEnvironment.uuid
}),
secretPath
});
await createIntegration.mutateAsync({
integrationAuthId,
isActive: true,
app: targetRepo.name,
appId: targetRepo.appId,
sourceEnvironment: sourceEnvironment.slug,
targetEnvironment: targetWorkspace.name,
targetEnvironmentId: targetWorkspace.slug,
...(scope.value === BitbucketScope.Env &&
targetEnvironment && {
targetService: targetEnvironment.name,
targetServiceId: targetEnvironment.uuid
}),
secretPath
});
createNotification({
type: "success",
text: "Successfully created integration"
});
navigate({
to: "/projects/secret-management/$projectId/integrations",
params: {
projectId: currentProject.id
},
search: {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
});
} catch (err) {
createNotification({
type: "error",
text: "Failed to create integration"
});
console.error(err);
}
createNotification({
type: "success",
text: "Successfully created integration"
});
navigate({
to: "/projects/secret-management/$projectId/integrations",
params: {
projectId: currentProject.id
},
search: {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
});
};
useEffect(() => {
@@ -73,51 +73,43 @@ export const CircleCIConfigurePage = () => {
: undefined;
const onSubmit = async (data: TFormData) => {
try {
if (data.scope === CircleCiScope.Context) {
await mutateAsync({
scope: data.scope,
integrationAuthId,
isActive: true,
sourceEnvironment: data.sourceEnvironment.slug,
app: data.targetContext.name,
appId: data.targetContext.id,
owner: data.targetOrg.name,
secretPath: data.secretPath
});
} else {
await mutateAsync({
scope: data.scope,
integrationAuthId,
isActive: true,
app: data.targetProject.name, // project name
owner: data.targetOrg.name, // organization name
appId: data.targetProject.id, // project id (used for syncing)
sourceEnvironment: data.sourceEnvironment.slug,
secretPath: data.secretPath
});
}
createNotification({
type: "success",
text: "Successfully created integration"
if (data.scope === CircleCiScope.Context) {
await mutateAsync({
scope: data.scope,
integrationAuthId,
isActive: true,
sourceEnvironment: data.sourceEnvironment.slug,
app: data.targetContext.name,
appId: data.targetContext.id,
owner: data.targetOrg.name,
secretPath: data.secretPath
});
navigate({
to: "/projects/secret-management/$projectId/integrations",
params: {
projectId: currentProject.id
},
search: {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
} else {
await mutateAsync({
scope: data.scope,
integrationAuthId,
isActive: true,
app: data.targetProject.name, // project name
owner: data.targetOrg.name, // organization name
appId: data.targetProject.id, // project id (used for syncing)
sourceEnvironment: data.sourceEnvironment.slug,
secretPath: data.secretPath
});
} catch (err) {
createNotification({
type: "error",
text: "Failed to create integration"
});
console.error(err);
}
createNotification({
type: "success",
text: "Successfully created integration"
});
navigate({
to: "/projects/secret-management/$projectId/integrations",
params: {
projectId: currentProject.id
},
search: {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
});
};
if (isCircleCIOrganizationsLoading)
@@ -1,8 +1,6 @@
import { useEffect, useState } from "react";
import { useNavigate, useSearch } from "@tanstack/react-router";
import axios from "axios";
import { createNotification } from "@app/components/notifications";
import {
Button,
Card,
@@ -102,19 +100,7 @@ export const CloudflarePagesConfigurePage = () => {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
});
} catch (err) {
console.error(err);
let errorMessage: string = "Something went wrong!";
if (axios.isAxiosError(err)) {
const { message } = err?.response?.data as { message: string };
errorMessage = message;
}
createNotification({
text: errorMessage,
type: "error"
});
} catch {
setIsLoading(false);
}
};
@@ -1,8 +1,6 @@
import { useEffect, useState } from "react";
import { useNavigate, useSearch } from "@tanstack/react-router";
import axios from "axios";
import { createNotification } from "@app/components/notifications";
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from "@app/components/v2";
import { SecretPathInput } from "@app/components/v2/SecretPathInput";
import { ROUTE_PATHS } from "@app/const/routes";
@@ -75,19 +73,7 @@ export const CloudflareWorkersConfigurePage = () => {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
});
} catch (err) {
console.error(err);
let errorMessage: string = "Something went wrong!";
if (axios.isAxiosError(err)) {
const { message } = err?.response?.data as { message: string };
errorMessage = message;
}
createNotification({
text: errorMessage,
type: "error"
});
} catch {
setIsLoading(false);
}
};
@@ -55,49 +55,45 @@ export const DatabricksConfigurePage = () => {
const [secretPath, setSecretPath] = useState("/");
const handleButtonClick = async () => {
try {
if (!integrationAuth?.id) return;
if (!integrationAuth?.id) return;
if (!targetScope) {
createNotification({
type: "error",
text: "Please select a scope"
});
return;
}
const selectedScope = integrationAuthScopes?.find(
(integrationAuthScope) => integrationAuthScope.name === targetScope
);
if (!selectedScope) {
createNotification({
type: "error",
text: "Invalid scope selected"
});
return;
}
await mutateAsync({
integrationAuthId: integrationAuth?.id,
isActive: true,
app: selectedScope.name, // scope name
sourceEnvironment: selectedSourceEnvironment,
secretPath
if (!targetScope) {
createNotification({
type: "error",
text: "Please select a scope"
});
navigate({
to: "/projects/secret-management/$projectId/integrations",
params: {
projectId: currentProject.id
},
search: {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
});
} catch (err) {
console.error(err);
return;
}
const selectedScope = integrationAuthScopes?.find(
(integrationAuthScope) => integrationAuthScope.name === targetScope
);
if (!selectedScope) {
createNotification({
type: "error",
text: "Invalid scope selected"
});
return;
}
await mutateAsync({
integrationAuthId: integrationAuth?.id,
isActive: true,
app: selectedScope.name, // scope name
sourceEnvironment: selectedSourceEnvironment,
secretPath
});
navigate({
to: "/projects/secret-management/$projectId/integrations",
params: {
projectId: currentProject.id
},
search: {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
});
};
return integrationAuth && selectedSourceEnvironment && integrationAuthScopes ? (
@@ -12,12 +12,10 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import { useNavigate, useSearch } from "@tanstack/react-router";
import axios from "axios";
import { motion } from "framer-motion";
import { twMerge } from "tailwind-merge";
import { z, ZodIssueCode } from "zod";
import { createNotification } from "@app/components/notifications";
import {
Button,
Card,
@@ -275,19 +273,7 @@ export const GithubConfigurePage = () => {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
});
} catch (err) {
console.error(err);
let errorMessage: string = "Something went wrong!";
if (axios.isAxiosError(err)) {
const { message } = err?.response?.data as { message: string };
errorMessage = message;
}
createNotification({
text: errorMessage,
type: "error"
});
} catch {
setIsLoading(false);
}
};
@@ -4,10 +4,8 @@ import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-sv
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import { useNavigate } from "@tanstack/react-router";
import axios from "axios";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { Button, Card, CardBody, CardTitle, FormControl, Input } from "@app/components/v2";
import { useProject } from "@app/context";
import { useSaveIntegrationAccessToken } from "@app/hooks/api";
@@ -41,37 +39,23 @@ export const HashicorpVaultAuthorizePage = () => {
});
const handleFormSubmit = async (formData: TForm) => {
try {
const integrationAuth = await mutateAsync({
workspaceId: currentProject.id,
integration: "hashicorp-vault",
accessId: formData.vaultRoleID,
accessToken: formData.vaultSecretID,
url: formData.vaultURL,
namespace: formData.vaultNamespace
});
navigate({
to: "/projects/secret-management/$projectId/integrations/hashicorp-vault/create",
params: {
projectId: currentProject.id
},
search: {
integrationAuthId: integrationAuth.id
}
});
} catch (err) {
console.error(err);
let errorMessage: string = "Something went wrong!";
if (axios.isAxiosError(err)) {
const { message } = err?.response?.data as { message: string };
errorMessage = message;
const integrationAuth = await mutateAsync({
workspaceId: currentProject.id,
integration: "hashicorp-vault",
accessId: formData.vaultRoleID,
accessToken: formData.vaultSecretID,
url: formData.vaultURL,
namespace: formData.vaultNamespace
});
navigate({
to: "/projects/secret-management/$projectId/integrations/hashicorp-vault/create",
params: {
projectId: currentProject.id
},
search: {
integrationAuthId: integrationAuth.id
}
createNotification({
text: errorMessage,
type: "error"
});
}
});
};
return (

Some files were not shown because too many files have changed in this diff Show More