feat: improve UX with drawer detail view and proper settings placement

Major UX improvements:
- Changed detail view from full page to drawer (slides from right)
- Moved plugin settings from sidebar to Settings → Plugins (proper pattern)
- Fixed React error #310 by adding defensive String() wrappers
- Fixed syncMessage getter to always return string
- Added safety checks for encryptedData access
- Added error handling for useGet failures

The drawer approach keeps the list visible while viewing details,
matching Headlamp's design patterns. Settings are now properly
located in the global Settings → Plugins section instead of
cluttering the plugin's sidebar navigation.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
2026-02-12 21:40:40 -05:00
parent 905283f134
commit b08df4fb76
6 changed files with 157 additions and 94 deletions
@@ -101,7 +101,9 @@ export class SealedSecret extends KubeObject<SealedSecretInterface> {
if (!condition) {
return 'Unknown';
}
return condition.message || condition.reason || condition.status;
// Ensure we always return a string, not an object
const message = condition.message || condition.reason || condition.status;
return String(message || 'Unknown');
}
/**
@@ -120,21 +122,11 @@ export class SealedSecret extends KubeObject<SealedSecretInterface> {
}
const result = await tryCatchAsync(async () => {
// Query the CRD to get available versions
const response = await fetch(
// Query the CRD to get available versions using Headlamp's API proxy
const crd = await ApiProxy.request(
'/apis/apiextensions.k8s.io/v1/customresourcedefinitions/sealedsecrets.bitnami.com'
);
if (!response.ok) {
if (response.status === 404) {
throw new Error('SealedSecrets CRD not found. Please install Sealed Secrets on the cluster.');
}
const errorText = await response.text().catch(() => response.statusText);
throw new Error(`Failed to fetch CRD (${response.status} ${response.statusText}): ${errorText}`);
}
const crd = await response.json();
// Find the storage version (the version used for persistence)
const storageVersion = crd.spec?.versions?.find((v: any) => v.storage === true);