mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 00:52:09 +00:00
feat: renamed old frontend and fixed some minor bugs
This commit is contained in:
+133
@@ -0,0 +1,133 @@
|
||||
/* credits: https://iamkate.com/code/tree-views/ */
|
||||
.tree {
|
||||
--spacing: 1.5rem;
|
||||
--radius: 4px;
|
||||
}
|
||||
|
||||
.tree li {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-left: calc(2 * var(--spacing) - var(--radius) - 2px);
|
||||
}
|
||||
|
||||
.tree ul {
|
||||
margin-left: calc(var(--radius) - var(--spacing));
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.tree ul li {
|
||||
border-left: 2px solid #888;
|
||||
min-height: 2.5rem;
|
||||
}
|
||||
|
||||
.tree ul li:last-child {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.tree ul li::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: calc(var(--spacing) / -1);
|
||||
left: -2px;
|
||||
width: calc(var(--spacing) + 2px);
|
||||
height: calc(var(--spacing) + 13px);
|
||||
border: solid #888;
|
||||
border-radius: 0 0 0 8px;
|
||||
border-width: 0 0 2px 2px;
|
||||
transition: all 200ms linear;
|
||||
}
|
||||
|
||||
.details[open] summary ~ * {
|
||||
animation: sweep 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes sweep {
|
||||
0% {
|
||||
opacity: 0;
|
||||
margin-left: -10px;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
margin-left: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.tree summary {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
min-height: 2.5rem;
|
||||
}
|
||||
|
||||
.tree summary::marker,
|
||||
.tree summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tree summary:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.tree summary:focus-visible {
|
||||
outline: 1px dotted #000;
|
||||
}
|
||||
|
||||
.tree li::after,
|
||||
.tree summary::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: calc(var(--spacing) / 2 - var(--radius));
|
||||
left: calc(var(--spacing) - var(--radius) - 1px);
|
||||
width: calc(2 * var(--radius));
|
||||
height: calc(2 * var(--radius));
|
||||
border-radius: 50%;
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
.tree summary::before {
|
||||
z-index: 1;
|
||||
background: #ddd 0 0;
|
||||
}
|
||||
|
||||
.tree details[open] > summary::before {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import { useState } from "react";
|
||||
import { faChevronRight, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import * as Collapsible from "@radix-ui/react-collapsible";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { FormControl, FormLabel, SecretInput, Spinner, Tooltip } from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { useGetSecretReferenceTree } from "@app/hooks/api";
|
||||
import { TSecretReferenceTraceNode } from "@app/hooks/api/types";
|
||||
|
||||
import style from "./SecretReferenceDetails.module.css";
|
||||
|
||||
type Props = {
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
secretKey: string;
|
||||
};
|
||||
|
||||
const INTERPOLATION_SYNTAX_REG = /\${([^}]+)}/;
|
||||
export const hasSecretReference = (value: string | undefined) =>
|
||||
value ? INTERPOLATION_SYNTAX_REG.test(value) : false;
|
||||
|
||||
export const SecretReferenceNode = ({
|
||||
node,
|
||||
isRoot,
|
||||
secretKey
|
||||
}: {
|
||||
node: TSecretReferenceTraceNode;
|
||||
isRoot?: boolean;
|
||||
secretKey?: string;
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const hasChildren = node.children.length > 0;
|
||||
|
||||
return (
|
||||
<li>
|
||||
<Collapsible.Root open={isOpen} className="" onOpenChange={setIsOpen}>
|
||||
<Collapsible.Trigger
|
||||
className={twMerge(
|
||||
hasChildren && "decoration-bunker-4ø00 underline-offset-4 data-[state=open]:underline",
|
||||
"[&>svg]:data-[state=open]:rotate-[90deg] [&>svg]:data-[state=open]:text-yellow-500"
|
||||
)}
|
||||
disabled={!hasChildren}
|
||||
>
|
||||
{hasChildren && (
|
||||
<FontAwesomeIcon
|
||||
icon={faChevronRight}
|
||||
className="d mr-2 text-mineshaft-400 transition-transform duration-300 ease-linear"
|
||||
aria-hidden
|
||||
/>
|
||||
)}
|
||||
{isRoot
|
||||
? secretKey
|
||||
: `${node.environment}${
|
||||
node.secretPath === "/" ? "" : node.secretPath.split("/").join(".")
|
||||
}.${node.key}`}
|
||||
<Tooltip className="max-w-md break-words" content={node.value}>
|
||||
<span
|
||||
className={twMerge(
|
||||
"ml-1 px-1 text-xs text-mineshaft-400",
|
||||
!node.value && "text-red-400"
|
||||
)}
|
||||
>
|
||||
<FontAwesomeIcon icon={node.value ? faEye : faEyeSlash} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content className={twMerge("mt-4", style.collapsibleContent)}>
|
||||
{hasChildren && (
|
||||
<ul>
|
||||
{node.children.map((el, index) => (
|
||||
<SecretReferenceNode node={el} key={`${el.key}-${index + 1}`} />
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</Collapsible.Content>
|
||||
</Collapsible.Root>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export const SecretReferenceTree = ({ secretPath, environment, secretKey }: Props) => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const projectId = currentWorkspace?.id || "";
|
||||
|
||||
const { data, isPending } = useGetSecretReferenceTree({
|
||||
secretPath,
|
||||
environmentSlug: environment,
|
||||
projectId,
|
||||
secretKey
|
||||
});
|
||||
|
||||
const tree = data?.tree;
|
||||
const secretValue = data?.value;
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="flex items-center justify-center py-4">
|
||||
<Spinner size="xs" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FormControl label="Expanded value">
|
||||
<SecretInput
|
||||
key="value-overriden"
|
||||
isReadOnly
|
||||
value={secretValue}
|
||||
containerClassName="text-bunker-300 hover:border-primary-400/50 border border-mineshaft-600 bg-bunker-700 px-2 py-1.5"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="mb-2" label="Reference Tree" />
|
||||
<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 && (
|
||||
<ul className={style.tree}>
|
||||
<SecretReferenceNode node={tree} isRoot secretKey={secretKey} />
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-2 text-sm text-mineshaft-400">
|
||||
Click a secret key to view its sub-references.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { hasSecretReference, SecretReferenceTree } from "./SecretReferenceDetails";
|
||||
Reference in New Issue
Block a user