refactor: streamline async logic and notification handling across various settings and integration components

This commit is contained in:
Victor Santos
2025-11-03 15:11:10 -03:00
parent 3aeee8d552
commit c005f8a0fe
33 changed files with 709 additions and 1061 deletions

View File

@@ -39,40 +39,33 @@ export const AuditLogsRetentionSection = () => {
if (!currentProject) return null; if (!currentProject) return null;
const handleAuditLogsRetentionSubmit = async ({ auditLogsRetentionDays }: TForm) => { const handleAuditLogsRetentionSubmit = async ({ auditLogsRetentionDays }: TForm) => {
try { if (!subscription?.auditLogs) {
if (!subscription?.auditLogs) { handlePopUpOpen("upgradePlan", {
handlePopUpOpen("upgradePlan", { description:
description: "You can only configure audit logs retention if you switch to Infisical's Pro plan."
"You can only configure audit logs retention if you switch to Infisical's Pro plan."
});
return;
}
if (subscription && auditLogsRetentionDays > subscription?.auditLogsRetentionDays) {
handlePopUpOpen("upgradePlan", {
description:
"To update your audit logs retention period to a higher value, switch to Infisical's Pro plan."
});
return;
}
await updateAuditLogsRetention({
auditLogsRetentionDays,
projectSlug: currentProject.slug
}); });
createNotification({ return;
text: "Successfully updated audit logs retention period",
type: "success"
});
} catch {
createNotification({
text: "Failed updating audit logs retention period",
type: "error"
});
} }
if (subscription && auditLogsRetentionDays > subscription?.auditLogsRetentionDays) {
handlePopUpOpen("upgradePlan", {
description:
"To update your audit logs retention period to a higher value, switch to Infisical's Pro plan."
});
return;
}
await updateAuditLogsRetention({
auditLogsRetentionDays,
projectSlug: currentProject.slug
});
createNotification({
text: "Successfully updated audit logs retention period",
type: "success"
});
}; };
// render only for dedicated/self-hosted instances of Infisical // render only for dedicated/self-hosted instances of Infisical

View File

@@ -2,7 +2,6 @@ import { faHome } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, useNavigate, useParams } from "@tanstack/react-router"; import { Link, useNavigate, useParams } from "@tanstack/react-router";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions"; import { OrgPermissionCan } from "@app/components/permissions";
import { RequestProjectAccessModal } from "@app/components/projects"; import { RequestProjectAccessModal } from "@app/components/projects";
import { AccessRestrictedBanner, Button } from "@app/components/v2"; import { AccessRestrictedBanner, Button } from "@app/components/v2";
@@ -35,19 +34,12 @@ export const ProjectAccessError = () => {
const handleAccessProject = async () => { const handleAccessProject = async () => {
if (!project) return; if (!project) return;
try { await orgAdminAccessProject.mutateAsync({
await orgAdminAccessProject.mutateAsync({ projectId: project.id
projectId: project.id });
}); await navigate({
await navigate({ to: "."
to: "." });
});
} catch {
createNotification({
text: "Failed to access project",
type: "error"
});
}
}; };
return ( return (

View File

@@ -131,52 +131,44 @@ export const ShareSecretForm = ({
emails, emails,
shouldLimitView shouldLimitView
}: FormData) => { }: FormData) => {
try { const expiresAt = new Date(new Date().getTime() + Number(expiresIn));
const expiresAt = new Date(new Date().getTime() + Number(expiresIn));
const processedEmails = emails ? emails.split(",").map((e) => e.trim()) : undefined; const processedEmails = emails ? emails.split(",").map((e) => e.trim()) : undefined;
const { id } = await createSharedSecret.mutateAsync({ const { id } = await createSharedSecret.mutateAsync({
name, name,
password, password,
secretValue: secret, secretValue: secret,
expiresAt, expiresAt,
expiresAfterViews: shouldLimitView ? Number(viewLimit) : undefined, expiresAfterViews: shouldLimitView ? Number(viewLimit) : undefined,
accessType, accessType,
emails: processedEmails emails: processedEmails
});
if (processedEmails && processedEmails.length > 0) {
setSecretLink("");
createNotification({
text: `Shared secret link emailed to ${processedEmails.length} user(s).`,
type: "success"
}); });
} else {
if (processedEmails && processedEmails.length > 0) { const link = new URL(`${window.location.origin}/shared/secret/${id}`);
setSecretLink(""); if (subOrganization) {
createNotification({ link.searchParams.set("subOrganization", subOrganization);
text: `Shared secret link emailed to ${processedEmails.length} user(s).`,
type: "success"
});
} else {
const link = new URL(`${window.location.origin}/shared/secret/${id}`);
if (subOrganization) {
link.searchParams.set("subOrganization", subOrganization);
}
setSecretLink(link.toString());
navigator.clipboard.writeText(link.toString());
setCopyTextSecret("secret");
createNotification({
text: "Shared secret link copied to clipboard.",
type: "success"
});
} }
reset(); setSecretLink(link.toString());
} catch (error) {
console.error(error); navigator.clipboard.writeText(link.toString());
setCopyTextSecret("secret");
createNotification({ createNotification({
text: "Failed to create a shared secret.", text: "Shared secret link copied to clipboard.",
type: "error" type: "success"
}); });
} }
reset();
}; };
if (secretLink === null) if (secretLink === null)

View File

@@ -140,22 +140,15 @@ export const RollbackPreviewTab = (): JSX.Element => {
); );
const handleRollback = async (): Promise<void> => { const handleRollback = async (): Promise<void> => {
try { await rollback(message);
await rollback(message);
createNotification({ createNotification({
type: "success", type: "success",
text: "Rollback completed successfully" text: "Rollback completed successfully"
}); });
handlePopUpClose("rollbackConfirm"); handlePopUpClose("rollbackConfirm");
goBackToHistory(); goBackToHistory();
} catch (error) {
createNotification({
type: "error",
text: error instanceof Error ? error.message : "Failed to rollback changes"
});
}
}; };
const folderChanges: FolderChanges[] = rollbackChangesNested || []; const folderChanges: FolderChanges[] = rollbackChangesNested || [];

