/** * SealedSecrets List View * * Displays all SealedSecrets in the cluster with filtering and navigation */ import { Link } from '@kinvolk/headlamp-plugin/lib/CommonComponents'; import { SectionBox, SectionFilterHeader, SimpleTable, StatusLabel, } from '@kinvolk/headlamp-plugin/lib/CommonComponents'; import { Box, Button } from '@mui/material'; import React from 'react'; import { useParams } from 'react-router-dom'; import { usePermission } from '../hooks/usePermissions'; import { SealedSecret } from '../lib/SealedSecretCRD'; import { SealedSecretScope } from '../types'; import { EncryptDialog } from './EncryptDialog'; import { SealedSecretListSkeleton } from './LoadingSkeletons'; import { SealedSecretDetail } from './SealedSecretDetail'; import { VersionWarning } from './VersionWarning'; /** * Format scope for display */ function formatScope(scope: SealedSecretScope): string { switch (scope) { case 'strict': return 'Strict'; case 'namespace-wide': return 'Namespace-wide'; case 'cluster-wide': return 'Cluster-wide'; default: return scope; } } /** * SealedSecrets list view component */ export function SealedSecretList() { const { namespace, name } = useParams<{ namespace?: string; name?: string }>(); const [sealedSecrets, error, loading] = SealedSecret.useList(); const [createDialogOpen, setCreateDialogOpen] = React.useState(false); const { allowed: canCreate } = usePermission(undefined, 'canCreate'); // Memoize callbacks to prevent re-renders const handleOpenDialog = React.useCallback(() => { setCreateDialogOpen(true); }, []); const handleCloseDialog = React.useCallback(() => { setCreateDialogOpen(false); }, []); // Memoize column definitions (stable reference for table) const columns = React.useMemo( () => [ { label: 'Name', getter: (ss: SealedSecret) => ( {ss.metadata.name} ), }, { label: 'Namespace', getter: (ss: SealedSecret) => ss.metadata.namespace, }, { label: 'Encrypted Keys', getter: (ss: SealedSecret) => ss.encryptedKeysCount, }, { label: 'Scope', getter: (ss: SealedSecret) => formatScope(ss.scope), }, { label: 'Sync Status', getter: (ss: SealedSecret) => ( {ss.isSynced ? 'Synced' : 'Not Synced'} ), }, { label: 'Age', getter: (ss: SealedSecret) => ss.getAge(), }, ], [] ); // Memoize actions array (stable reference) const actions = React.useMemo( () => canCreate ? [ , ] : [], [canCreate, handleOpenDialog] ); // Show loading skeleton while data is being fetched if (loading) { return ( ); } // Show error if CRD is not installed if (error) { return ( Error {error.message.includes('404') ? ( <>

Sealed Secrets CRD not found. Please ensure Sealed Secrets is installed on your cluster.

Install with:{' '} kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml

) : (

Failed to load Sealed Secrets: {error.message}

)}
); } return ( <> {namespace && name && } ); }