mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 22:51:53 +00:00
Merge pull request #3422 from Infisical/feat/addProjectDeletionProtection
Add project delete protection
This commit is contained in:
@@ -33,6 +33,7 @@ import {
|
||||
TGetUpgradeProjectStatusDTO,
|
||||
TListProjectIdentitiesDTO,
|
||||
ToggleAutoCapitalizationDTO,
|
||||
ToggleDeleteProjectProtectionDTO,
|
||||
TSearchProjectsDTO,
|
||||
TUpdateWorkspaceIdentityRoleDTO,
|
||||
TUpdateWorkspaceUserRoleDTO,
|
||||
@@ -306,6 +307,25 @@ export const useToggleAutoCapitalization = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useToggleDeleteProjectProtection = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation<Workspace, object, ToggleDeleteProjectProtectionDTO>({
|
||||
mutationFn: async ({ workspaceID, state }) => {
|
||||
const { data } = await apiRequest.post<{ workspace: Workspace }>(
|
||||
`/api/v1/workspace/${workspaceID}/delete-protection`,
|
||||
{
|
||||
hasDeleteProtection: state
|
||||
}
|
||||
);
|
||||
return data.workspace;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: workspaceKeys.getAllUserWorkspace() });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateWorkspaceVersionLimit = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -316,8 +336,8 @@ export const useUpdateWorkspaceVersionLimit = () => {
|
||||
});
|
||||
return data.workspace;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: workspaceKeys.getAllUserWorkspace() });
|
||||
onSuccess: (dto) => {
|
||||
queryClient.invalidateQueries({ queryKey: workspaceKeys.getAllUserWorkspace(dto.type) });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -36,6 +36,7 @@ export type Workspace = {
|
||||
slug: string;
|
||||
createdAt: string;
|
||||
roles?: TProjectRole[];
|
||||
hasDeleteProtection: boolean;
|
||||
};
|
||||
|
||||
export type WorkspaceEnv = {
|
||||
@@ -80,6 +81,7 @@ export type UpdateProjectDTO = {
|
||||
export type UpdatePitVersionLimitDTO = { projectSlug: string; pitVersionLimit: number };
|
||||
export type UpdateAuditLogsRetentionDTO = { projectSlug: string; auditLogsRetentionDays: number };
|
||||
export type ToggleAutoCapitalizationDTO = { workspaceID: string; state: boolean };
|
||||
export type ToggleDeleteProjectProtectionDTO = { workspaceID: string; state: boolean };
|
||||
|
||||
export type DeleteWorkspaceDTO = { workspaceID: string };
|
||||
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import { Checkbox } from "@app/components/v2";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||
import { useToggleDeleteProjectProtection } from "@app/hooks/api/workspace/queries";
|
||||
|
||||
export const DeleteProjectProtection = () => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { mutateAsync } = useToggleDeleteProjectProtection();
|
||||
|
||||
const handleToggleDeleteProjectProtection = async (state: boolean) => {
|
||||
try {
|
||||
if (!currentWorkspace?.id) return;
|
||||
|
||||
await mutateAsync({
|
||||
workspaceID: currentWorkspace.id,
|
||||
state
|
||||
});
|
||||
|
||||
const text = `Successfully ${state ? "enabled" : "disabled"} delete protection`;
|
||||
createNotification({
|
||||
text,
|
||||
type: "success"
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to update delete protection",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<p className="mb-3 text-xl font-semibold">Delete Protection</p>
|
||||
<ProjectPermissionCan I={ProjectPermissionActions.Edit} a={ProjectPermissionSub.Settings}>
|
||||
{(isAllowed) => (
|
||||
<div className="w-max">
|
||||
<Checkbox
|
||||
className="data-[state=checked]:bg-primary"
|
||||
id="hasDeleteProtection"
|
||||
isDisabled={!isAllowed}
|
||||
isChecked={currentWorkspace?.hasDeleteProtection ?? false}
|
||||
onCheckedChange={(state) => {
|
||||
handleToggleDeleteProjectProtection(state as boolean);
|
||||
}}
|
||||
>
|
||||
Protects the project from being deleted accidentally. While this option is enabled,
|
||||
you can't delete the project.
|
||||
</Checkbox>
|
||||
</div>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
export { DeleteProjectProtection } from "./DeleteProjectProtection";
|
||||
+1
-1
@@ -144,7 +144,7 @@ export const DeleteProjectSection = () => {
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
isLoading={isDeleting}
|
||||
isDisabled={!isAllowed || isDeleting}
|
||||
isDisabled={!isAllowed || isDeleting || currentWorkspace?.hasDeleteProtection}
|
||||
colorSchema="danger"
|
||||
variant="outline_bg"
|
||||
type="submit"
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ import { ProjectType, ProjectVersion } from "@app/hooks/api/workspace/types";
|
||||
import { AuditLogsRetentionSection } from "../AuditLogsRetentionSection";
|
||||
import { AutoCapitalizationSection } from "../AutoCapitalizationSection";
|
||||
import { BackfillSecretReferenceSecretion } from "../BackfillSecretReferenceSection";
|
||||
import { DeleteProjectProtection } from "../DeleteProjectProtection";
|
||||
import { DeleteProjectSection } from "../DeleteProjectSection";
|
||||
import { EnvironmentSection } from "../EnvironmentSection";
|
||||
import { PointInTimeVersionLimitSection } from "../PointInTimeVersionLimitSection";
|
||||
@@ -27,6 +28,7 @@ export const ProjectGeneralTab = () => {
|
||||
{currentWorkspace?.version !== ProjectVersion.V3 && isSecretManager && (
|
||||
<RebuildSecretIndicesSection />
|
||||
)}
|
||||
<DeleteProjectProtection />
|
||||
<DeleteProjectSection />
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user