satellite/{satellitedb, web}: display object count in satellite UI

Even though we want to start charging segment fee instead of object fee,
it's hard for users to understand what a segment is. This PR adds the
object count back in the UI alongside with segment count to help address
the issue.

Change-Id: I92eb42c769d350eba68a72443deffec5c278359c
This commit is contained in:
Yingrong Zhao 2021-10-28 11:50:06 -04:00 committed by Yingrong Zhao
parent 187e508364
commit 774ae017e3
13 changed files with 37 additions and 9 deletions

View File

@ -72,6 +72,7 @@ type ProjectUsage struct {
Storage float64 `json:"storage"`
Egress int64 `json:"egress"`
SegmentCount float64 `json:"segmentCount"`
ObjectCount float64 `json:"objectCount"`
Since time.Time `json:"since"`
Before time.Time `json:"before"`
@ -90,6 +91,7 @@ type BucketUsage struct {
Storage float64
Egress float64
ObjectCount int64
SegmentCount int64
Since time.Time

View File

@ -68,6 +68,8 @@ const (
FieldEgress = "egress"
// FieldSegmentCount is a field name for segments count.
FieldSegmentCount = "segmentCount"
// FieldObjectCount is a field name for objects count.
FieldObjectCount = "objectCount"
// FieldPageCount is a field name for total page count.
FieldPageCount = "pageCount"
// FieldCurrentPage is a field name for current page number.
@ -336,6 +338,9 @@ func graphqlBucketUsage() *graphql.Object {
FieldEgress: &graphql.Field{
Type: graphql.Float,
},
FieldObjectCount: &graphql.Field{
Type: graphql.Float,
},
FieldSegmentCount: &graphql.Field{
Type: graphql.Float,
},
@ -417,6 +422,9 @@ func graphqlProjectUsage() *graphql.Object {
FieldEgress: &graphql.Field{
Type: graphql.Float,
},
FieldObjectCount: &graphql.Field{
Type: graphql.Float,
},
FieldSegmentCount: &graphql.Field{
Type: graphql.Float,
},

View File

@ -205,6 +205,7 @@ func TestBuckets(t *testing.T) {
bucketName
storage
egress
objectCount
segmentCount
since
before
@ -342,6 +343,7 @@ func TestProjects(t *testing.T) {
bucketName
storage
egress
objectCount
segmentCount
since
before
@ -582,6 +584,7 @@ func TestWrongUser(t *testing.T) {
bucketName
storage
egress
objectCount
segmentCount
since
before
@ -728,6 +731,7 @@ func TestWrongUser(t *testing.T) {
bucketName
storage
egress
objectCount
segmentCount
since
before

View File

@ -279,7 +279,8 @@ func (db *ProjectAccounting) GetProjectTotal(ctx context.Context, projectID uuid
bucket_storage_tallies.total_bytes,
bucket_storage_tallies.inline,
bucket_storage_tallies.remote,
bucket_storage_tallies.total_segments_count
bucket_storage_tallies.total_segments_count,
bucket_storage_tallies.object_count
FROM
bucket_storage_tallies
WHERE
@ -304,7 +305,7 @@ func (db *ProjectAccounting) GetProjectTotal(ctx context.Context, projectID uuid
tally := accounting.BucketStorageTally{}
var inline, remote int64
err = storageTalliesRows.Scan(&tally.IntervalStart, &tally.TotalBytes, &inline, &remote, &tally.TotalSegmentCount)
err = storageTalliesRows.Scan(&tally.IntervalStart, &tally.TotalBytes, &inline, &remote, &tally.TotalSegmentCount, &tally.ObjectCount)
if err != nil {
return nil, errs.Combine(err, storageTalliesRows.Close())
}
@ -331,13 +332,14 @@ func (db *ProjectAccounting) GetProjectTotal(ctx context.Context, projectID uuid
usage = new(accounting.ProjectUsage)
usage.Egress = memory.Size(totalEgress).Int64()
// sum up storage and objects
// sum up storage, objects, and segments
for _, tallies := range bucketsTallies {
for i := len(tallies) - 1; i > 0; i-- {
current := (tallies)[i]
hours := (tallies)[i-1].IntervalStart.Sub(current.IntervalStart).Hours()
usage.Storage += memory.Size(current.Bytes()).Float64() * hours
usage.SegmentCount += float64(current.TotalSegmentCount) * hours
usage.ObjectCount += float64(current.ObjectCount) * hours
}
}
@ -614,7 +616,7 @@ func (db *ProjectAccounting) GetBucketTotals(ctx context.Context, projectID uuid
FROM bucket_bandwidth_rollups
WHERE project_id = ? AND bucket_name = ? AND interval_start >= ? AND interval_start <= ? AND action = ?`)
storageQuery := db.db.Rebind(`SELECT total_bytes, inline, remote, total_segments_count
storageQuery := db.db.Rebind(`SELECT total_bytes, inline, remote, object_count, total_segments_count
FROM bucket_storage_tallies
WHERE project_id = ? AND bucket_name = ? AND interval_start >= ? AND interval_start <= ?
ORDER BY interval_start DESC
@ -646,7 +648,7 @@ func (db *ProjectAccounting) GetBucketTotals(ctx context.Context, projectID uuid
var tally accounting.BucketStorageTally
var inline, remote int64
err = storageRow.Scan(&tally.TotalBytes, &inline, &remote, &tally.TotalSegmentCount)
err = storageRow.Scan(&tally.TotalBytes, &inline, &remote, &tally.ObjectCount, &tally.TotalSegmentCount)
if err != nil {
if !errors.Is(err, sql.ErrNoRows) {
return nil, err
@ -660,6 +662,7 @@ func (db *ProjectAccounting) GetBucketTotals(ctx context.Context, projectID uuid
// fill storage and object count
bucketUsage.Storage = memory.Size(tally.Bytes()).GB()
bucketUsage.SegmentCount = tally.TotalSegmentCount
bucketUsage.ObjectCount = tally.ObjectCount
bucketUsages = append(bucketUsages, bucketUsage)
}

View File

@ -31,6 +31,7 @@ export class BucketsApiGql extends BaseGql implements BucketsApi {
bucketName,
storage,
egress,
objectCount,
segmentCount,
since,
before
@ -96,6 +97,7 @@ export class BucketsApiGql extends BaseGql implements BucketsApi {
key.bucketName,
key.storage,
key.egress,
key.objectCount,
key.segmentCount,
new Date(key.since),
new Date(key.before)));

View File

@ -6,6 +6,7 @@
<p class="container__item name" :title="itemData.name">{{ itemData.name }}</p>
<p class="container__item">{{ itemData.storage.toFixed(2) }}GB</p>
<p class="container__item">{{ itemData.egress.toFixed(2) }}GB</p>
<p class="container__item">{{ itemData.objectCount.toString() }}</p>
<p class="container__item">{{ itemData.segmentCount.toString() }}</p>
</div>
</template>
@ -18,7 +19,7 @@ import { Bucket } from '@/types/buckets';
// @vue/component
@Component
export default class BucketItem extends Vue {
@Prop({default: () => new Bucket('', 0, 0, 0, new Date(), new Date())})
@Prop({default: () => new Bucket('', 0, 0, 0, 0, new Date(), new Date())})
private readonly itemData: Bucket;
}
</script>

View File

@ -12,6 +12,9 @@
<div class="sort-header-container__item">
<p class="sort-header-container__item__name">BANDWIDTH</p>
</div>
<div class="sort-header-container__item">
<p class="sort-header-container__item__name">OBJECTS</p>
</div>
<div class="sort-header-container__item">
<p class="sort-header-container__item__name">SEGMENTS</p>
</div>

View File

@ -30,6 +30,7 @@ export class Bucket {
public name: string = '',
public storage: number = 0,
public egress: number = 0,
public objectCount: number = 0,
public segmentCount: number = 0,
public since: Date = new Date(),
public before: Date = new Date(),

View File

@ -23,7 +23,7 @@ const projectsApi = new ProjectsApiMock();
const projectsModule = makeProjectsModule(projectsApi);
const store = new Vuex.Store({ modules: { bucketUsageModule, projectsModule }});
const bucket = new Bucket('name', 1, 1, 1, new Date(), new Date());
const bucket = new Bucket('name', 1, 1, 1, 1, new Date(), new Date());
describe('BucketArea.vue', () => {
it('renders correctly without bucket', (): void => {

View File

@ -8,7 +8,7 @@ import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
const bucket = new Bucket('name', 1, 1, 1, new Date(), new Date());
const bucket = new Bucket('name', 1, 1, 1, 1, new Date(), new Date());
describe('BucketItem.vue', () => {
it('renders correctly', (): void => {

View File

@ -6,5 +6,6 @@ exports[`BucketItem.vue renders correctly 1`] = `
<p class="container__item">1.00GB</p>
<p class="container__item">1.00GB</p>
<p class="container__item">1</p>
<p class="container__item">1</p>
</div>
`;

View File

@ -11,6 +11,9 @@ exports[`SortingHeader.vue renders correctly 1`] = `
<div class="sort-header-container__item">
<p class="sort-header-container__item__name">BANDWIDTH</p>
</div>
<div class="sort-header-container__item">
<p class="sort-header-container__item__name">OBJECTS</p>
</div>
<div class="sort-header-container__item">
<p class="sort-header-container__item__name">SEGMENTS</p>
</div>

View File

@ -29,7 +29,7 @@ const store = new Vuex.Store<{
bucketsModule: typeof bucketsModule.state,
}>({modules: { projectsModule, bucketsModule } });
const state = store.state.bucketsModule;
const bucket = new Bucket('test', 10, 10, 1, new Date(), new Date());
const bucket = new Bucket('test', 10, 10, 1, 1, new Date(), new Date());
const page: BucketPage = { buckets: [bucket], currentPage: 1, pageCount: 1, offset: 0, limit: 7, search: 'test', totalCount: 1 };
describe('actions', () => {