View File

@@ -53,28 +53,20 @@ export const IntegrationDetailsByIDPage = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const handleIntegrationDelete = async (shouldDeleteIntegrationSecrets: boolean) => { const handleIntegrationDelete = async (shouldDeleteIntegrationSecrets: boolean) => {
try { await deleteIntegration({
await deleteIntegration({ id: integrationId,
id: integrationId, workspaceId: currentProject.id,
workspaceId: currentProject.id, shouldDeleteIntegrationSecrets
shouldDeleteIntegrationSecrets });
});
createNotification({ createNotification({
type: "success", type: "success",
text: "Deleted integration" text: "Deleted integration"
}); });
await navigate({ await navigate({
to: `/${ProjectType.SecretManager}/${projectId}/integrations` to: `/${ProjectType.SecretManager}/${projectId}/integrations`
}); });
} catch (err) {
console.log(err);
createNotification({
type: "error",
text: "Failed to delete integration"
});
}
}; };
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([

View File

@@ -488,55 +488,47 @@ export const OverviewPage = () => {
}; };
const handleSecretCreate = async (env: string, key: string, value: string) => { const handleSecretCreate = async (env: string, key: string, value: string) => {
try { // create folder if not existing
// create folder if not existing if (secretPath !== "/") {
if (secretPath !== "/") { // /hello/world -> [hello","world"]
// /hello/world -> [hello","world"] const pathSegment = secretPath.split("/").filter(Boolean);
const pathSegment = secretPath.split("/").filter(Boolean); const parentPath = `/${pathSegment.slice(0, -1).join("/")}`;
const parentPath = `/${pathSegment.slice(0, -1).join("/")}`; const folderName = pathSegment.at(-1);
const folderName = pathSegment.at(-1); const canCreateFolder = permission.can(
const canCreateFolder = permission.can( ProjectPermissionActions.Create,
ProjectPermissionActions.Create, subject(ProjectPermissionSub.SecretFolders, {
subject(ProjectPermissionSub.SecretFolders, { environment: env,
environment: env, secretPath: parentPath
secretPath: parentPath })
}) );
); if (folderName && parentPath && canCreateFolder) {
if (folderName && parentPath && canCreateFolder) { await getOrCreateFolder({
await getOrCreateFolder({ projectId,
projectId, path: parentPath,
path: parentPath, environment: env,
environment: env, name: folderName
name: folderName });
});
}
} }
const result = await createSecretV3({ }
environment: env, const result = await createSecretV3({
projectId, environment: env,
secretPath, projectId,
secretKey: key, secretPath,
secretValue: value, secretKey: key,
secretComment: "", secretValue: value,
type: SecretType.Shared secretComment: "",
}); type: SecretType.Shared
});
if ("approval" in result) { 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);
createNotification({ createNotification({
type: "error", type: "info",
text: "Failed to create secret" 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; secretValue = undefined;
} }
try { const result = await updateSecretV3({
const result = await updateSecretV3({ environment: env,
environment: env, projectId,
projectId, secretPath,
secretPath, secretKey: key,
secretKey: key, secretValue,
secretValue, type
type });
});
if ("approval" in result) { 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);
createNotification({ createNotification({
type: "error", type: "info",
text: "Failed to update secret" 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) => { const handleSecretDelete = async (env: string, key: string, secretId?: string) => {
try { const result = await deleteSecretV3({
const result = await deleteSecretV3({ environment: env,
environment: env, projectId,
projectId, secretPath,
secretPath, secretKey: key,
secretKey: key, secretId,
secretId, type: SecretType.Shared
type: SecretType.Shared });
});
if ("approval" in result) { 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);
createNotification({ createNotification({
type: "error", type: "info",
text: "Failed to delete secret" text: "Requested change has been sent for review"
});
} else {
createNotification({
type: "success",
text: "Successfully deleted secret"
}); });
} }
}; };

View File

@@ -193,19 +193,12 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => {
const slugSchema = z.string().trim().toLowerCase().min(1); const slugSchema = z.string().trim().toLowerCase().min(1);
const createNewTag = async (slug: string) => { const createNewTag = async (slug: string) => {
// TODO: Replace with slugSchema generic // TODO: Replace with slugSchema generic
try { const parsedSlug = slugSchema.parse(slug);
const parsedSlug = slugSchema.parse(slug); await createWsTag.mutateAsync({
await createWsTag.mutateAsync({ projectId,
projectId, tagSlug: parsedSlug,
tagSlug: parsedSlug, tagColor: ""
tagColor: "" });
});
} catch {
createNotification({
type: "error",
text: "Failed to create new tag"
});
}
}; };
return ( return (

View File

@@ -77,70 +77,55 @@ export const CreateSecretForm = ({
const slugSchema = z.string().trim().toLowerCase().min(1); const slugSchema = z.string().trim().toLowerCase().min(1);
const createNewTag = async (slug: string) => { const createNewTag = async (slug: string) => {
// TODO: Replace with slugSchema generic // TODO: Replace with slugSchema generic
try { const parsedSlug = slugSchema.parse(slug);
const parsedSlug = slugSchema.parse(slug); await createWsTag.mutateAsync({
await createWsTag.mutateAsync({ projectId,
projectId, tagSlug: parsedSlug,
tagSlug: parsedSlug, tagColor: ""
tagColor: "" });
});
} catch {
createNotification({
type: "error",
text: "Failed to create new tag"
});
}
}; };
const handleFormSubmit = async ({ key, value, tags }: TFormSchema) => { const handleFormSubmit = async ({ key, value, tags }: TFormSchema) => {
try { if (isBatchMode) {
if (isBatchMode) { const pendingSecretCreate: PendingSecretCreate = {
const pendingSecretCreate: PendingSecretCreate = { id: key,
id: key, type: PendingAction.Create,
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,
secretKey: key, secretKey: key,
secretValue: value || "", secretValue: value || "",
secretComment: "", secretComment: "",
type: SecretType.Shared, tags: tags?.map((el) => ({ id: el.value, slug: el.label })),
tagIds: tags?.map((el) => el.value) timestamp: Date.now(),
resourceType: "secret"
};
addPendingChange(pendingSecretCreate, {
projectId,
environment,
secretPath
}); });
closePopUp(PopUpNames.CreateSecretForm); closePopUp(PopUpNames.CreateSecretForm);
reset(); reset();
return;
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"
});
} }
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>) => { const handlePaste = (e: ClipboardEvent<HTMLInputElement>) => {

View File

@@ -293,174 +293,166 @@ export const SecretListView = ({
isSameTags && isSameTags &&
isSameRecipients; isSameRecipients;
try { // personal secret change
// personal secret change let personalAction = false;
let personalAction = false; if (overrideAction === "deleted") {
if (overrideAction === "deleted") { await handleSecretOperation("delete", SecretType.Personal, oldKey, {
await handleSecretOperation("delete", SecretType.Personal, oldKey, { secretId: orgSecret.idOverride
secretId: orgSecret.idOverride });
}); personalAction = true;
personalAction = true; } else if (overrideAction && idOverride) {
} else if (overrideAction && idOverride) { await handleSecretOperation("update", SecretType.Personal, oldKey, {
await handleSecretOperation("update", SecretType.Personal, oldKey, { value: valueOverride,
value: valueOverride, newKey: hasKeyChanged ? key : undefined,
newKey: hasKeyChanged ? key : undefined, secretId: orgSecret.idOverride,
secretId: orgSecret.idOverride, skipMultilineEncoding: modSecret.skipMultilineEncoding
skipMultilineEncoding: modSecret.skipMultilineEncoding });
}); personalAction = true;
personalAction = true; } else if (overrideAction) {
} else if (overrideAction) { await handleSecretOperation("create", SecretType.Personal, oldKey, {
await handleSecretOperation("create", SecretType.Personal, oldKey, { value: valueOverride
value: valueOverride });
}); personalAction = true;
personalAction = true; }
}
// shared secret change // shared secret change
if (!isSharedSecUnchanged && !personalAction) { if (!isSharedSecUnchanged && !personalAction) {
if (isBatchMode) { if (isBatchMode) {
const isEditingPendingCreation = isPending && pendingAction === PendingAction.Create; const isEditingPendingCreation = isPending && pendingAction === PendingAction.Create;
if (isEditingPendingCreation) { if (isEditingPendingCreation) {
const updatedCreate: PendingSecretCreate = { const updatedCreate: PendingSecretCreate = {
id: orgSecret.id, id: orgSecret.id,
type: PendingAction.Create, type: PendingAction.Create,
secretKey: key, secretKey: key,
secretValue: value || "", secretValue: value || "",
secretComment: comment || "", secretComment: comment || "",
skipMultilineEncoding: modSecret.skipMultilineEncoding || false, skipMultilineEncoding: modSecret.skipMultilineEncoding || false,
tags: tags?.map((tag) => ({ id: tag.id, slug: tag.name || tag.slug || "" })) || [], tags: tags?.map((tag) => ({ id: tag.id, slug: tag.name || tag.slug || "" })) || [],
secretMetadata: secretMetadata || [], secretMetadata: secretMetadata || [],
timestamp: Date.now(), timestamp: Date.now(),
resourceType: "secret", resourceType: "secret",
originalKey: oldKey originalKey: oldKey
}; };
addPendingChange(updatedCreate, { addPendingChange(updatedCreate, {
projectId, projectId,
environment, environment,
secretPath secretPath
}); });
} else { } else {
const trueOriginalSecret = getTrueOriginalSecret( const trueOriginalSecret = getTrueOriginalSecret(
orgSecret, orgSecret,
pendingChangesRef.current.secrets pendingChangesRef.current.secrets
); );
const updateChange: PendingSecretUpdate = { const updateChange: PendingSecretUpdate = {
id: orgSecret.id, id: orgSecret.id,
type: PendingAction.Update, type: PendingAction.Update,
secretKey: trueOriginalSecret.key, secretKey: trueOriginalSecret.key,
newSecretName: key, newSecretName: key,
originalValue: trueOriginalSecret.value, originalValue: trueOriginalSecret.value,
secretValue: value, secretValue: value,
originalComment: trueOriginalSecret.comment, originalComment: trueOriginalSecret.comment,
secretComment: comment, secretComment: comment,
originalSkipMultilineEncoding: trueOriginalSecret.skipMultilineEncoding, originalSkipMultilineEncoding: trueOriginalSecret.skipMultilineEncoding,
skipMultilineEncoding: modSecret.skipMultilineEncoding, skipMultilineEncoding: modSecret.skipMultilineEncoding,
originalTags: originalTags:
trueOriginalSecret.tags?.map((tag) => ({ id: tag.id, slug: tag.slug })) || [], trueOriginalSecret.tags?.map((tag) => ({ id: tag.id, slug: tag.slug })) || [],
tags: tags?.map((tag) => ({ id: tag.id, slug: tag.name || tag.slug || "" })) || [], tags: tags?.map((tag) => ({ id: tag.id, slug: tag.name || tag.slug || "" })) || [],
originalSecretMetadata: trueOriginalSecret.secretMetadata || [], originalSecretMetadata: trueOriginalSecret.secretMetadata || [],
secretMetadata: secretMetadata || [], secretMetadata: secretMetadata || [],
timestamp: Date.now(), timestamp: Date.now(),
resourceType: "secret", resourceType: "secret",
existingSecret: orgSecret existingSecret: orgSecret
}; };
addPendingChange(updateChange, { addPendingChange(updateChange, {
projectId, projectId,
environment, environment,
secretPath secretPath
}); });
}
if (!isReminderEvent) {
handlePopUpClose("secretDetail");
}
if (cb) cb();
return;
} }
await handleSecretOperation("update", SecretType.Shared, oldKey, { if (!isReminderEvent) {
value, handlePopUpClose("secretDetail");
tags: tagIds, }
comment,
reminderRepeatDays,
reminderNote,
reminderRecipients,
secretId: orgSecret.id,
newKey: hasKeyChanged ? key : undefined,
skipMultilineEncoding: modSecret.skipMultilineEncoding,
secretMetadata,
isRotatedSecret: orgSecret.isRotatedSecret,
secretValueHidden
});
if (cb) cb(); if (cb) cb();
} return;
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; await handleSecretOperation("update", SecretType.Shared, oldKey, {
if (isReminderEvent) { value,
successMessage = reminderRepeatDays tags: tagIds,
? "Successfully saved secret reminder" comment,
: "Successfully deleted secret reminder"; reminderRepeatDays,
} else { reminderNote,
successMessage = "Successfully saved secrets"; reminderRecipients,
} secretId: orgSecret.id,
newKey: hasKeyChanged ? key : undefined,
createNotification({ skipMultilineEncoding: modSecret.skipMultilineEncoding,
type: isProtectedBranch && !personalAction ? "info" : "success", secretMetadata,
text: isRotatedSecret: orgSecret.isRotatedSecret,
isProtectedBranch && !personalAction secretValueHidden
? "Requested changes have been sent for review"
: successMessage
});
} catch (error) {
console.log(error);
createNotification({
type: "error",
text: "Failed to save secret"
}); });
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] [environment, secretPath, isProtectedBranch, isBatchMode, projectId, addPendingChange]
); );
@@ -488,75 +480,67 @@ export const SecretListView = ({
value, value,
secretValueHidden secretValueHidden
} = popUp.deleteSecret?.data as SecretV3RawSanitized; } = popUp.deleteSecret?.data as SecretV3RawSanitized;
try { if (isBatchMode) {
if (isBatchMode) { const deleteChange: PendingSecretDelete = {
const deleteChange: PendingSecretDelete = { id: `${secretId}`,
id: `${secretId}`, type: PendingAction.Delete,
type: PendingAction.Delete, secretKey: key,
secretKey: key, secretValue: value || "",
secretValue: value || "", timestamp: Date.now(),
timestamp: Date.now(), resourceType: "secret",
resourceType: "secret", secretValueHidden
secretValueHidden };
};
addPendingChange(deleteChange, { addPendingChange(deleteChange, {
projectId, projectId,
environment, environment,
secretPath 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("deleteSecret");
handlePopUpClose("secretDetail"); handlePopUpClose("secretDetail");
createNotification({ return;
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"
});
} }
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, (popUp.deleteSecret?.data as SecretV3RawSanitized)?.key,
environment, environment,

View File

@@ -13,26 +13,18 @@ export const AutoCapitalizationSection = () => {
const { mutateAsync } = useUpdateProject(); const { mutateAsync } = useUpdateProject();
const handleToggleCapitalizationToggle = async (state: boolean) => { const handleToggleCapitalizationToggle = async (state: boolean) => {
try { if (!currentProject?.id) return;
if (!currentProject?.id) return;
await mutateAsync({ await mutateAsync({
projectId: currentProject.id, projectId: currentProject.id,
autoCapitalization: state autoCapitalization: state
}); });
const text = `Successfully ${state ? "enabled" : "disabled"} auto capitalization`; const text = `Successfully ${state ? "enabled" : "disabled"} auto capitalization`;
createNotification({ createNotification({
text, text,
type: "success" type: "success"
}); });
} catch (err) {
console.error(err);
createNotification({
text: "Failed to update auto capitalization",
type: "error"
});
}
}; };
return ( return (

View File

@@ -124,17 +124,13 @@ const LoadBackupModal = ({
return; return;
} }
try { await loadKmsBackup(backupContent);
await loadKmsBackup(backupContent); createNotification({
createNotification({ text: "Successfully loaded KMS backup",
text: "Successfully loaded KMS backup", type: "success"
type: "success" });
});
onOpenChange(false); onOpenChange(false);
} catch (err) {
console.error(err);
}
}; };
const parseFile = (file?: File) => { const parseFile = (file?: File) => {
@@ -245,20 +241,16 @@ export const EncryptionTab = () => {
}); });
const onUpdateProjectKms = async (data: TForm) => { const onUpdateProjectKms = async (data: TForm) => {
try { await updateProjectKms(
await updateProjectKms( data.kmsKeyId === INTERNAL_KMS_KEY_ID
data.kmsKeyId === INTERNAL_KMS_KEY_ID ? { type: KmsType.Internal }
? { type: KmsType.Internal } : { type: KmsType.External, kmsId: data.kmsKeyId }
: { type: KmsType.External, kmsId: data.kmsKeyId } );
);
createNotification({ createNotification({
text: "Successfully updated project KMS", text: "Successfully updated project KMS",
type: "success" type: "success"
}); });
} catch (err) {
console.error(err);
}
}; };
return ( return (

View File

@@ -36,28 +36,20 @@ const Content = ({ onComplete }: ContentProps) => {
}); });
const onFormSubmit = async ({ environmentName, environmentSlug }: FormData) => { const onFormSubmit = async ({ environmentName, environmentSlug }: FormData) => {
try { if (!currentProject?.id) return;
if (!currentProject?.id) return;
const env = await mutateAsync({ const env = await mutateAsync({
projectId: currentProject.id, projectId: currentProject.id,
name: environmentName, name: environmentName,
slug: environmentSlug slug: environmentSlug
}); });
createNotification({ createNotification({
text: "Successfully created environment", text: "Successfully created environment",
type: "success" type: "success"
}); });
onComplete(env); onComplete(env);
} catch (err) {
console.error(err);
createNotification({
text: "Failed to create environment",
type: "error"
});
}
}; };
return ( return (

View File

@@ -33,29 +33,21 @@ export const UpdateEnvironmentModal = ({ popUp, handlePopUpClose, handlePopUpTog
const oldEnvId = (popUp?.updateEnv?.data as { id: string })?.id; const oldEnvId = (popUp?.updateEnv?.data as { id: string })?.id;
const onFormSubmit = async ({ name, slug }: FormData) => { const onFormSubmit = async ({ name, slug }: FormData) => {
try { if (!currentProject?.id) return;
if (!currentProject?.id) return;
await mutateAsync({ await mutateAsync({
projectId: currentProject.id, projectId: currentProject.id,
name, name,
slug, slug,
id: oldEnvId id: oldEnvId
}); });
createNotification({ createNotification({
text: "Successfully updated environment", text: "Successfully updated environment",
type: "success" type: "success"
}); });
handlePopUpClose("updateEnv"); handlePopUpClose("updateEnv");
} catch (err) {
console.error(err);
createNotification({
text: "Failed to update environment",
type: "error"
});
}
}; };
return ( return (

View File

@@ -34,22 +34,15 @@ export const PointInTimeVersionLimitSection = () => {
if (!currentProject) return null; if (!currentProject) return null;
const handleVersionLimitSubmit = async ({ pitVersionLimit }: TForm) => { const handleVersionLimitSubmit = async ({ pitVersionLimit }: TForm) => {
try { await updateProject({
await updateProject({ pitVersionLimit,
pitVersionLimit, projectId
projectId });
});
createNotification({ createNotification({
text: "Successfully updated version limit", text: "Successfully updated version limit",
type: "success" type: "success"
}); });
} catch {
createNotification({
text: "Failed updating project's version limit",
type: "error"
});
}
}; };
const isAdmin = hasProjectRole(ProjectMembershipRole.Admin); const isAdmin = hasProjectRole(ProjectMembershipRole.Admin);

View File

@@ -15,12 +15,12 @@ export const SecretSharingSection = () => {
const handleToggle = async (state: boolean) => { const handleToggle = async (state: boolean) => {
setIsLoading(true); setIsLoading(true);
try { if (!currentProject?.id) {
if (!currentProject?.id) { setIsLoading(false);
setIsLoading(false); return;
return; }
}
try {
await updateProject({ await updateProject({
projectId: currentProject.id, projectId: currentProject.id,
secretSharing: state secretSharing: state
@@ -30,12 +30,6 @@ export const SecretSharingSection = () => {
text: `Successfully ${state ? "enabled" : "disabled"} secret sharing for this project`, text: `Successfully ${state ? "enabled" : "disabled"} secret sharing for this project`,
type: "success" type: "success"
}); });
} catch (err) {
console.error(err);
createNotification({
text: "Failed to update secret sharing for this project",
type: "error"
});
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }

View File

@@ -39,29 +39,21 @@ export const AddSecretTagModal = ({ popUp, handlePopUpClose, handlePopUpToggle }
}); });
const onFormSubmit = async ({ slug }: FormData) => { const onFormSubmit = async ({ slug }: FormData) => {
try { if (!currentProject?.id) return;
if (!currentProject?.id) return;
await createWsTag.mutateAsync({ await createWsTag.mutateAsync({
projectId: currentProject?.id, projectId: currentProject?.id,
tagSlug: slug, tagSlug: slug,
tagColor: "" tagColor: ""
}); });
handlePopUpClose("CreateSecretTag"); handlePopUpClose("CreateSecretTag");
createNotification({ createNotification({
text: "Successfully created a tag", text: "Successfully created a tag",
type: "success" type: "success"
}); });
reset(); reset();
} catch (err) {
console.error(err);
createNotification({
text: "Failed to create a tag",
type: "error"
});
}
}; };
return ( return (

View File

@@ -29,25 +29,17 @@ export const SecretTagsSection = (): JSX.Element => {
const deleteWsTag = useDeleteWsTag(); const deleteWsTag = useDeleteWsTag();
const onDeleteApproved = async () => { const onDeleteApproved = async () => {
try { await deleteWsTag.mutateAsync({
await deleteWsTag.mutateAsync({ projectId: currentProject?.id || "",
projectId: currentProject?.id || "", tagID: (popUp?.deleteTagConfirmation?.data as DeleteModalData)?.id
tagID: (popUp?.deleteTagConfirmation?.data as DeleteModalData)?.id });
});
createNotification({ createNotification({
text: "Successfully deleted tag", text: "Successfully deleted tag",
type: "success" type: "success"
}); });
handlePopUpClose("deleteTagConfirmation"); handlePopUpClose("deleteTagConfirmation");
} catch (err) {
console.error(err);
createNotification({
text: "Failed to delete the tag",
type: "error"
});
}
}; };
return ( return (

View File

@@ -126,43 +126,35 @@ export const BitbucketConfigurePage = () => {
}: TFormData) => { }: TFormData) => {
if (!targetRepo || !targetWorkspace) return; if (!targetRepo || !targetWorkspace) return;
try { await createIntegration.mutateAsync({
await createIntegration.mutateAsync({ integrationAuthId,
integrationAuthId, isActive: true,
isActive: true, app: targetRepo.name,
app: targetRepo.name, appId: targetRepo.appId,
appId: targetRepo.appId, sourceEnvironment: sourceEnvironment.slug,
sourceEnvironment: sourceEnvironment.slug, targetEnvironment: targetWorkspace.name,
targetEnvironment: targetWorkspace.name, targetEnvironmentId: targetWorkspace.slug,
targetEnvironmentId: targetWorkspace.slug, ...(scope.value === BitbucketScope.Env &&
...(scope.value === BitbucketScope.Env && targetEnvironment && {
targetEnvironment && { targetService: targetEnvironment.name,
targetService: targetEnvironment.name, targetServiceId: targetEnvironment.uuid
targetServiceId: targetEnvironment.uuid }),
}), secretPath
secretPath });
});
createNotification({ createNotification({
type: "success", type: "success",
text: "Successfully created integration" text: "Successfully created integration"
}); });
navigate({ navigate({
to: "/projects/secret-management/$projectId/integrations", to: "/projects/secret-management/$projectId/integrations",
params: { params: {
projectId: currentProject.id projectId: currentProject.id
}, },
search: { search: {
selectedTab: IntegrationsListPageTabs.NativeIntegrations selectedTab: IntegrationsListPageTabs.NativeIntegrations
} }
}); });
} catch (err) {
createNotification({
type: "error",
text: "Failed to create integration"
});
console.error(err);
}
}; };
useEffect(() => { useEffect(() => {

View File

@@ -73,51 +73,43 @@ export const CircleCIConfigurePage = () => {
: undefined; : undefined;
const onSubmit = async (data: TFormData) => { const onSubmit = async (data: TFormData) => {
try { if (data.scope === CircleCiScope.Context) {
if (data.scope === CircleCiScope.Context) { await mutateAsync({
await mutateAsync({ scope: data.scope,
scope: data.scope, integrationAuthId,
integrationAuthId, isActive: true,
isActive: true, sourceEnvironment: data.sourceEnvironment.slug,
sourceEnvironment: data.sourceEnvironment.slug, app: data.targetContext.name,
app: data.targetContext.name, appId: data.targetContext.id,
appId: data.targetContext.id, owner: data.targetOrg.name,
owner: data.targetOrg.name, secretPath: data.secretPath
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"
}); });
navigate({ } else {
to: "/projects/secret-management/$projectId/integrations", await mutateAsync({
params: { scope: data.scope,
projectId: currentProject.id integrationAuthId,
}, isActive: true,
search: { app: data.targetProject.name, // project name
selectedTab: IntegrationsListPageTabs.NativeIntegrations 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) if (isCircleCIOrganizationsLoading)

View File

@@ -1,8 +1,6 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useNavigate, useSearch } from "@tanstack/react-router"; import { useNavigate, useSearch } from "@tanstack/react-router";
import axios from "axios";
import { createNotification } from "@app/components/notifications";
import { import {
Button, Button,
Card, Card,
@@ -102,19 +100,7 @@ export const CloudflarePagesConfigurePage = () => {
selectedTab: IntegrationsListPageTabs.NativeIntegrations selectedTab: IntegrationsListPageTabs.NativeIntegrations
} }
}); });
} catch (err) { } catch {
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"
});
setIsLoading(false); setIsLoading(false);
} }
}; };

View File

@@ -1,8 +1,6 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useNavigate, useSearch } from "@tanstack/react-router"; 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 { Button, Card, CardTitle, FormControl, Select, SelectItem } from "@app/components/v2";
import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { SecretPathInput } from "@app/components/v2/SecretPathInput";
import { ROUTE_PATHS } from "@app/const/routes"; import { ROUTE_PATHS } from "@app/const/routes";
@@ -75,19 +73,7 @@ export const CloudflareWorkersConfigurePage = () => {
selectedTab: IntegrationsListPageTabs.NativeIntegrations selectedTab: IntegrationsListPageTabs.NativeIntegrations
} }
}); });
} catch (err) { } catch {
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"
});
setIsLoading(false); setIsLoading(false);
} }
}; };

View File

@@ -55,49 +55,45 @@ export const DatabricksConfigurePage = () => {
const [secretPath, setSecretPath] = useState("/"); const [secretPath, setSecretPath] = useState("/");
const handleButtonClick = async () => { const handleButtonClick = async () => {
try { if (!integrationAuth?.id) return;
if (!integrationAuth?.id) return;
if (!targetScope) { if (!targetScope) {
createNotification({ createNotification({
type: "error", type: "error",
text: "Please select a scope" 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
}); });
return;
navigate({
to: "/projects/secret-management/$projectId/integrations",
params: {
projectId: currentProject.id
},
search: {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
});
} catch (err) {
console.error(err);
} }
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 ? ( return integrationAuth && selectedSourceEnvironment && integrationAuthScopes ? (

View File

@@ -12,12 +12,10 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useNavigate, useSearch } from "@tanstack/react-router"; import { useNavigate, useSearch } from "@tanstack/react-router";
import axios from "axios";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { z, ZodIssueCode } from "zod"; import { z, ZodIssueCode } from "zod";
import { createNotification } from "@app/components/notifications";
import { import {
Button, Button,
Card, Card,
@@ -275,19 +273,7 @@ export const GithubConfigurePage = () => {
selectedTab: IntegrationsListPageTabs.NativeIntegrations selectedTab: IntegrationsListPageTabs.NativeIntegrations
} }
}); });
} catch (err) { } catch {
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"
});
setIsLoading(false); setIsLoading(false);
} }
}; };

View File

@@ -4,10 +4,8 @@ import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-sv
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useNavigate } from "@tanstack/react-router"; import { useNavigate } from "@tanstack/react-router";
import axios from "axios";
import { z } from "zod"; import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { Button, Card, CardBody, CardTitle, FormControl, Input } from "@app/components/v2"; import { Button, Card, CardBody, CardTitle, FormControl, Input } from "@app/components/v2";
import { useProject } from "@app/context"; import { useProject } from "@app/context";
import { useSaveIntegrationAccessToken } from "@app/hooks/api"; import { useSaveIntegrationAccessToken } from "@app/hooks/api";
@@ -41,37 +39,23 @@ export const HashicorpVaultAuthorizePage = () => {
}); });
const handleFormSubmit = async (formData: TForm) => { const handleFormSubmit = async (formData: TForm) => {
try { const integrationAuth = await mutateAsync({
const integrationAuth = await mutateAsync({ workspaceId: currentProject.id,
workspaceId: currentProject.id, integration: "hashicorp-vault",
integration: "hashicorp-vault", accessId: formData.vaultRoleID,
accessId: formData.vaultRoleID, accessToken: formData.vaultSecretID,
accessToken: formData.vaultSecretID, url: formData.vaultURL,
url: formData.vaultURL, namespace: formData.vaultNamespace
namespace: formData.vaultNamespace });
}); navigate({
navigate({ to: "/projects/secret-management/$projectId/integrations/hashicorp-vault/create",
to: "/projects/secret-management/$projectId/integrations/hashicorp-vault/create", params: {
params: { projectId: currentProject.id
projectId: currentProject.id },
}, search: {
search: { integrationAuthId: integrationAuth.id
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;
} }
});
createNotification({
text: errorMessage,
type: "error"
});
}
}; };
return ( return (

View File

@@ -10,10 +10,8 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { useNavigate, useSearch } from "@tanstack/react-router"; import { useNavigate, useSearch } from "@tanstack/react-router";
import axios from "axios";
import { z } from "zod"; import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { import {
Button, Button,
Card, Card,
@@ -90,38 +88,24 @@ export const HashicorpVaultConfigurePage = () => {
}); });
const handleFormSubmit = async (formData: TForm) => { const handleFormSubmit = async (formData: TForm) => {
try { if (!integrationAuth?.id) return;
if (!integrationAuth?.id) return; await mutateAsync({
await mutateAsync({ integrationAuthId: integrationAuth?.id,
integrationAuthId: integrationAuth?.id, isActive: true,
isActive: true, app: formData.vaultEnginePath,
app: formData.vaultEnginePath, sourceEnvironment: formData.selectedSourceEnvironment,
sourceEnvironment: formData.selectedSourceEnvironment, path: formData.vaultSecretPath,
path: formData.vaultSecretPath, secretPath: formData.secretPath
secretPath: formData.secretPath });
}); navigate({
navigate({ to: "/projects/secret-management/$projectId/integrations",
to: "/projects/secret-management/$projectId/integrations", params: {
params: { projectId: currentProject.id
projectId: currentProject.id },
}, search: {
search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations
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"
});
}
}; };
return integrationAuth ? ( return integrationAuth ? (

View File

@@ -6,7 +6,6 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { useNavigate } from "@tanstack/react-router"; import { useNavigate } from "@tanstack/react-router";
import { z } from "zod"; import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2";
import { useProject } from "@app/context"; import { useProject } from "@app/context";
import { removeTrailingSlash } from "@app/helpers/string"; import { removeTrailingSlash } from "@app/helpers/string";
@@ -29,30 +28,22 @@ export const OctopusDeployAuthorizePage = () => {
}); });
const onSubmit = async ({ instanceUrl, apiKey }: TForm) => { const onSubmit = async ({ instanceUrl, apiKey }: TForm) => {
try { const integrationAuth = await mutateAsync({
const integrationAuth = await mutateAsync({ workspaceId: currentProject.id,
workspaceId: currentProject.id, integration: "octopus-deploy",
integration: "octopus-deploy", url: removeTrailingSlash(instanceUrl),
url: removeTrailingSlash(instanceUrl), accessToken: apiKey
accessToken: apiKey });
});
navigate({ navigate({
to: "/projects/secret-management/$projectId/integrations/octopus-deploy/create", to: "/projects/secret-management/$projectId/integrations/octopus-deploy/create",
params: { params: {
projectId: currentProject.id projectId: currentProject.id
}, },
search: { search: {
integrationAuthId: integrationAuth.id integrationAuthId: integrationAuth.id
} }
}); });
} catch (err: any) {
createNotification({
type: "error",
text: err.message ?? "Error authorizing integration"
});
console.error(err);
}
}; };
return ( return (

View File

@@ -107,49 +107,41 @@ export const OctopusDeployConfigurePage = () => {
targetRoles, targetRoles,
scope scope
}: TFormData) => { }: TFormData) => {
try { await createIntegration.mutateAsync({
await createIntegration.mutateAsync({ integrationAuthId,
integrationAuthId, isActive: true,
isActive: true, scope,
scope, app: targetResource.name,
app: targetResource.name, appId: targetResource.appId,
appId: targetResource.appId, targetEnvironment: targetSpace.Name,
targetEnvironment: targetSpace.Name, targetEnvironmentId: targetSpace.Id,
targetEnvironmentId: targetSpace.Id, metadata: {
metadata: { octopusDeployScopeValues: {
octopusDeployScopeValues: { Environment: targetEnvironments?.map(({ Id }) => Id),
Environment: targetEnvironments?.map(({ Id }) => Id), Action: targetActions?.map(({ Id }) => Id),
Action: targetActions?.map(({ Id }) => Id), Channel: targetChannels?.map(({ Id }) => Id),
Channel: targetChannels?.map(({ Id }) => Id), ProcessOwner: targetProcesses?.map(({ Id }) => Id),
ProcessOwner: targetProcesses?.map(({ Id }) => Id), Role: targetRoles?.map(({ Id }) => Id),
Role: targetRoles?.map(({ Id }) => Id), Machine: targetMachines?.map(({ Id }) => Id)
Machine: targetMachines?.map(({ Id }) => Id)
}
},
sourceEnvironment: sourceEnvironment.slug,
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) { sourceEnvironment: sourceEnvironment.slug,
createNotification({ secretPath
type: "error", });
text: "Failed to create integration"
}); createNotification({
console.error(err); type: "success",
} text: "Successfully created integration"
});
navigate({
to: "/projects/secret-management/$projectId/integrations",
params: {
projectId: currentProject.id
},
search: {
selectedTab: IntegrationsListPageTabs.NativeIntegrations
}
});
}; };
useEffect(() => { useEffect(() => {

View File

@@ -83,23 +83,14 @@ export const ChangeEmailSection = () => {
return; return;
} }
try { await requestEmailChangeOTP({ newEmail });
await requestEmailChangeOTP({ newEmail }); setPendingEmail(newEmail);
setPendingEmail(newEmail); setIsOTPModalOpen(true);
setIsOTPModalOpen(true);
createNotification({ createNotification({
text: "Verification code sent to your new email address. Check your inbox!", text: "Verification code sent to your new email address. Check your inbox!",
type: "success" type: "success"
}); });
} catch (err: any) {
console.error(err);
const errorMessage = err?.response?.data?.message || "Failed to send verification code";
createNotification({
text: errorMessage,
type: "error"
});
}
}; };
const [typedOTP, setTypedOTP] = useState(""); const [typedOTP, setTypedOTP] = useState("");
@@ -135,8 +126,6 @@ export const ChangeEmailSection = () => {
navigate({ to: "/login" }); navigate({ to: "/login" });
}, 2000); }, 2000);
} catch (err: any) { } catch (err: any) {
console.error(err);
const errorMessage = err?.response?.data?.message || "Invalid verification code"; const errorMessage = err?.response?.data?.message || "Invalid verification code";
if (errorMessage.includes("Invalid verification code")) { if (errorMessage.includes("Invalid verification code")) {
// Reset to email step so user must request new OTP // Reset to email step so user must request new OTP
@@ -149,11 +138,6 @@ export const ChangeEmailSection = () => {
text: "Invalid verification code. Please request a new one.", text: "Invalid verification code. Please request a new one.",
type: "error" type: "error"
}); });
} else {
createNotification({
text: errorMessage,
type: "error"
});
} }
} }
}; };

View File

@@ -97,21 +97,13 @@ export const ChangePasswordSection = () => {
}; };
const onSetupPassword = async () => { const onSetupPassword = async () => {
try { await sendSetupPasswordEmail.mutateAsync();
await sendSetupPasswordEmail.mutateAsync();
createNotification({ createNotification({
title: "Password setup verification email sent", title: "Password setup verification email sent",
text: "Check your email to confirm password setup", text: "Check your email to confirm password setup",
type: "info" type: "info"
}); });
} catch (err) {
console.error(err);
createNotification({
text: "Failed to send password setup email",
type: "error"
});
}
}; };
return ( return (

View File

@@ -15,23 +15,15 @@ export const DeleteAccountSection = () => {
const { mutateAsync: deleteUserMutateAsync, isPending } = useDeleteMe(); const { mutateAsync: deleteUserMutateAsync, isPending } = useDeleteMe();
const handleDeleteAccountSubmit = async () => { const handleDeleteAccountSubmit = async () => {
try { await deleteUserMutateAsync();
await deleteUserMutateAsync();
createNotification({ createNotification({
text: "Successfully deleted account", text: "Successfully deleted account",
type: "success" type: "success"
}); });
navigate({ to: "/login" }); navigate({ to: "/login" });
handlePopUpClose("deleteAccount"); handlePopUpClose("deleteAccount");
} catch (err) {
console.error(err);
createNotification({
text: "Failed to delete account",
type: "error"
});
}
}; };
return ( return (

View File

@@ -84,49 +84,27 @@ export const MFASection = () => {
}, [totpRegistration, showMobileAuthSetup]); }, [totpRegistration, showMobileAuthSetup]);
const handleTotpDeletion = async () => { const handleTotpDeletion = async () => {
try { await deleteTotpConfiguration();
await deleteTotpConfiguration();
await mutateAsync({ await mutateAsync({
selectedMfaMethod: MfaMethod.EMAIL selectedMfaMethod: MfaMethod.EMAIL
}); });
createNotification({ createNotification({
text: "Successfully deleted mobile authenticator and switched to email authentication", text: "Successfully deleted mobile authenticator and switched to email authentication",
type: "success" type: "success"
}); });
handlePopUpClose("deleteTotpConfig"); handlePopUpClose("deleteTotpConfig");
} catch (err) {
console.error(err);
const error = err as any;
const text = error?.response?.data?.message ?? "Failed to delete mobile authenticator";
createNotification({
text,
type: "error"
});
}
}; };
const handleGenerateMoreRecoveryCodes = async () => { const handleGenerateMoreRecoveryCodes = async () => {
try { await createTotpRecoveryCodes();
await createTotpRecoveryCodes();
createNotification({ createNotification({
text: "Successfully generated new recovery codes", text: "Successfully generated new recovery codes",
type: "success" type: "success"
}); });
} catch (err) {
console.error(err);
const error = err as any;
const text = error?.response?.data?.message ?? "Failed to generate new recovery codes";
createNotification({
text,
type: "error"
});
}
}; };
const handleFormDataChange = async (field: string, value: any) => { const handleFormDataChange = async (field: string, value: any) => {
@@ -200,10 +178,6 @@ export const MFASection = () => {
await queryClient.invalidateQueries({ queryKey: userKeys.totpConfiguration }); await queryClient.invalidateQueries({ queryKey: userKeys.totpConfiguration });
} catch { } catch {
createNotification({
text: "Failed to verify TOTP code. Please try again.",
type: "error"
});
setIsLoading(false); setIsLoading(false);
return; return;
} }
@@ -249,12 +223,6 @@ export const MFASection = () => {
setShowMobileAuthSetup(false); setShowMobileAuthSetup(false);
setTotpCode(""); setTotpCode("");
setShouldShowRecoveryCodes.off(); setShouldShowRecoveryCodes.off();
} catch (err) {
createNotification({
text: "Something went wrong while updating two-factor authentication settings.",
type: "error"
});
console.error(err);
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }

View File

@@ -40,19 +40,11 @@ export const SessionsTable = () => {
] as const); ] as const);
const handleSignOut = async (sessionId: string) => { const handleSignOut = async (sessionId: string) => {
try { await revokeMySessionById(sessionId);
await revokeMySessionById(sessionId); createNotification({
createNotification({ text: "Session revoked successfully",
text: "Session revoked successfully", type: "success"
type: "success" });
});
} catch (error) {
console.error(error);
createNotification({
text: "Failed to revoke session",
type: "error"
});
}
handlePopUpClose("deleteSession"); handlePopUpClose("deleteSession");
}; };

View File

@@ -27,22 +27,14 @@ export const UserNameSection = (): JSX.Element => {
}, [user]); }, [user]);
const onFormSubmit = async ({ name }: FormData) => { const onFormSubmit = async ({ name }: FormData) => {
try { if (!user?.id) return;
if (!user?.id) return; if (name === "") return;
if (name === "") return;
await mutateAsync({ newName: name }); await mutateAsync({ newName: name });
createNotification({ createNotification({
text: "Successfully renamed user", text: "Successfully renamed user",
type: "success" type: "success"
}); });
} catch (error) {
console.error(error);
createNotification({
text: "Failed to rename user",
type: "error"
});
}
}; };
return ( return (