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:
parent
187e508364
commit
774ae017e3
@ -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
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)));
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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(),
|
||||
|
@ -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 => {
|
||||
|
@ -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 => {
|
||||
|
@ -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>
|
||||
`;
|
||||
|
@ -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>
|
||||
|
@ -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', () => {
|
||||
|
Loading…
Reference in New Issue
Block a user