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
@@ -35,6 +35,10 @@ abstract class BaseErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoun
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
console.error('Error caught by boundary:', error, errorInfo);
console.error('Error type:', typeof error);
console.error('Error keys:', Object.keys(error));
console.error('Error message:', error.message);
console.error('Error toString:', String(error));
this.setState({ errorInfo });
}
@@ -95,7 +99,14 @@ export class CryptoErrorBoundary extends BaseErrorBoundary {
variant="body2"
sx={{ mt: 2, fontFamily: 'monospace', fontSize: '0.875rem' }}
>
Error: {this.state.error.message}
{(() => {
try {
const msg = this.state.error.message || this.state.error.toString();
return `Error: ${String(msg)}`;
} catch (e) {
return 'Error: [Unable to display error message]';
}
})()}
</Typography>
)}
</Alert>
@@ -143,7 +154,14 @@ export class ApiErrorBoundary extends BaseErrorBoundary {
variant="body2"
sx={{ mt: 2, fontFamily: 'monospace', fontSize: '0.875rem' }}
>
Error: {this.state.error.message}
{(() => {
try {
const msg = this.state.error.message || this.state.error.toString();
return `Error: ${String(msg)}`;
} catch (e) {
return 'Error: [Unable to display error message]';
}
})()}
</Typography>
)}
</Alert>
@@ -182,7 +200,14 @@ export class GenericErrorBoundary extends BaseErrorBoundary {
variant="body2"
sx={{ mt: 2, fontFamily: 'monospace', fontSize: '0.875rem' }}
>
Error: {this.state.error.message}
{(() => {
try {
const msg = this.state.error.message || this.state.error.toString();
return `Error: ${String(msg)}`;
} catch (e) {
return 'Error: [Unable to display error message]';
}
})()}
</Typography>
)}
</Alert>