mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 02:26:26 +00:00
feat: added resync replication feature
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
export { useCreateSecretImport, useDeleteSecretImport, useUpdateSecretImport } from "./mutation";
|
||||
export {
|
||||
useCreateSecretImport,
|
||||
useDeleteSecretImport,
|
||||
useResyncSecretReplication,
|
||||
useUpdateSecretImport
|
||||
} from "./mutation";
|
||||
export {
|
||||
useGetImportedFoldersByEnv,
|
||||
useGetImportedSecretsAllEnvs,
|
||||
|
||||
@@ -3,7 +3,12 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { secretImportKeys } from "./queries";
|
||||
import { TCreateSecretImportDTO, TDeleteSecretImportDTO, TUpdateSecretImportDTO } from "./types";
|
||||
import {
|
||||
TCreateSecretImportDTO,
|
||||
TDeleteSecretImportDTO,
|
||||
TResyncSecretReplicationDTO,
|
||||
TUpdateSecretImportDTO
|
||||
} from "./types";
|
||||
|
||||
export const useCreateSecretImport = () => {
|
||||
const queryClient = useQueryClient();
|
||||
@@ -54,6 +59,19 @@ export const useUpdateSecretImport = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useResyncSecretReplication = () => {
|
||||
return useMutation<{}, {}, TResyncSecretReplicationDTO>({
|
||||
mutationFn: async ({ environment, projectId, path, id }) => {
|
||||
const { data } = await apiRequest.post(`/api/v1/secret-imports/${id}/replication-resync`, {
|
||||
environment,
|
||||
path,
|
||||
workspaceId: projectId
|
||||
});
|
||||
return data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteSecretImport = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
|
||||
@@ -76,6 +76,13 @@ export type TUpdateSecretImportDTO = {
|
||||
}>;
|
||||
};
|
||||
|
||||
export type TResyncSecretReplicationDTO = {
|
||||
id: string;
|
||||
projectId: string;
|
||||
environment: string;
|
||||
path?: string;
|
||||
};
|
||||
|
||||
export type TDeleteSecretImportDTO = {
|
||||
id: string;
|
||||
projectId: string;
|
||||
|
||||
@@ -81,7 +81,8 @@ export const CreateSecretImportForm = ({
|
||||
reset();
|
||||
createNotification({
|
||||
type: "success",
|
||||
text: "Successfully linked"
|
||||
text: `Successfully linked.${isReplication ? " Kindly refresh the board to see changes." : ""
|
||||
}`
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
+54
-1
@@ -6,14 +6,18 @@ import {
|
||||
faFileImport,
|
||||
faFolder,
|
||||
faKey,
|
||||
faRotate,
|
||||
faUpDown
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import { EmptyState, IconButton, SecretInput, TableContainer, Tag } from "@app/components/v2";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||
import { useToggle } from "@app/hooks";
|
||||
import { useResyncSecretReplication } from "@app/hooks/api";
|
||||
|
||||
type Props = {
|
||||
onDelete: () => void;
|
||||
@@ -60,10 +64,12 @@ export const SecretImportItem = ({
|
||||
secretPath,
|
||||
environment
|
||||
}: Props) => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const [isExpanded, setIsExpanded] = useToggle();
|
||||
const { attributes, listeners, transform, transition, setNodeRef, isDragging } = useSortable({
|
||||
id
|
||||
});
|
||||
const resyncSecretReplication = useResyncSecretReplication();
|
||||
|
||||
useEffect(() => {
|
||||
const filteredSecrets = importedSecrets.filter((secret) =>
|
||||
@@ -88,6 +94,28 @@ export const SecretImportItem = ({
|
||||
transition
|
||||
};
|
||||
|
||||
const handleResyncSecretReplication = async () => {
|
||||
if (resyncSecretReplication.isLoading) return;
|
||||
try {
|
||||
await resyncSecretReplication.mutateAsync({
|
||||
id,
|
||||
environment,
|
||||
path: secretPath,
|
||||
projectId: currentWorkspace?.id || ""
|
||||
});
|
||||
createNotification({
|
||||
text: "Kindly refresh the board to see changes.",
|
||||
type: "success"
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
createNotification({
|
||||
text: "Failed to resync replication",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -109,6 +137,31 @@ export const SecretImportItem = ({
|
||||
isReplication={isReplication}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 px-4 py-2">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
|
||||
renderTooltip
|
||||
allowedLabel="Resync replicated secrets"
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<IconButton
|
||||
size="md"
|
||||
colorSchema="primary"
|
||||
variant="plain"
|
||||
ariaLabel="expand"
|
||||
className={twMerge(
|
||||
"p-0 opacity-0 group-hover:opacity-100",
|
||||
resyncSecretReplication.isLoading && "animate-spin opacity-100"
|
||||
)}
|
||||
isDisabled={!isAllowed}
|
||||
onClick={handleResyncSecretReplication}
|
||||
>
|
||||
<FontAwesomeIcon icon={faRotate} />
|
||||
</IconButton>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4 border-l border-mineshaft-600 px-4 py-2">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
|
||||
Reference in New Issue
Block a user