diff --git a/backend/src/ee/services/license/license-fns.ts b/backend/src/ee/services/license/license-fns.ts index 5b755567b..3df2ad942 100644 --- a/backend/src/ee/services/license/license-fns.ts +++ b/backend/src/ee/services/license/license-fns.ts @@ -20,7 +20,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({ identitiesUsed: 0, dynamicSecret: false, secretVersioning: true, - pitRecovery: false, + pitRecovery: true, ipAllowlisting: false, rbac: false, githubOrgSync: false, @@ -40,7 +40,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({ status: null, trial_end: null, has_used_trial: true, - secretApproval: false, + secretApproval: true, secretRotation: false, caCrl: false, instanceUserManagement: false, diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx index 430ec8492..7fd050b03 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChangeItem.tsx @@ -156,11 +156,11 @@ export const SecretApprovalRequestChangeItem = ({
Tags
-
+
{(secretVersion?.tags?.length ?? 0) ? ( secretVersion?.tags?.map(({ slug, id: tagId, color }) => (
if (change.type === PendingAction.Create && existingFolder) { createNotification({ - text: "Another folder with same name already exists", + text: "A folder with this name already exists", type: "error" }); return { pendingChanges: newChanges }; @@ -302,7 +302,7 @@ const createBatchModeStore: StateCreator existingFolder ) { createNotification({ - text: "Another folder with same name already exists", + text: "A folder with this name already exists", type: "error" }); return { pendingChanges: newChanges }; @@ -322,7 +322,7 @@ const createBatchModeStore: StateCreator if (change.type === PendingAction.Create && existingSecret) { createNotification({ - text: "Another secret with same name already exists", + text: "A secret with this name already exists", type: "error" }); return { pendingChanges: newChanges }; @@ -343,7 +343,7 @@ const createBatchModeStore: StateCreator if (existingNewSecretName) { createNotification({ - text: "Another secret with same name already exists", + text: "A secret with this name already exists", type: "error" }); return { pendingChanges: newChanges }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx index f65b2dd10..f3fef4fd9 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx @@ -1,9 +1,19 @@ /* eslint-disable jsx-a11y/label-has-associated-control */ import React, { useState } from "react"; -import { faCodeCommit, faEye, faFolder, faKey, faTrash } from "@fortawesome/free-solid-svg-icons"; +import { + faChevronDown, + faChevronRight, + faCodeCommit, + faEye, + faFolder, + faKey, + faTrash +} from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { twMerge } from "tailwind-merge"; import { Badge, Button, IconButton, Input, Modal, ModalContent, Tooltip } from "@app/components/v2"; +import { useToggle } from "@app/hooks"; import { PendingAction } from "@app/hooks/api/secretFolders/types"; import { @@ -39,7 +49,7 @@ const TagsList: React.FC<{ tags?: { id: string; slug: string }[]; className?: st return (
{tags.map((tag) => ( - + {tag.slug} ))} @@ -79,12 +89,14 @@ const ComparisonTableRow: React.FC<{ return ( - {label}: - + + {label} + +
{previousValue}
-
{newValue}
+
{newValue}
); @@ -96,6 +108,8 @@ const ChangeTable: React.FC = ({ workspaceId, secretPath }) => { + const [isOpen, setIsOpen] = useToggle(true); + const getChangeBadge = (type: PendingChange["type"]) => { switch (type) { case PendingAction.Create: @@ -114,7 +128,7 @@ const ChangeTable: React.FC = ({ if (change.type === PendingAction.Create) { return ( -
+
@@ -185,83 +199,85 @@ const ChangeTable: React.FC = ({ if (!hasChanges) return null; return ( -
-
- - {hasKeyChange && ( - {change.existingSecret.key}} - newValue={{change.newSecretName}} - /> - )} - {hasValueChange && ( - - {change.existingSecret.value || (empty)} - - } - newValue={ -
- {change.secretValue || (empty)} -
- } - /> - )} - {hasCommentChange && ( - (empty) - } - newValue={change.secretComment || (empty)} - /> - )} - {hasMultilineChange && ( - - )} - {hasTagsChange && ( - } - newValue={} - /> - )} - {hasMetadataChange && ( - } - newValue={} - /> - )} -
-
-
+ + + {hasKeyChange && ( + {change.existingSecret.key}} + newValue={{change.newSecretName}} + /> + )} + {hasValueChange && ( + + {change.existingSecret.value || ( + (empty) + )} + + } + newValue={ +
+ {change.secretValue || ( + (empty) + )} +
+ } + /> + )} + {hasCommentChange && ( + (empty) + ) + } + newValue={ + change.secretComment || (empty) + } + /> + )} + {hasMultilineChange && ( + + )} + {hasTagsChange && ( + } + newValue={} + /> + )} + {hasMetadataChange && ( + } + newValue={} + /> + )} +
+
); } if (change.type === PendingAction.Delete) { return ( -
- - - - - - - -
Key: - {change.secretKey} -
-
+ + + + + + + +
Key: + {change.secretKey} +
); } @@ -273,26 +289,24 @@ const ChangeTable: React.FC = ({ if (change.type === PendingAction.Create) { return ( -
- - - - - +
Name: - {change.folderName} + + + + + + + {change.description !== undefined && change.description !== "" && ( + + + - {change.description !== undefined && change.description !== "" && ( - - - - - )} - -
Name: + {change.folderName} +
Description: + {change.description}
Description: - {change.description} -
- + )} +
); } @@ -305,45 +319,41 @@ const ChangeTable: React.FC = ({ if (!hasChanges) return null; return ( -
- - - {hasNameChange && ( - {change.originalFolderName}} - newValue={{change.folderName}} - /> - )} - {hasDescriptionChange && ( - (empty) - } - newValue={change.description || (empty)} - /> - )} - -
-
+ + + {hasNameChange && ( + {change.originalFolderName}} + newValue={{change.folderName}} + /> + )} + {hasDescriptionChange && ( + (empty) + } + newValue={change.description || (empty)} + /> + )} + +
); } if (change.type === PendingAction.Delete) { return ( -
- - - - - - - -
Name: - {change.folderName} -
-
+ + + + + + + +
Name: + {change.folderName} +
); } @@ -372,6 +382,49 @@ const ChangeTable: React.FC = ({ }); }; + return ( +
+
setIsOpen.toggle()} + onKeyDown={(e) => { + if (e.key === "Enter") { + setIsOpen.toggle(); + } + }} + > + + +
+ {getChangeName()} + {getChangeBadge(change.type)} +
+ + handleDeletePending(change.resourceType, change.id)} + > + + + +
+ + {isOpen ? ( +
+ {change.resourceType === "secret" ? renderSecretChanges() : renderFolderChanges()} +
+ ) : null} +
+ ); + return (
@@ -432,32 +485,35 @@ export const CommitForm: React.FC = ({ {/* Floating Panel */} {!isModalOpen && (
-
+
- - Ready to Commit + + Pending Changes
- {totalChangesCount} change{totalChangesCount !== 1 ? "s" : ""} + {totalChangesCount} Change{totalChangesCount !== 1 ? "s" : ""}
-
+
@@ -470,23 +526,20 @@ export const CommitForm: React.FC = ({ - + Commit Changes - - {totalChangesCount} change{totalChangesCount !== 1 ? "s" : ""} + + {totalChangesCount} Change{totalChangesCount !== 1 ? "s" : ""}
} + subTitle={"Write a commit message and review the changes you're about to commit."} className="max-h-[90vh] max-w-5xl" >
-

- Write a commit message and review the changes you're about to commit. -

- {/* Changes List */}
-
+
{/* Folder Changes */} {pendingChanges.folders.length > 0 && (
@@ -494,7 +547,7 @@ export const CommitForm: React.FC = ({ Folders ({pendingChanges.folders.length}) -
+
{pendingChanges.folders.map((change) => ( = ({ {/* Secret Changes */} {pendingChanges.secrets.length > 0 && (
-

- +

+ Secrets ({pendingChanges.secrets.length})

-
+
{pendingChanges.secrets.map((change) => ( = ({
{/* Action Buttons */} -
+
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretDetailSidebar.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretDetailSidebar.tsx index 6e501a06d..142bd3216 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretDetailSidebar.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretDetailSidebar.tsx @@ -1088,7 +1088,7 @@ export const SecretDetailSidebar = ({ isDisabled={isSubmitting || !isDirty || !isAllowed} isLoading={isSubmitting} > - Save Changes + Apply Changes )} diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx index 614e1d35e..f55479593 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/SecretItem.tsx @@ -38,7 +38,7 @@ import { WsTag } from "@app/hooks/api/types"; import { subject } from "@casl/ability"; import { zodResolver } from "@hookform/resolvers/zod"; import { AnimatePresence, motion } from "framer-motion"; -import { memo, useEffect, useRef, useCallback } from "react"; +import { memo, useCallback, useEffect, useRef } from "react"; import { Controller, useFieldArray, useForm } from "react-hook-form"; import { twMerge } from "tailwind-merge"; import { @@ -799,7 +799,7 @@ export const SecretItem = memo( isPending ? ( )}