diff --git a/frontend/src/hooks/api/secretFolders/types.ts b/frontend/src/hooks/api/secretFolders/types.ts index 8fde9c63d..412f2686d 100644 --- a/frontend/src/hooks/api/secretFolders/types.ts +++ b/frontend/src/hooks/api/secretFolders/types.ts @@ -1,3 +1,7 @@ +export enum ReservedFolders { + SecretReplication = "__reserve_replication_" +} + export type TSecretFolder = { id: string; name: string; diff --git a/frontend/src/hooks/api/secretImports/types.ts b/frontend/src/hooks/api/secretImports/types.ts index 64b55425d..1a6c06dd3 100644 --- a/frontend/src/hooks/api/secretImports/types.ts +++ b/frontend/src/hooks/api/secretImports/types.ts @@ -10,6 +10,7 @@ export type TSecretImport = { position: string; createdAt: string; updatedAt: string; + isReserved?: boolean; isReplication?: boolean; isReplicationSuccess?: boolean; replicationStatus?: string; diff --git a/frontend/src/lib/fn/string.ts b/frontend/src/lib/fn/string.ts new file mode 100644 index 000000000..a7de20262 --- /dev/null +++ b/frontend/src/lib/fn/string.ts @@ -0,0 +1,9 @@ +import { ReservedFolders } from "@app/hooks/api/secretFolders/types"; + +export const formatReservedPaths = (secretPath: string) => { + const i = secretPath.indexOf(ReservedFolders.SecretReplication); + if (i !== -1) { + return secretPath.slice(0, i); + } + return secretPath; +}; diff --git a/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx b/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx index 4815c7535..33025342f 100644 --- a/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx +++ b/frontend/src/views/SecretApprovalPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx @@ -20,6 +20,7 @@ import { useUpdateSecretApprovalReviewStatus } from "@app/hooks/api"; import { ApprovalStatus, CommitType, TWorkspaceUser } from "@app/hooks/api/types"; +import { formatReservedPaths } from "@app/lib/fn/string"; import { SecretApprovalRequestAction } from "./SecretApprovalRequestAction"; import { SecretApprovalRequestChangeItem } from "./SecretApprovalRequestChangeItem"; @@ -200,7 +201,9 @@ export const SecretApprovalRequestChanges = ({
-
{secretApprovalRequestDetails.secretPath}
+
+ {formatReservedPaths(secretApprovalRequestDetails.secretPath)} +
diff --git a/frontend/src/views/SecretMainPage/components/ActionBar/CreateSecretImportForm.tsx b/frontend/src/views/SecretMainPage/components/ActionBar/CreateSecretImportForm.tsx index a2a0b4354..5832779e3 100644 --- a/frontend/src/views/SecretMainPage/components/ActionBar/CreateSecretImportForm.tsx +++ b/frontend/src/views/SecretMainPage/components/ActionBar/CreateSecretImportForm.tsx @@ -6,7 +6,6 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, - Checkbox, FormControl, Modal, ModalContent, @@ -151,11 +150,25 @@ export const CreateSecretImportForm = ({ name="isReplication" control={control} defaultValue={false} - render={({ field }) => ( - - Enable replication to synchronize changes.
Warning: This will overwrite any - existing secrets with the same name. -
+ render={({ field: { value, onChange }, fieldState: { error } }) => ( + + + )} />
diff --git a/frontend/src/views/SecretMainPage/components/SecretImportListView/SecretImportItem.tsx b/frontend/src/views/SecretMainPage/components/SecretImportListView/SecretImportItem.tsx index c78af8ffd..07c66f17c 100644 --- a/frontend/src/views/SecretMainPage/components/SecretImportListView/SecretImportItem.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretImportListView/SecretImportItem.tsx @@ -30,20 +30,17 @@ import { import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; import { useToggle } from "@app/hooks"; import { useResyncSecretReplication } from "@app/hooks/api"; +import { TSecretImport } from "@app/hooks/api/types"; type Props = { onDelete: () => void; environment: string; secretPath?: string; - isReplication?: boolean; - isReplicationSuccess?: boolean; - replicationStatus?: string; - lastReplicated?: string; - importEnvName: string; - importEnvPath: string; + secretImport?: TSecretImport; + isReplicationExpand?: boolean; importedSecrets: { key: string; value: string; overriden: { env: string; secretPath: string } }[]; searchTerm: string; - id: string; + onExpandReplicateSecrets: (id: string) => void; }; // to show the environment and folder icon @@ -70,25 +67,29 @@ export const EnvFolderIcon = ({ export const SecretImportItem = ({ onDelete, - id, - importEnvName, - importEnvPath, - isReplication, + isReplicationExpand, importedSecrets = [], searchTerm = "", secretPath, environment, - isReplicationSuccess, - replicationStatus, - lastReplicated + secretImport, + onExpandReplicateSecrets: onExpandReplicate }: Props) => { + const { + isReserved, + id, + isReplication, + isReplicationSuccess, + replicationStatus, + lastReplicated, + importEnv + } = secretImport as TSecretImport; 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) => secret.key.toUpperCase().includes(searchTerm.toUpperCase()) @@ -134,24 +135,39 @@ export const SecretImportItem = ({ } }; + const handleRowClick = () => { + if (isReplication) { + onExpandReplicate(id); + } else { + setIsExpanded.toggle(); + } + }; + return ( <>
setIsExpanded.toggle()} - onKeyDown={() => setIsExpanded.toggle()} + onClick={handleRowClick} + onKeyDown={(e) => { + if (e.key === "Enter") { + handleRowClick(); + } + }} >
@@ -193,29 +209,31 @@ export const SecretImportItem = ({
)} - - {(isAllowed) => ( - - - - )} - + {isReplication && ( + + {(isAllowed) => ( + + + + )} + + )}
- {!isReplication && isExpanded && !isDragging && ( + {!isReplication && (isReplicationExpand || isExpanded) && !isDragging && ( { overridenSec[el.key] = { env: importSecrets[i].environmentInfo.name, - secretPath: importSecrets[i].secretPath + secretPath: formatReservedPaths(importSecrets[i].secretPath) }; }); } @@ -91,6 +93,8 @@ export const SecretImportListView = ({ "deleteSecretImport" ] as const); + const [replicationSecrets, setReplicationSecrets] = useState>({}); + const sensors = useSensors( useSensor(MouseSensor, {}), useSensor(TouchSensor, {}), @@ -149,6 +153,22 @@ export const SecretImportListView = ({ } }; + const handleOpenReplicationSecrets = (replicationImportId: string) => { + console.log(secretImports); + const reservedImport = secretImports.find( + ({ isReserved, importPath, importEnv }) => + importEnv.slug === environment && + isReserved && + importPath === `/${ReservedFolders.SecretReplication}${replicationImportId}` + ); + if (reservedImport) { + setReplicationSecrets((state) => ({ + ...state, + [reservedImport.id]: !state?.[reservedImport.id] + })); + } + }; + return ( <> {items?.map((item) => { - const { - importPath, - importEnv, - id, - isReplication, - replicationStatus, - lastReplicated, - isReplicationSuccess - } = item; + // TODO(akhilmhdh): change this and pass this whole object instead of one by one return (