fix: Resolve UI errors and improve user creation flow

- Fix validateDOMNesting warnings in Reports and QuickStartWizard components
- Fix user creation API field mapping (accessKey/secretKey to username/password)
- Increase timeout for bucket-with-user creation to prevent socket hang up errors
- Improve credential display with clear Access Key/Secret Key labels
- Add MinIO CLI connection examples to credential displays
- Make timeout 60 seconds for complex operations that create bucket, user, and policy

This fixes:
- React DOM nesting warnings with Chip components
- 400 Bad Request errors when creating users
- Socket hang up errors during bucket+user creation
- Clear display of MinIO access credentials

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-23 17:20:54 +02:00
parent cdd4dcc2db
commit 6388a54fe6
4 changed files with 41 additions and 20 deletions
@@ -119,10 +119,13 @@ const CreateBucketDialog: React.FC<CreateBucketDialogProps> = ({
if (data.createUser) {
// Create bucket with user (like the script)
// This operation can take longer as it creates bucket, user, and policy
await api.post('/buckets/with-user', {
bucketName: data.bucketName,
username: data.username!,
password: data.password!,
}, {
timeout: 60000, // 60 seconds timeout for this complex operation
});
setCredentials({
username: data.username!,
@@ -300,7 +303,7 @@ const CreateBucketDialog: React.FC<CreateBucketDialogProps> = ({
{credentials && (
<Box sx={{ mt: 2 }}>
<Typography variant="h6" gutterBottom>
User Credentials
MinIO User Credentials
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
Save these credentials securely. They won't be shown again.
@@ -309,27 +312,36 @@ const CreateBucketDialog: React.FC<CreateBucketDialogProps> = ({
<Box sx={{ bgcolor: 'grey.100', p: 2, borderRadius: 1, mb: 2 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
<Typography variant="body2">
<strong>Username:</strong> {credentials.username}
<strong>Access Key (Username):</strong> {credentials.username}
</Typography>
<IconButton
size="small"
onClick={() => copyToClipboard(credentials.username)}
title="Copy access key"
>
<ContentCopy fontSize="small" />
</IconButton>
</Box>
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
<Typography variant="body2">
<strong>Password:</strong> {credentials.password}
<strong>Secret Key (Password):</strong> {credentials.password}
</Typography>
<IconButton
size="small"
onClick={() => copyToClipboard(credentials.password)}
title="Copy secret key"
>
<ContentCopy fontSize="small" />
</IconButton>
</Box>
</Box>
<Typography variant="body2" color="text.secondary">
Use these credentials to connect via MinIO Client:
</Typography>
<Box sx={{ bgcolor: 'grey.900', color: 'grey.100', p: 1, borderRadius: 1, fontFamily: 'monospace', fontSize: '0.875rem', mt: 1 }}>
mc alias set myminio http://your-minio-server:9000 {credentials.username} {credentials.password}
</Box>
</Box>
)}
@@ -123,7 +123,9 @@ const QuickStartWizard: React.FC<QuickStartWizardProps> = ({
try {
// Step 1: Create bucket
await api.post('/buckets', { name: setupData.bucketName });
await api.post('/buckets', { name: setupData.bucketName }, {
timeout: 30000, // 30 seconds timeout
});
// Step 2: Create user
await userService.createUser({
@@ -165,7 +167,7 @@ const QuickStartWizard: React.FC<QuickStartWizardProps> = ({
};
const handleCopyCredentials = () => {
const credentials = `MinIO Credentials\n\nBucket: ${completedSetup.bucket}\nUsername: ${completedSetup.user}\nPassword: ${completedSetup.password}\nPolicy: ${completedSetup.policy}`;
const credentials = `MinIO Credentials\n\nBucket: ${completedSetup.bucket}\nAccess Key: ${completedSetup.user}\nSecret Key: ${completedSetup.password}\nPolicy: ${completedSetup.policy}\n\nConnection Example:\nmc alias set myminio http://your-minio-server:9000 ${completedSetup.user} ${completedSetup.password}`;
navigator.clipboard.writeText(credentials);
};
@@ -335,14 +337,16 @@ const QuickStartWizard: React.FC<QuickStartWizardProps> = ({
<ListItemText
primary="Access Level"
secondary={
<Chip
label={setupData.policyType}
size="small"
color={
setupData.policyType === 'readwrite' ? 'success' :
setupData.policyType === 'readonly' ? 'info' : 'warning'
}
/>
<Box component="span">
<Chip
label={setupData.policyType}
size="small"
color={
setupData.policyType === 'readwrite' ? 'success' :
setupData.policyType === 'readonly' ? 'info' : 'warning'
}
/>
</Box>
}
/>
</ListItem>
@@ -371,17 +375,17 @@ const QuickStartWizard: React.FC<QuickStartWizardProps> = ({
<Paper variant="outlined" sx={{ p: 3, mt: 2, bgcolor: 'grey.50' }}>
<Typography variant="h6" gutterBottom>
<Assignment sx={{ verticalAlign: 'middle', mr: 1 }} />
Your Credentials
Your MinIO Credentials
</Typography>
<Box sx={{ fontFamily: 'monospace', mt: 2 }}>
<Typography variant="body2">
<strong>Bucket:</strong> {completedSetup.bucket}
</Typography>
<Typography variant="body2">
<strong>Username:</strong> {completedSetup.user}
<strong>Access Key:</strong> {completedSetup.user}
</Typography>
<Typography variant="body2">
<strong>Password:</strong> {completedSetup.password}
<strong>Secret Key:</strong> {completedSetup.password}
</Typography>
<Typography variant="body2">
<strong>Policy:</strong> {completedSetup.policy}
+5 -3
View File
@@ -311,14 +311,16 @@ const Reports: React.FC = () => {
</Box>
{scheduleInfo && (
<>
<Typography variant="body2" paragraph>
<strong>Status:</strong>{' '}
<Box sx={{ mb: 2 }}>
<Typography variant="body2" component="span">
<strong>Status:</strong>{' '}
</Typography>
<Chip
label={scheduleInfo.enabled ? 'Enabled' : 'Disabled'}
size="small"
color={scheduleInfo.enabled ? 'success' : 'default'}
/>
</Typography>
</Box>
<Typography variant="body2" paragraph>
<strong>Schedule:</strong> {scheduleInfo.schedule}
</Typography>
+4 -1
View File
@@ -39,7 +39,10 @@ class UserService {
async createUser(userData: CreateUserRequest): Promise<void> {
try {
await axios.post(`${this.baseURL}/users`, userData, {
await axios.post(`${this.baseURL}/users`, {
username: userData.accessKey,
password: userData.secretKey,
}, {
headers: getAuthHeaders(),
});
} catch (error) {