This commit is contained in:
Scott Wilson
2025-07-21 10:07:19 -07:00
parent 0dba359f96
commit 1fc217798e
2 changed files with 77 additions and 150 deletions
@@ -475,7 +475,7 @@ const formatDeletedJson = (json: JsonValue): JSX.Element => {
const cleanVersionForComparison = (version: Version): JsonValue => { const cleanVersionForComparison = (version: Version): JsonValue => {
const { id, version: versionNumber, ...cleanVersion } = version; const { id, version: versionNumber, ...cleanVersion } = version;
return cleanVersion; return Object.fromEntries(Object.entries(cleanVersion).filter((entry) => Boolean(entry[1])));
}; };
export const SecretVersionDiffView = ({ export const SecretVersionDiffView = ({
@@ -486,6 +486,7 @@ export const SecretVersionDiffView = ({
customHeader, customHeader,
excludedFieldsHighlight = ["metadata", "tags"] excludedFieldsHighlight = ["metadata", "tags"]
}: SecretVersionDiffViewProps) => { }: SecretVersionDiffViewProps) => {
console.log("item", item);
const oldContainerRef = useRef<HTMLDivElement>(null); const oldContainerRef = useRef<HTMLDivElement>(null);
const newContainerRef = useRef<HTMLDivElement>(null); const newContainerRef = useRef<HTMLDivElement>(null);
const [internalCollapsed, setInternalCollapsed] = useState(isCollapsed); const [internalCollapsed, setInternalCollapsed] = useState(isCollapsed);
@@ -1,20 +1,12 @@
/* eslint-disable jsx-a11y/label-has-associated-control */ /* eslint-disable jsx-a11y/label-has-associated-control */
import React, { useState } from "react"; import React, { useState } from "react";
import { import { faCodeCommit, faEye, faFolder, faKey, faTrash } from "@fortawesome/free-solid-svg-icons";
faChevronDown,
faChevronRight,
faCodeCommit,
faEye,
faFolder,
faKey,
faTrash
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { twMerge } from "tailwind-merge";
import { Badge, Button, IconButton, Input, Modal, ModalContent, Tooltip } from "@app/components/v2"; import { Badge, Button, Input, Modal, ModalContent } from "@app/components/v2";
import { useToggle } from "@app/hooks"; import { useToggle } from "@app/hooks";
import { PendingAction } from "@app/hooks/api/secretFolders/types"; import { PendingAction } from "@app/hooks/api/secretFolders/types";
import { SecretVersionDiffView } from "@app/pages/secret-manager/CommitDetailsPage/components/SecretVersionDiffView";
import { import {
PendingChange, PendingChange,
@@ -178,6 +170,8 @@ const ChangeTable: React.FC<ChangeTableProps> = ({
} }
if (change.type === PendingAction.Update) { if (change.type === PendingAction.Update) {
const { existingSecret } = change;
const hasKeyChange = change.newSecretName && change.secretKey !== change.newSecretName; const hasKeyChange = change.newSecretName && change.secretKey !== change.newSecretName;
const hasValueChange = change.secretValue !== change.originalValue; const hasValueChange = change.secretValue !== change.originalValue;
const hasCommentChange = change.secretComment !== change.originalComment; const hasCommentChange = change.secretComment !== change.originalComment;
@@ -199,85 +193,58 @@ const ChangeTable: React.FC<ChangeTableProps> = ({
if (!hasChanges) return null; if (!hasChanges) return null;
return ( return (
<table className="w-full text-sm"> <SecretVersionDiffView
<tbody> item={{
{hasKeyChange && ( secretKey: change.secretKey,
<ComparisonTableRow isUpdated: true,
label="Key" type: "secret",
previousValue={<span className="font-mono">{change.existingSecret.key}</span>} id: change.id,
newValue={<span className="font-mono">{change.newSecretName}</span>} versions: [
/> {
)} version: 1,
{hasValueChange && ( secretKey: change.newSecretName ? existingSecret.key : undefined,
<ComparisonTableRow secretValue: change.secretValue ? existingSecret.value : undefined,
label="Value" tags: change.tags ? existingSecret.tags : undefined,
previousValue={ secretMetadata: change.secretMetadata ? existingSecret.secretMetadata : undefined,
<div className="max-w-md break-all rounded"> skipMultilineEncoding:
{change.existingSecret.value || ( typeof change.skipMultilineEncoding === "boolean"
<span className="italic text-mineshaft-400">(empty)</span> ? existingSecret.skipMultilineEncoding
)} : undefined,
</div> comment: change.secretComment !== undefined ? existingSecret.comment : undefined
} },
newValue={ {
<div className="max-w-md break-all rounded"> version: 2,
{change.secretValue || ( secretKey: change.newSecretName,
<span className="italic text-mineshaft-400">(empty)</span> secretValue: change.secretValue,
)} tags: change.tags,
</div> secretMetadata: change.secretMetadata,
} skipMultilineEncoding: change.skipMultilineEncoding,
/> comment: change.secretComment
)} }
{hasCommentChange && ( ]
<ComparisonTableRow }}
label="Comment" />
previousValue={
change.existingSecret.comment || (
<span className="italic text-mineshaft-400">(empty)</span>
)
}
newValue={
change.secretComment || <span className="italic text-mineshaft-400">(empty)</span>
}
/>
)}
{hasMultilineChange && (
<ComparisonTableRow
label="Multi-line Encoding"
previousValue={change.existingSecret.skipMultilineEncoding ? "Enabled" : "Disabled"}
newValue={change.skipMultilineEncoding ? "Enabled" : "Disabled"}
/>
)}
{hasTagsChange && (
<ComparisonTableRow
label="Tags"
previousValue={<TagsList tags={change.existingSecret.tags} />}
newValue={<TagsList tags={change.tags} />}
/>
)}
{hasMetadataChange && (
<ComparisonTableRow
label="Metadata"
previousValue={<MetadataList metadata={change.existingSecret.secretMetadata} />}
newValue={<MetadataList metadata={change.secretMetadata} />}
/>
)}
</tbody>
</table>
); );
} }
if (change.type === PendingAction.Delete) { if (change.type === PendingAction.Delete) {
const { secretKey, secretValue } = change;
return ( return (
<table className="w-full text-sm"> <SecretVersionDiffView
<tbody> item={{
<tr className="border-b border-mineshaft-700"> secretKey: change.secretKey,
<td className="w-24 py-3 pl-4 font-medium text-red-400">Key:</td> isDeleted: true,
<td className="px-3 py-3 font-mono text-red-400 line-through" colSpan={2}> type: "secret",
{change.secretKey} id: change.id,
</td> versions: [
</tr> {
</tbody> version: 1,
</table> secretKey,
secretValue
}
]
}}
/>
); );
} }
@@ -382,71 +349,30 @@ const ChangeTable: React.FC<ChangeTableProps> = ({
}); });
}; };
return ( return change.resourceType === "secret" ? renderSecretChanges() : renderFolderChanges();
<div className="overflow-clip rounded-t-none border border-t-0 border-mineshaft-600 bg-mineshaft-800 first:rounded-t-md first:border-t last:rounded-b-md last:border-b">
<div
className={twMerge(
"flex h-12 cursor-pointer items-center border-mineshaft-600 px-3.5 py-2 text-sm text-gray-300",
isOpen && "border-b"
)}
role="button"
tabIndex={0}
onClick={() => setIsOpen.toggle()}
onKeyDown={(e) => {
if (e.key === "Enter") {
setIsOpen.toggle();
}
}}
>
<FontAwesomeIcon className="mr-3 w-4" icon={isOpen ? faChevronDown : faChevronRight} />
<div className="flex flex-1 items-center gap-1.5 text-sm"> // return (
{getChangeName()} // <div className="py-2 shadow-sm">
{getChangeBadge(change.type)} // <div className="flex items-center justify-between">
</div> // <div className="flex items-center gap-3">
<Tooltip content="Discard change"> // <span className="font-medium text-mineshaft-100">{getChangeName()}</span>
<IconButton // {getChangeBadge(change.type)}
ariaLabel="delete-change" // </div>
variant="plain" // <Tooltip content="Discard change">
colorSchema="danger" // <IconButton
size="sm" // ariaLabel="delete-change"
onClick={() => handleDeletePending(change.resourceType, change.id)} // variant="plain"
> // colorSchema="danger"
<FontAwesomeIcon icon={faTrash} /> // size="sm"
</IconButton> // onClick={() => handleDeletePending(change.resourceType, change.id)}
</Tooltip> // >
</div> // <FontAwesomeIcon icon={faTrash} />
// </IconButton>
{isOpen ? ( // </Tooltip>
<div className="overflow-hidden bg-mineshaft-900"> // </div>
{change.resourceType === "secret" ? renderSecretChanges() : renderFolderChanges()} // {change.resourceType === "secret" ? renderSecretChanges() : renderFolderChanges()}
</div> // </div>
) : null} // );
</div>
);
return (
<div className="py-2 shadow-sm">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<span className="font-medium text-mineshaft-100">{getChangeName()}</span>
{getChangeBadge(change.type)}
</div>
<Tooltip content="Discard change">
<IconButton
ariaLabel="delete-change"
variant="plain"
colorSchema="danger"
size="sm"
onClick={() => handleDeletePending(change.resourceType, change.id)}
>
<FontAwesomeIcon icon={faTrash} />
</IconButton>
</Tooltip>
</div>
{change.resourceType === "secret" ? renderSecretChanges() : renderFolderChanges()}
</div>
);
}; };
export const CommitForm: React.FC<CommitFormProps> = ({ export const CommitForm: React.FC<CommitFormProps> = ({