From 9591d8e04d09147d7597a2a27e56cd560ea3d607 Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Thu, 3 Oct 2024 14:10:36 +0800 Subject: [PATCH] added some info hover cards. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • found this this is probably the wrong direction • will create a new page for next iteration. --- .../JwtSecrets/AlgorithmHoverCard.tsx | 22 ++ .../JwtSecrets/JWTSecretKeysTable.tsx | 374 ++++++++++++------ .../interfaces/JwtSecrets/algorithmDetails.ts | 81 ++++ apps/studio/components/ui/InfoPill.tsx | 61 +++ 4 files changed, 423 insertions(+), 115 deletions(-) create mode 100644 apps/studio/components/interfaces/JwtSecrets/AlgorithmHoverCard.tsx create mode 100644 apps/studio/components/interfaces/JwtSecrets/algorithmDetails.ts create mode 100644 apps/studio/components/ui/InfoPill.tsx diff --git a/apps/studio/components/interfaces/JwtSecrets/AlgorithmHoverCard.tsx b/apps/studio/components/interfaces/JwtSecrets/AlgorithmHoverCard.tsx new file mode 100644 index 00000000000..73d80e7d8f8 --- /dev/null +++ b/apps/studio/components/interfaces/JwtSecrets/AlgorithmHoverCard.tsx @@ -0,0 +1,22 @@ +import React from 'react' +import { GlobeLock } from 'lucide-react' +import { algorithmDetails, AlgorithmDetail } from './algorithmDetails' +import { InfoPill } from '../../ui/InfoPill' + +interface AlgorithmHoverCardProps { + algorithm: keyof typeof algorithmDetails +} + +export const AlgorithmHoverCard: React.FC = ({ algorithm }) => { + const details: AlgorithmDetail = algorithmDetails[algorithm] + + return ( + } + title={details.name} + description={details.description} + links={details.links} + /> + ) +} diff --git a/apps/studio/components/interfaces/JwtSecrets/JWTSecretKeysTable.tsx b/apps/studio/components/interfaces/JwtSecrets/JWTSecretKeysTable.tsx index b65e5f9d17b..c699b557011 100644 --- a/apps/studio/components/interfaces/JwtSecrets/JWTSecretKeysTable.tsx +++ b/apps/studio/components/interfaces/JwtSecrets/JWTSecretKeysTable.tsx @@ -29,6 +29,8 @@ import { DialogTrigger, DialogFooter, DialogDescription, + DialogSection, + DialogSectionSeparator, } from 'ui/src/components/shadcn/ui/dialog' import { Select, @@ -54,10 +56,20 @@ import { Eye, ArrowUpCircle, Key, + Fingerprint, + GlobeLock, + ExternalLink, } from 'lucide-react' import { motion, AnimatePresence } from 'framer-motion' import { toast } from 'sonner' import { cn } from 'ui' +import { + HoverCard, + HoverCardContent, + HoverCardTrigger, +} from 'ui/src/components/shadcn/ui/hover-card' +import { algorithmDetails } from './algorithmDetails' +import { AlgorithmHoverCard } from './AlgorithmHoverCard' type KeyStatus = 'STANDBY' | 'IN_USE' | 'PREVIOUSLY_USED' type JWTAlgorithm = 'HS256' | 'RS256' | 'ES256' @@ -80,21 +92,12 @@ const statusLabels: Record = { } const statusColors: Record = { - STANDBY: 'text-xs font-mono uppercase bg-warning bg-opacity-100 text-warning-200 border-warning', - IN_USE: 'text-xs font-mono uppercase bg-brand bg-opacity-100 text-brand-200 border-brand', - PREVIOUSLY_USED: 'text-xs font-mono uppercase bg-alternative text-gray-800', -} - -const algorithmLabels: Record = { - HS256: 'HS256 (Symmetric)', - RS256: 'RS256 (RSA)', - ES256: 'ES256 (ECC)', -} - -const algorithmDescriptions: Record = { - HS256: 'HMAC with SHA-256: Fast, simple, requires secure key exchange', - RS256: 'RSA with SHA-256: Allows public key distribution, slower', - ES256: 'ECDSA with SHA-256: Compact keys, fast, modern alternative to RSA', + STANDBY: + 'text-xs leading-normal px-1.5 font-mono py-0 uppercase bg-warning bg-opacity-100 text-warning-200 border-warning', + IN_USE: + 'text-xs leading-normal px-1.5 font-mono py-0 uppercase bg-brand bg-opacity-100 text-brand-200 border-brand', + PREVIOUSLY_USED: + 'text-xs leading-normal px-1.5 font-mono py-0 uppercase bg-alternative text-gray-800', } const initialKeys: SecretKey[] = [ @@ -337,6 +340,138 @@ const ApiKeySection: React.FC<{ inUseKey: SecretKey | undefined }> = ({ inUseKey ) } +const StandbyKeyIllustration = () => ( + + + + + + + + + + + + + + + + + + + + + +) + export function JWTSecretKeysTable() { const [secretKeys, setSecretKeys] = useAtom(secretKeysAtom) const [selectedKey, setSelectedKey] = useState(null) @@ -500,29 +635,21 @@ NEW_STANDBY_KEY_CONTENT setReplacementKeyId(null) } - const MotionTableRow = motion(TableRow) - const renderKeyRow = (key: SecretKey) => ( - - - {statusLabels[key.status]} + + {statusLabels[key.status]} {key.keyId} {key.createdAt} - {algorithmLabels[key.algorithm]} + + + @@ -589,13 +716,13 @@ NEW_STANDBY_KEY_CONTENT - + ) return ( <>
-
+ {/*
-
+
*/}
- - - - - Status - - - Key ID - - - Created At - - - Type - - - Actions - - - - - {activeKeys.map(renderKeyRow)} - -
+ + + + + + Status + + + Key ID + + + Created At + + + Type + + + Actions + + + + {activeKeys.map(renderKeyRow)} +
+
+ +
+
+ +
+
+

Standby JWT signing key

+

+ Create Standby keys ahead of time which can then be promoted to 'In use' at any + time. +

+ +
+
+
{previouslyUsedKeys.length > 0 && ( @@ -697,67 +841,67 @@ NEW_STANDBY_KEY_CONTENT Create a new JWT Key -
-
- - -

- {algorithmDescriptions[newKeyAlgorithm]} -

-
-
- - setNewKeyDescription(e.target.value)} - placeholder="Enter key description" - /> -
-
- setUseCustomSigningKey(checked as boolean)} - /> - -
- {useCustomSigningKey && ( + + +
- -