Skip to content

Commit 96b1d4f

Browse files
authored
Added bucket details inside objects listing (#1502)
Signed-off-by: Benjamin Perez <[email protected]>
1 parent 02acb76 commit 96b1d4f

File tree

4 files changed

+93
-38
lines changed

4 files changed

+93
-38
lines changed

portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {
4545
decodeFileName,
4646
encodeFileName,
4747
niceBytes,
48+
niceBytesInt,
4849
} from "../../../../../../common/utils";
4950

5051
import {
@@ -1094,27 +1095,6 @@ const ListObjects = ({
10941095
uploadPath = uploadPath.concat(currentPath);
10951096
}
10961097

1097-
// TODO: Add bucket information panel
1098-
/*
1099-
*
1100-
* subTitle={
1101-
<Fragment>
1102-
<Grid item xs={12} className={classes.bucketDetails}>
1103-
<span className={classes.detailsSpacer}>
1104-
Created:&nbsp;&nbsp;&nbsp;<strong></strong>
1105-
</span>
1106-
<span className={classes.detailsSpacer}>
1107-
Access:&nbsp;&nbsp;&nbsp;<strong></strong>
1108-
</span>
1109-
<span className={classes.detailsSpacer}>
1110-
SIZE / TOTAL OBJECTS
1111-
</span>
1112-
</Grid>
1113-
</Fragment>
1114-
}
1115-
*
1116-
* */
1117-
11181098
return (
11191099
<React.Fragment>
11201100
{shareFileModalOpen && selectedPreview && (
@@ -1178,6 +1158,38 @@ const ListObjects = ({
11781158
fullSizeBreadcrumbs
11791159
/>
11801160
}
1161+
subTitle={
1162+
<Fragment>
1163+
<Grid item xs={12} className={classes.bucketDetails}>
1164+
<span className={classes.detailsSpacer}>
1165+
Created:&nbsp;&nbsp;&nbsp;
1166+
<strong>{bucketInfo?.creation_date || ""}</strong>
1167+
</span>
1168+
<span className={classes.detailsSpacer}>
1169+
Access:&nbsp;&nbsp;&nbsp;
1170+
<strong>{bucketInfo?.access || ""}</strong>
1171+
</span>
1172+
{bucketInfo && (
1173+
<Fragment>
1174+
<span className={classes.detailsSpacer}>
1175+
{bucketInfo.size && (
1176+
<Fragment>{niceBytesInt(bucketInfo.size)}</Fragment>
1177+
)}
1178+
{bucketInfo.size && bucketInfo.objects ? " / " : ""}
1179+
{bucketInfo.objects && (
1180+
<Fragment>
1181+
{bucketInfo.objects}&nbsp;Object
1182+
{bucketInfo.objects && bucketInfo.objects !== 1
1183+
? "s"
1184+
: ""}
1185+
</Fragment>
1186+
)}
1187+
</span>
1188+
</Fragment>
1189+
)}
1190+
</Grid>
1191+
</Fragment>
1192+
}
11811193
actions={
11821194
<Fragment>
11831195
<input

portal-ui/src/screens/Console/Buckets/types.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ export interface BucketInfo {
4545
name: string;
4646
access: string;
4747
definition: string;
48+
creation_date?: string;
49+
objects?: number;
50+
size?: number;
4851
}
4952

5053
export interface BucketList {

restapi/user_buckets.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"strings"
2525
"time"
2626

27+
"github.com/minio/madmin-go"
2728
"github.com/minio/mc/cmd"
2829
"github.com/minio/mc/pkg/probe"
2930
"github.com/minio/minio-go/v7"
@@ -561,11 +562,19 @@ func getBucketSetPolicyResponse(session *models.Principal, bucketName string, re
561562
// defining the client to be used
562563
minioClient := minioClient{client: mClient}
563564

565+
mAdmin, err := NewMinioAdminClient(session)
566+
if err != nil {
567+
return nil, prepareError(err)
568+
}
569+
// create a minioClient interface implementation
570+
// defining the client to be used
571+
adminClient := AdminClient{Client: mAdmin}
572+
564573
if err := setBucketAccessPolicy(ctx, minioClient, bucketName, *req.Access, req.Definition); err != nil {
565574
return nil, prepareError(err)
566575
}
567576
// set bucket access policy
568-
bucket, err := getBucketInfo(ctx, minioClient, bucketName)
577+
bucket, err := getBucketInfo(ctx, minioClient, adminClient, bucketName)
569578
if err != nil {
570579
return nil, prepareError(err)
571580
}
@@ -624,7 +633,7 @@ func getDeleteBucketResponse(session *models.Principal, params user_api.DeleteBu
624633
}
625634

626635
// getBucketInfo return bucket information including name, policy access, size and creation date
627-
func getBucketInfo(ctx context.Context, client MinioClient, bucketName string) (*models.Bucket, error) {
636+
func getBucketInfo(ctx context.Context, client MinioClient, adminClient MinioAdmin, bucketName string) (*models.Bucket, error) {
628637
var bucketAccess models.BucketAccess
629638
policyStr, err := client.getBucketPolicy(context.Background(), bucketName)
630639
if err != nil {
@@ -655,13 +664,28 @@ func getBucketInfo(ctx context.Context, client MinioClient, bucketName string) (
655664
if bucketTags != nil {
656665
bucketDetails.Tags = bucketTags.ToMap()
657666
}
667+
668+
info, err := adminClient.AccountInfo(ctx)
669+
if err != nil {
670+
return nil, err
671+
}
672+
673+
var bucketInfo madmin.BucketAccessInfo
674+
675+
for _, bucket := range info.Buckets {
676+
if bucket.Name == bucketName {
677+
bucketInfo = bucket
678+
}
679+
}
680+
658681
return &models.Bucket{
659682
Name: &bucketName,
660683
Access: &bucketAccess,
661684
Definition: policyStr,
662-
CreationDate: "", // to be implemented
663-
Size: 0, // to be implemented
685+
CreationDate: bucketInfo.Created.Format(time.RFC3339),
686+
Size: int64(bucketInfo.Size),
664687
Details: bucketDetails,
688+
Objects: int64(bucketInfo.Objects),
665689
}, nil
666690
}
667691

@@ -676,7 +700,16 @@ func getBucketInfoResponse(session *models.Principal, params user_api.BucketInfo
676700
// create a minioClient interface implementation
677701
// defining the client to be used
678702
minioClient := minioClient{client: mClient}
679-
bucket, err := getBucketInfo(ctx, minioClient, params.Name)
703+
704+
mAdmin, err := NewMinioAdminClient(session)
705+
if err != nil {
706+
return nil, prepareError(err)
707+
}
708+
// create a minioClient interface implementation
709+
// defining the client to be used
710+
adminClient := AdminClient{Client: mAdmin}
711+
712+
bucket, err := getBucketInfo(ctx, minioClient, adminClient, params.Name)
680713
if err != nil {
681714
return nil, prepareError(err)
682715
}

restapi/user_buckets_test.go

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ func TestBucketInfo(t *testing.T) {
256256
assert := assert.New(t)
257257
// mock minIO client
258258
minClient := minioClientMock{}
259+
adminClient := adminClientMock{}
259260
ctx := context.Background()
260261
function := "getBucketInfo()"
261262

@@ -269,8 +270,9 @@ func TestBucketInfo(t *testing.T) {
269270
outputExpected := &models.Bucket{
270271
Name: swag.String(bucketToSet),
271272
Access: models.NewBucketAccess(models.BucketAccessPRIVATE),
272-
CreationDate: "", // to be implemented
273-
Size: 0, // to be implemented
273+
CreationDate: "0001-01-01T00:00:00Z",
274+
Size: 0,
275+
Objects: 0,
274276
}
275277
infoPolicy := `
276278
{
@@ -307,14 +309,15 @@ func TestBucketInfo(t *testing.T) {
307309
return mockBucketList, nil
308310
}
309311

310-
bucketInfo, err := getBucketInfo(ctx, minClient, bucketToSet)
312+
bucketInfo, err := getBucketInfo(ctx, minClient, adminClient, bucketToSet)
311313
if err != nil {
312314
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
313315
}
314316
assert.Equal(outputExpected.Name, bucketInfo.Name)
315317
assert.Equal(outputExpected.Access, bucketInfo.Access)
316318
assert.Equal(outputExpected.CreationDate, bucketInfo.CreationDate)
317319
assert.Equal(outputExpected.Size, bucketInfo.Size)
320+
assert.Equal(outputExpected.Objects, bucketInfo.Objects)
318321

319322
// Test-2: getBucketInfo() get a bucket with PUBLIC access
320323
// mock policy for bucket csbucket with readWrite access (should return PUBLIC)
@@ -326,17 +329,19 @@ func TestBucketInfo(t *testing.T) {
326329
outputExpected = &models.Bucket{
327330
Name: swag.String(bucketToSet),
328331
Access: models.NewBucketAccess(models.BucketAccessPUBLIC),
329-
CreationDate: "", // to be implemented
330-
Size: 0, // to be implemented
332+
CreationDate: "0001-01-01T00:00:00Z",
333+
Size: 0,
334+
Objects: 0,
331335
}
332-
bucketInfo, err = getBucketInfo(ctx, minClient, bucketToSet)
336+
bucketInfo, err = getBucketInfo(ctx, minClient, adminClient, bucketToSet)
333337
if err != nil {
334338
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
335339
}
336340
assert.Equal(outputExpected.Name, bucketInfo.Name)
337341
assert.Equal(outputExpected.Access, bucketInfo.Access)
338342
assert.Equal(outputExpected.CreationDate, bucketInfo.CreationDate)
339343
assert.Equal(outputExpected.Size, bucketInfo.Size)
344+
assert.Equal(outputExpected.Objects, bucketInfo.Objects)
340345

341346
// Test-3: getBucketInfo() get a bucket with PRIVATE access
342347
// if bucket has a null statement, the the bucket is PRIVATE
@@ -348,17 +353,19 @@ func TestBucketInfo(t *testing.T) {
348353
outputExpected = &models.Bucket{
349354
Name: swag.String(bucketToSet),
350355
Access: models.NewBucketAccess(models.BucketAccessPRIVATE),
351-
CreationDate: "", // to be implemented
352-
Size: 0, // to be implemented
356+
CreationDate: "0001-01-01T00:00:00Z",
357+
Size: 0,
358+
Objects: 0,
353359
}
354-
bucketInfo, err = getBucketInfo(ctx, minClient, bucketToSet)
360+
bucketInfo, err = getBucketInfo(ctx, minClient, adminClient, bucketToSet)
355361
if err != nil {
356362
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
357363
}
358364
assert.Equal(outputExpected.Name, bucketInfo.Name)
359365
assert.Equal(outputExpected.Access, bucketInfo.Access)
360366
assert.Equal(outputExpected.CreationDate, bucketInfo.CreationDate)
361367
assert.Equal(outputExpected.Size, bucketInfo.Size)
368+
assert.Equal(outputExpected.Objects, bucketInfo.Objects)
362369

363370
// Test-4: getBucketInfo() returns an error while parsing invalid policy
364371
mockPolicy = "policyinvalid"
@@ -369,10 +376,10 @@ func TestBucketInfo(t *testing.T) {
369376
outputExpected = &models.Bucket{
370377
Name: swag.String(bucketToSet),
371378
Access: models.NewBucketAccess(models.BucketAccessCUSTOM),
372-
CreationDate: "", // to be implemented
373-
Size: 0, // to be implemented
379+
CreationDate: "",
380+
Size: 0,
374381
}
375-
_, err = getBucketInfo(ctx, minClient, bucketToSet)
382+
_, err = getBucketInfo(ctx, minClient, adminClient, bucketToSet)
376383
if assert.Error(err) {
377384
assert.Equal("invalid character 'p' looking for beginning of value", err.Error())
378385
}

0 commit comments

Comments
 (0)