chore: move source to repo root and standardize config

Phase 1 — Structural overhaul:
- Move all source from headlamp-sealed-secrets/ subdirectory to repo root
- Delete 23 AI-generated docs, 8 pre-built tarballs, release snapshots dir
- Remove all working-directory refs from CI/release workflows
- Update install-plugin.sh and typedoc.json paths

Phase 2 — Config standardization:
- Create .eslintrc.js and .prettierrc.js (standard Headlamp configs)
- Remove inline eslintConfig/prettier from package.json (drop jsx-a11y, prettier extends)
- Rewrite tsconfig.json (package name extend, add compilerOptions.types)
- Create vitest.config.mts and vitest.setup.ts (standard from polaris)
- Replace headlamp-plugin CLI scripts with direct tool invocation
- Rewrite .gitignore with standard baseline

Phase 3 — MCP & Claude settings:
- Create .mcp.json with github/kubernetes/flux/playwright servers
- Create .claude/settings.local.json
- Remove 7 specialized agents, keep 3 meta-orchestration agents

Phase 4 — Documentation:
- Rewrite CLAUDE.md (remove subdirectory refs, standard format)
- Add ArtifactHub badge, Architecture section, standardized install methods to README.md
- Create CONTRIBUTING.md and SECURITY.md
- Fix pre-existing test bugs in validators.test.ts (isValidNamespace returns boolean,
  not ValidationResult; error message string mismatches)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
DevContainer User
2026-03-03 21:31:12 +00:00
parent 604fe06f9c
commit af95c3795c
108 changed files with 704 additions and 14041 deletions
+169
View File
@@ -0,0 +1,169 @@
/**
* 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) => (
<Link
routeName="sealedsecret"
params={{
namespace: ss.metadata.namespace,
name: ss.metadata.name,
}}
>
{ss.metadata.name}
</Link>
),
},
{
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) => (
<StatusLabel status={ss.isSynced ? 'success' : 'error'}>
{ss.isSynced ? 'Synced' : 'Not Synced'}
</StatusLabel>
),
},
{
label: 'Age',
getter: (ss: SealedSecret) => ss.getAge(),
},
],
[]
);
// Memoize actions array (stable reference)
const actions = React.useMemo(
() =>
canCreate
? [
<Button key="create" variant="contained" color="primary" onClick={handleOpenDialog}>
Create Sealed Secret
</Button>,
]
: [],
[canCreate, handleOpenDialog]
);
// Show loading skeleton while data is being fetched
if (loading) {
return (
<SectionBox title="Sealed Secrets">
<SealedSecretListSkeleton />
</SectionBox>
);
}
// Show error if CRD is not installed
if (error) {
return (
<SectionBox
title="Sealed Secrets"
>
<Box p={2}>
<StatusLabel status="error">Error</StatusLabel>
<Box mt={2}>
{error.message.includes('404') ? (
<>
<p>
Sealed Secrets CRD not found. Please ensure Sealed Secrets is installed on your
cluster.
</p>
<p>
Install with: <code>kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml</code>
</p>
</>
) : (
<p>Failed to load Sealed Secrets: {error.message}</p>
)}
</Box>
</Box>
</SectionBox>
);
}
return (
<>
<SectionBox
title="Sealed Secrets"
>
<VersionWarning autoDetect showDetails={false} />
<SectionFilterHeader title="" noNamespaceFilter={false} actions={actions} />
<SimpleTable data={sealedSecrets} columns={columns} />
</SectionBox>
<EncryptDialog open={createDialogOpen} onClose={handleCloseDialog} />
{namespace && name && <SealedSecretDetail />}
</>
);
}