style: format all source files with Prettier
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -80,7 +80,9 @@ export function DecryptDialog({ sealedSecret, secretKey, onClose }: DecryptDialo
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose} aria-label="Close dialog">Close</Button>
|
||||
<Button onClick={onClose} aria-label="Close dialog">
|
||||
Close
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
@@ -103,7 +105,9 @@ export function DecryptDialog({ sealedSecret, secretKey, onClose }: DecryptDialo
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose} aria-label="Close dialog">Close</Button>
|
||||
<Button onClick={onClose} aria-label="Close dialog">
|
||||
Close
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
@@ -182,7 +186,9 @@ export function DecryptDialog({ sealedSecret, secretKey, onClose }: DecryptDialo
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={onClose} aria-label="Close dialog">Close</Button>
|
||||
<Button onClick={onClose} aria-label="Close dialog">
|
||||
Close
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -83,7 +83,9 @@ export function EncryptDialog({ open, onClose }: EncryptDialogProps) {
|
||||
|
||||
const handleCreate = async () => {
|
||||
// Filter out empty rows
|
||||
const validKeyValues = keyValues.filter(kv => kv.key || kv.value).map(kv => ({
|
||||
const validKeyValues = keyValues
|
||||
.filter(kv => kv.key || kv.value)
|
||||
.map(kv => ({
|
||||
key: kv.key,
|
||||
value: kv.value,
|
||||
}));
|
||||
@@ -232,7 +234,11 @@ export function EncryptDialog({ open, onClose }: EncryptDialogProps) {
|
||||
disabled={keyValues.length === 1}
|
||||
color="error"
|
||||
aria-label={`Remove key-value pair ${index + 1}`}
|
||||
title={keyValues.length === 1 ? 'At least one key-value pair is required' : `Remove key-value pair ${index + 1}`}
|
||||
title={
|
||||
keyValues.length === 1
|
||||
? 'At least one key-value pair is required'
|
||||
: `Remove key-value pair ${index + 1}`
|
||||
}
|
||||
>
|
||||
<Icon icon="mdi:delete" />
|
||||
</IconButton>
|
||||
|
||||
@@ -192,8 +192,8 @@ export class GenericErrorBoundary extends BaseErrorBoundary {
|
||||
Something Went Wrong
|
||||
</Typography>
|
||||
<Typography variant="body2" paragraph>
|
||||
An unexpected error occurred. Please try reloading the page or contact your administrator
|
||||
if the problem persists.
|
||||
An unexpected error occurred. Please try reloading the page or contact your
|
||||
administrator if the problem persists.
|
||||
</Typography>
|
||||
{this.state.error && (
|
||||
<Typography
|
||||
|
||||
@@ -41,15 +41,37 @@ export function SealedSecretDetailSkeleton() {
|
||||
<Skeleton variant="text" width="40%" height={40} sx={{ mb: 3 }} animation="wave" />
|
||||
|
||||
{/* Metadata section */}
|
||||
<Skeleton variant="rectangular" height={200} sx={{ mb: 2, borderRadius: 1 }} animation="wave" />
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
height={200}
|
||||
sx={{ mb: 2, borderRadius: 1 }}
|
||||
animation="wave"
|
||||
/>
|
||||
|
||||
{/* Encrypted data section */}
|
||||
<Skeleton variant="rectangular" height={150} sx={{ mb: 2, borderRadius: 1 }} animation="wave" />
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
height={150}
|
||||
sx={{ mb: 2, borderRadius: 1 }}
|
||||
animation="wave"
|
||||
/>
|
||||
|
||||
{/* Actions section */}
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
<Skeleton variant="rectangular" width={120} height={36} sx={{ borderRadius: 1 }} animation="wave" />
|
||||
<Skeleton variant="rectangular" width={120} height={36} sx={{ borderRadius: 1 }} animation="wave" />
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
width={120}
|
||||
height={36}
|
||||
sx={{ borderRadius: 1 }}
|
||||
animation="wave"
|
||||
/>
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
width={120}
|
||||
height={36}
|
||||
sx={{ borderRadius: 1 }}
|
||||
animation="wave"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
@@ -66,10 +88,27 @@ export function SealingKeysListSkeleton() {
|
||||
{[1, 2].map(i => (
|
||||
<Box key={i} sx={{ mb: 3 }}>
|
||||
<Skeleton variant="text" width="30%" height={32} sx={{ mb: 1 }} animation="wave" />
|
||||
<Skeleton variant="rectangular" height={100} sx={{ borderRadius: 1, mb: 1 }} animation="wave" />
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
height={100}
|
||||
sx={{ borderRadius: 1, mb: 1 }}
|
||||
animation="wave"
|
||||
/>
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<Skeleton variant="rectangular" width={100} height={28} sx={{ borderRadius: 1 }} animation="wave" />
|
||||
<Skeleton variant="rectangular" width={100} height={28} sx={{ borderRadius: 1 }} animation="wave" />
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
width={100}
|
||||
height={28}
|
||||
sx={{ borderRadius: 1 }}
|
||||
animation="wave"
|
||||
/>
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
width={100}
|
||||
height={28}
|
||||
sx={{ borderRadius: 1 }}
|
||||
animation="wave"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
|
||||
@@ -87,9 +87,7 @@ export function SealedSecretDetail() {
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Failed to load SealedSecret
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
{String(error)}
|
||||
</Typography>
|
||||
<Typography variant="body2">{String(error)}</Typography>
|
||||
</Alert>
|
||||
</Box>
|
||||
);
|
||||
@@ -271,7 +269,9 @@ export function SealedSecretDetail() {
|
||||
},
|
||||
{
|
||||
name: 'Labels',
|
||||
value: String(JSON.stringify(sealedSecret.spec.template.metadata?.labels || {})),
|
||||
value: String(
|
||||
JSON.stringify(sealedSecret.spec.template.metadata?.labels || {})
|
||||
),
|
||||
hide: !sealedSecret.spec.template.metadata?.labels,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -126,9 +126,7 @@ export function SealedSecretList() {
|
||||
// Show error if CRD is not installed
|
||||
if (error) {
|
||||
return (
|
||||
<SectionBox
|
||||
title="Sealed Secrets"
|
||||
>
|
||||
<SectionBox title="Sealed Secrets">
|
||||
<Box p={2}>
|
||||
<StatusLabel status="error">Error</StatusLabel>
|
||||
<Box mt={2}>
|
||||
@@ -139,7 +137,11 @@ export function SealedSecretList() {
|
||||
cluster.
|
||||
</p>
|
||||
<p>
|
||||
Install with: <code>kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml</code>
|
||||
Install with:{' '}
|
||||
<code>
|
||||
kubectl apply -f
|
||||
https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
|
||||
</code>
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
@@ -153,9 +155,7 @@ export function SealedSecretList() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<SectionBox
|
||||
title="Sealed Secrets"
|
||||
>
|
||||
<SectionBox title="Sealed Secrets">
|
||||
<VersionWarning autoDetect showDetails={false} />
|
||||
<SectionFilterHeader title="" noNamespaceFilter={false} actions={actions} />
|
||||
<SimpleTable data={sealedSecrets} columns={columns} />
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
*/
|
||||
|
||||
import { K8s } from '@kinvolk/headlamp-plugin/lib';
|
||||
import { SectionBox, SimpleTable, StatusLabel } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
|
||||
import {
|
||||
SectionBox,
|
||||
SimpleTable,
|
||||
StatusLabel,
|
||||
} from '@kinvolk/headlamp-plugin/lib/CommonComponents';
|
||||
import { Box, Button, Chip } from '@mui/material';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import React from 'react';
|
||||
@@ -27,7 +31,9 @@ interface SealingKey {
|
||||
*/
|
||||
export function SealingKeysView() {
|
||||
const config = getPluginConfig();
|
||||
const [secrets, , loading] = K8s.ResourceClasses.Secret.useList({ namespace: config.controllerNamespace });
|
||||
const [secrets, , loading] = K8s.ResourceClasses.Secret.useList({
|
||||
namespace: config.controllerNamespace,
|
||||
});
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
// Filter for sealing key secrets
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
*/
|
||||
|
||||
import { Link } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
|
||||
import { NameValueTable, SectionBox, StatusLabel } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
|
||||
import {
|
||||
NameValueTable,
|
||||
SectionBox,
|
||||
StatusLabel,
|
||||
} from '@kinvolk/headlamp-plugin/lib/CommonComponents';
|
||||
import React from 'react';
|
||||
import { SealedSecret } from '../lib/SealedSecretCRD';
|
||||
|
||||
|
||||
@@ -41,9 +41,7 @@ export function VersionWarning({ autoDetect = true, showDetails = false }: Versi
|
||||
} else if (result.ok === false) {
|
||||
setDetectedVersion(null);
|
||||
// Ensure error is always a string
|
||||
const errorMessage = typeof result.error === 'string'
|
||||
? result.error
|
||||
: String(result.error);
|
||||
const errorMessage = typeof result.error === 'string' ? result.error : String(result.error);
|
||||
setError(errorMessage);
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -70,11 +68,14 @@ export function VersionWarning({ autoDetect = true, showDetails = false }: Versi
|
||||
if (error) {
|
||||
return (
|
||||
<Box mb={2}>
|
||||
<Alert severity="error" action={
|
||||
<Alert
|
||||
severity="error"
|
||||
action={
|
||||
<Button color="inherit" size="small" onClick={detectVersion}>
|
||||
Retry
|
||||
</Button>
|
||||
}>
|
||||
}
|
||||
>
|
||||
<strong>API Version Detection Failed</strong>
|
||||
<br />
|
||||
{String(error)}
|
||||
@@ -84,7 +85,8 @@ export function VersionWarning({ autoDetect = true, showDetails = false }: Versi
|
||||
<br />
|
||||
Install Sealed Secrets with:{' '}
|
||||
<code style={{ fontSize: '0.875em' }}>
|
||||
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
|
||||
kubectl apply -f
|
||||
https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
|
||||
</code>
|
||||
<br />
|
||||
Or visit:{' '}
|
||||
|
||||
@@ -15,14 +15,7 @@ import {
|
||||
parsePublicKeyFromCert,
|
||||
} from '../lib/crypto';
|
||||
import { validateSecretKey, validateSecretName, validateSecretValue } from '../lib/validators';
|
||||
import {
|
||||
AsyncResult,
|
||||
CertificateInfo,
|
||||
Err,
|
||||
Ok,
|
||||
PlaintextValue,
|
||||
SealedSecretScope,
|
||||
} from '../types';
|
||||
import { AsyncResult, CertificateInfo, Err, Ok, PlaintextValue, SealedSecretScope } from '../types';
|
||||
|
||||
/**
|
||||
* Request parameters for encryption
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* SealedSecret Custom Resource Definition
|
||||
*/
|
||||
|
||||
import { ApiProxy,K8s } from '@kinvolk/headlamp-plugin/lib';
|
||||
import { ApiProxy, K8s } from '@kinvolk/headlamp-plugin/lib';
|
||||
|
||||
const { apiFactoryWithNamespace } = ApiProxy;
|
||||
const { KubeObject } = K8s.cluster;
|
||||
|
||||
@@ -39,7 +39,10 @@ describe('retry logic', () => {
|
||||
.mockResolvedValueOnce({ ok: false, error: 'error2' })
|
||||
.mockResolvedValueOnce({ ok: true, value: 'success' });
|
||||
|
||||
const promise = retryWithBackoff(failTwiceThenSucceed, { maxAttempts: 3, initialDelayMs: 100 });
|
||||
const promise = retryWithBackoff(failTwiceThenSucceed, {
|
||||
maxAttempts: 3,
|
||||
initialDelayMs: 100,
|
||||
});
|
||||
await vi.runAllTimersAsync();
|
||||
const result = await promise;
|
||||
|
||||
@@ -72,7 +75,10 @@ describe('retry logic', () => {
|
||||
.mockResolvedValueOnce({ ok: false, error: 'error2' })
|
||||
.mockResolvedValueOnce({ ok: true, value: 'success' });
|
||||
|
||||
const promise = retryWithBackoff(failTwiceThenSucceed, { maxAttempts: 3, initialDelayMs: 1000 });
|
||||
const promise = retryWithBackoff(failTwiceThenSucceed, {
|
||||
maxAttempts: 3,
|
||||
initialDelayMs: 1000,
|
||||
});
|
||||
|
||||
// Fast-forward through retries
|
||||
await vi.runAllTimersAsync();
|
||||
|
||||
+6
-8
@@ -109,9 +109,7 @@ export async function retryWithBackoff<T, E>(
|
||||
const isLastAttempt = attempt === opts.maxAttempts - 1;
|
||||
if (isLastAttempt) {
|
||||
// No more retries, return final error
|
||||
return Err(
|
||||
`Operation failed after ${opts.maxAttempts} attempts:\n${errors.join('\n')}`
|
||||
);
|
||||
return Err(`Operation failed after ${opts.maxAttempts} attempts:\n${errors.join('\n')}`);
|
||||
}
|
||||
|
||||
// Wait before retrying
|
||||
@@ -124,9 +122,7 @@ export async function retryWithBackoff<T, E>(
|
||||
|
||||
const isLastAttempt = attempt === opts.maxAttempts - 1;
|
||||
if (isLastAttempt) {
|
||||
return Err(
|
||||
`Operation failed after ${opts.maxAttempts} attempts:\n${errors.join('\n')}`
|
||||
);
|
||||
return Err(`Operation failed after ${opts.maxAttempts} attempts:\n${errors.join('\n')}`);
|
||||
}
|
||||
|
||||
const delay = calculateDelay(attempt, opts);
|
||||
@@ -171,10 +167,12 @@ export function isRetryableHttpError(error: Error): boolean {
|
||||
}
|
||||
|
||||
// Check for specific retryable status codes
|
||||
return message.includes('429') || // Too Many Requests
|
||||
return (
|
||||
message.includes('429') || // Too Many Requests
|
||||
message.includes('408') || // Request Timeout
|
||||
message.includes('503') || // Service Unavailable
|
||||
message.includes('504'); // Gateway Timeout
|
||||
message.includes('504')
|
||||
); // Gateway Timeout
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-3
@@ -16,9 +16,7 @@ type KubeObjectInterface = K8s.cluster.KubeObjectInterface;
|
||||
* return Ok(a / b);
|
||||
* }
|
||||
*/
|
||||
export type Result<T, E = Error> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: E };
|
||||
export type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };
|
||||
|
||||
/**
|
||||
* Async result type for promises that can fail
|
||||
|
||||
Reference in New Issue
Block a user