improvements: transitions and minor UI adjustments to secret reference tree

This commit is contained in:
Scott Wilson
2024-10-25 14:23:42 -07:00
parent b9a1629db0
commit 657130eb80
4 changed files with 302 additions and 40 deletions
+213 -14
View File
@@ -26,6 +26,7 @@
"@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-collapsible": "^1.1.1",
"@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-hover-card": "^1.0.7", "@radix-ui/react-hover-card": "^1.0.7",
@@ -4846,6 +4847,37 @@
} }
} }
}, },
"node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collapsible": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.3.tgz",
"integrity": "sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-presence": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.1",
"@radix-ui/react-use-layout-effect": "1.0.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-alert-dialog": { "node_modules/@radix-ui/react-alert-dialog": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.5.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.0.5.tgz",
@@ -4928,25 +4960,25 @@
} }
}, },
"node_modules/@radix-ui/react-collapsible": { "node_modules/@radix-ui/react-collapsible": {
"version": "1.0.3", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.3.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.1.tgz",
"integrity": "sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==", "integrity": "sha512-1///SnrfQHJEofLokyczERxQbWfCGQlQ2XsCZMucVs6it+lq9iw4vXy+uDn1edlb58cOZOWSldnfPAYcT4O/Yg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.13.10", "@radix-ui/primitive": "1.1.0",
"@radix-ui/primitive": "1.0.1", "@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-compose-refs": "1.0.1", "@radix-ui/react-context": "1.1.1",
"@radix-ui/react-context": "1.0.1", "@radix-ui/react-id": "1.1.0",
"@radix-ui/react-id": "1.0.1", "@radix-ui/react-presence": "1.1.1",
"@radix-ui/react-presence": "1.0.1", "@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-primitive": "1.0.3", "@radix-ui/react-use-controllable-state": "1.1.0",
"@radix-ui/react-use-controllable-state": "1.0.1", "@radix-ui/react-use-layout-effect": "1.1.0"
"@radix-ui/react-use-layout-effect": "1.0.1"
}, },
"peerDependencies": { "peerDependencies": {
"@types/react": "*", "@types/react": "*",
"@types/react-dom": "*", "@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0" "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@types/react": { "@types/react": {
@@ -4957,6 +4989,173 @@
} }
} }
}, },
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz",
"integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==",
"license": "MIT"
},
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
"integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-context": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz",
"integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-id": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
"integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-presence": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz",
"integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-primitive": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
"integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-slot": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
"integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
"integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-controllable-state": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
"integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-use-callback-ref": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz",
"integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collection": { "node_modules/@radix-ui/react-collection": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz",
+1
View File
@@ -39,6 +39,7 @@
"@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-collapsible": "^1.1.1",
"@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-hover-card": "^1.0.7", "@radix-ui/react-hover-card": "^1.0.7",
@@ -16,7 +16,7 @@
} }
.tree ul li { .tree ul li {
border-left: 2px solid #ddd; border-left: 2px solid #888;
min-height: 2.5rem; min-height: 2.5rem;
} }
@@ -32,11 +32,21 @@
left: -2px; left: -2px;
width: calc(var(--spacing) + 2px); width: calc(var(--spacing) + 2px);
height: calc(var(--spacing) + 13px); height: calc(var(--spacing) + 13px);
border: solid #ddd; border: solid #888;
border-radius: 0 0 0 8px;
border-width: 0 0 2px 2px; border-width: 0 0 2px 2px;
transition: all 200ms linear; transition: all 200ms linear;
} }
.details[open] summary ~ * {
animation: sweep .5s ease-in-out;
}
@keyframes sweep {
0% {opacity: 0; margin-left: -10px}
100% {opacity: 1; margin-left: 0px}
}
.tree summary { .tree summary {
display: block; display: block;
cursor: pointer; cursor: pointer;
@@ -77,3 +87,41 @@
.tree details[open] > summary::before { .tree details[open] > summary::before {
background-position: calc(-2 * var(--radius)) 0; background-position: calc(-2 * var(--radius)) 0;
} }
.collapsibleContent {
/*overflow-y: hidden;*/
}
.collapsibleContent[data-state="open"] {
animation: slideDown 300ms ease-out;
}
.collapsibleContent[data-state="closed"] {
animation: slideUp 300ms ease-out;
}
@keyframes slideDown {
0% {
height: 0;
opacity: 0;
}
50% {
opacity: 0;
}
100% {
height: var(--radix-collapsible-content-height);
opacity: 1;
}
}
@keyframes slideUp {
0% {
height: var(--radix-collapsible-content-height);
opacity: 1;
}
50% {
opacity: 0;
}
100% {
height: 0;
opacity: 0;
}
}
@@ -1,10 +1,11 @@
import { faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; import { useState } from "react";
import { faChevronRight, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as Collapsible from "@radix-ui/react-collapsible";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { FormControl, FormLabel, SecretInput, Spinner, Tooltip } from "@app/components/v2"; import { FormControl, FormLabel, SecretInput, Spinner, Tooltip } from "@app/components/v2";
import { useWorkspace } from "@app/context"; import { useWorkspace } from "@app/context";
import { useToggle } from "@app/hooks";
import { useGetSecretReferenceTree } from "@app/hooks/api"; import { useGetSecretReferenceTree } from "@app/hooks/api";
import { TSecretReferenceTraceNode } from "@app/hooks/api/types"; import { TSecretReferenceTraceNode } from "@app/hooks/api/types";
@@ -29,18 +30,26 @@ export const SecretReferenceNode = ({
isRoot?: boolean; isRoot?: boolean;
secretKey?: string; secretKey?: string;
}) => { }) => {
const [isOpen, setIsOpen] = useToggle(); const [isOpen, setIsOpen] = useState(false);
const hasChildren = node.children.length > 0;
return ( return (
<li> <li>
<details <Collapsible.Root open={isOpen} className="" onOpenChange={setIsOpen}>
open={isOpen} <Collapsible.Trigger
onToggle={(el) => { className={twMerge(
el.preventDefault(); hasChildren && " decoration-bunker-4ø00 underline-offset-4 data-[state=open]:underline",
el.stopPropagation(); "[&>svg]:data-[state=open]:rotate-[90deg] [&>svg]:data-[state=open]:text-yellow-500"
setIsOpen.toggle(); )}
}} disabled={!hasChildren}
> >
<summary className={twMerge(node.children.length > 0 && !isOpen && "text-primary")}> {hasChildren && (
<FontAwesomeIcon
icon={faChevronRight}
className=" d mr-2 text-mineshaft-400 transition-transform duration-300 ease-linear"
aria-hidden
/>
)}
{isRoot {isRoot
? secretKey ? secretKey
: `${node.environment}${ : `${node.environment}${
@@ -48,20 +57,25 @@ export const SecretReferenceNode = ({
}.${node.key}`} }.${node.key}`}
<Tooltip className="max-w-md break-words" content={node.value}> <Tooltip className="max-w-md break-words" content={node.value}>
<span <span
className={twMerge("ml-1 px-1 text-xs text-gray-400", !node.value && "text-red-400")} className={twMerge(
"ml-1 px-1 text-xs text-mineshaft-400",
!node.value && "text-red-400"
)}
> >
<FontAwesomeIcon icon={node.value ? faEye : faEyeSlash} /> <FontAwesomeIcon icon={node.value ? faEye : faEyeSlash} />
</span> </span>
</Tooltip> </Tooltip>
</summary> </Collapsible.Trigger>
{node.children.length > 0 && ( <Collapsible.Content className={twMerge("mt-4", style.collapsibleContent)}>
<ul> {hasChildren && (
{node.children.map((el, index) => ( <ul>
<SecretReferenceNode node={el} key={`${el.key}-${index + 1}`} /> {node.children.map((el, index) => (
))} <SecretReferenceNode node={el} key={`${el.key}-${index + 1}`} />
</ul> ))}
)} </ul>
</details> )}
</Collapsible.Content>
</Collapsible.Root>
</li> </li>
); );
}; };
@@ -95,11 +109,11 @@ export const SecretReferenceTree = ({ secretPath, environment, secretKey }: Prop
key="value-overriden" key="value-overriden"
isReadOnly isReadOnly
value={secretValue} value={secretValue}
containerClassName="text-bunker-300 hover:border-primary-400/50 border border-mineshaft-600 bg-bunker-800 px-2 py-1.5" containerClassName="text-bunker-300 hover:border-primary-400/50 border border-mineshaft-600 bg-bunker-700 px-2 py-1.5"
/> />
</FormControl> </FormControl>
<FormLabel className="mb-2" label="Reference Tree" /> <FormLabel className="mb-2" label="Reference Tree" />
<div className="relative max-h-96 overflow-auto rounded bg-bunker-700 py-2 pt-6 text-sm"> <div className="thin-scrollbar relative max-h-96 overflow-auto rounded-md border border-mineshaft-600 bg-bunker-700 py-6 text-sm text-mineshaft-200">
{tree && ( {tree && (
<ul className={style.tree}> <ul className={style.tree}>
<SecretReferenceNode node={tree} isRoot secretKey={secretKey} /> <SecretReferenceNode node={tree} isRoot secretKey={secretKey} />