satellite/{projectaccounting, web}: merge settled and allocated lines for bandwidth graph

Merged bandwidth graph lines to show only allocated-dead for last 3 days and settled for other days.

Issue:
https://github.com/storj/storj/issues/6072

Change-Id: Ic7f03d22ccd82d27ae6e6a85e73e144c9852e33b
This commit is contained in:
Vitalii 2023-09-12 14:55:57 +03:00
parent ec8f3b4528
commit 8f27425284
8 changed files with 45 additions and 184 deletions

View File

@ -84,12 +84,17 @@ func Test_DailyUsage(t *testing.T) {
require.NoError(t, err)
err = satelliteSys.DB.Orders().UpdateBucketBandwidthSettle(ctx, projectID, []byte(firstBucketName), pb.PieceAction_GET, segment, 0, inFiveMinutes)
require.NoError(t, err)
err = planet.Satellites[0].DB.Orders().UpdateBucketBandwidthSettle(ctx, projectID, []byte(secondBucketName), pb.PieceAction_GET, segment, 0, inFiveMinutes)
err = satelliteSys.DB.Orders().UpdateBucketBandwidthSettle(ctx, projectID, []byte(secondBucketName), pb.PieceAction_GET, segment, 0, inFiveMinutes)
require.NoError(t, err)
err = satelliteSys.DB.Orders().UpdateBucketBandwidthAllocation(ctx, projectID, []byte(firstBucketName), pb.PieceAction_GET, segment, inFiveMinutes)
require.NoError(t, err)
err = satelliteSys.DB.Orders().UpdateBucketBandwidthAllocation(ctx, projectID, []byte(secondBucketName), pb.PieceAction_GET, segment, inFiveMinutes)
require.NoError(t, err)
usage1, err := satelliteSys.DB.ProjectAccounting().GetProjectDailyUsageByDateRange(ctx, projectID, now, inFiveMinutes, 0)
require.NoError(t, err)
require.Equal(t, 2*segment, usage1.StorageUsage[0].Value)
require.Equal(t, 2*segment, usage1.AllocatedBandwidthUsage[0].Value)
require.Equal(t, 2*segment, usage1.SettledBandwidthUsage[0].Value)
},
)

View File

@ -119,7 +119,7 @@ export class ProjectsHttpApi implements ProjectsApi {
/**
* Get project limits.
*
* @param projectId- project ID
* @param projectId - project ID
* @throws Error
*/
public async getLimits(projectId: string): Promise<ProjectLimits> {
@ -179,9 +179,9 @@ export class ProjectsHttpApi implements ProjectsApi {
/**
* Get project daily usage for specific date range.
*
* @param projectId- project ID
* @param start- since date
* @param end- before date
* @param projectId - project ID
* @param start - since date
* @param end - before date
* @throws Error
*/
public async getDailyUsage(projectId: string, start: Date, end: Date): Promise<ProjectsStorageBandwidthDaily> {
@ -211,11 +211,6 @@ export class ProjectsHttpApi implements ProjectsApi {
date.setHours(0, 0, 0, 0);
return new DataStamp(el.value, date);
}),
usage.settledBandwidthUsage.map(el => {
const date = new Date(el.date);
date.setHours(0, 0, 0, 0);
return new DataStamp(el.value, date);
}),
);
}

View File

@ -23,21 +23,17 @@ import { ChartUtils } from '@/utils/chart';
import VChart from '@/components/common/VChart.vue';
const props = withDefaults(defineProps<{
settledData: DataStamp[],
allocatedData: DataStamp[],
data: DataStamp[],
since: Date,
before: Date,
width: number,
height: number,
isVuetify?: boolean,
}>(), {
settledData: () => [],
allocatedData: () => [],
data: () => [],
since: () => new Date(),
before: () => new Date(),
width: 0,
height: 0,
isVuetify: false,
});
const chartKey = ref<number>(0);
@ -46,14 +42,13 @@ const chartKey = ref<number>(0);
* Returns formatted data to render chart.
*/
const chartData = computed((): ChartData => {
const mainData: number[] = props.settledData.map(el => el.value);
const secondaryData: number[] = props.allocatedData.map(el => el.value);
const data: number[] = props.data.map(el => el.value);
const xAxisDateLabels: string[] = ChartUtils.daysDisplayedOnChart(props.since, props.before);
return {
labels: xAxisDateLabels,
datasets: [{
data: mainData,
data,
fill: true,
backgroundColor: 'rgba(226, 220, 255, .3)',
borderColor: '#7B61FF',
@ -66,20 +61,6 @@ const chartData = computed((): ChartData => {
pointBorderWidth: 1,
pointBackgroundColor: '#FFFFFF',
order: 0,
}, {
data: secondaryData,
fill: true,
backgroundColor: 'rgba(226, 220, 255, .7)',
borderColor: '#E2DCFF',
pointHoverBackgroundColor: '#FFFFFF',
pointBorderColor: '#E2DCFF',
pointHoverBorderWidth: 3,
hoverRadius: 8,
hitRadius: 3,
pointRadius: 2,
pointBorderWidth: 1,
pointBackgroundColor: '#FFFFFF',
order: 1,
}],
};
});
@ -88,27 +69,10 @@ const chartData = computed((): ChartData => {
* Used as constructor of custom tooltip.
*/
function tooltip(tooltipModel: TooltipModel<ChartType>): void {
if (!tooltipModel.dataPoints) {
const settledTooltip = Tooltip.createTooltip('settled-bandwidth-tooltip');
const allocatedTooltip = Tooltip.createTooltip('allocated-bandwidth-tooltip');
Tooltip.remove(settledTooltip);
Tooltip.remove(allocatedTooltip);
const tooltipParams = new TooltipParams(tooltipModel, 'bandwidth-chart', 'allocated-bandwidth-tooltip',
allocatedTooltipMarkUp(tooltipModel), 76, 81);
return;
}
tooltipModel.dataPoints.forEach(p => {
let tooltipParams: TooltipParams;
if (p.datasetIndex === 0) {
tooltipParams = new TooltipParams(tooltipModel, 'bandwidth-chart', 'settled-bandwidth-tooltip',
settledTooltipMarkUp(tooltipModel), -20, props.isVuetify ? 68 : 78);
} else {
tooltipParams = new TooltipParams(tooltipModel, 'bandwidth-chart', 'allocated-bandwidth-tooltip',
allocatedTooltipMarkUp(tooltipModel), 95, props.isVuetify ? 68 : 78);
}
Tooltip.custom(tooltipParams);
});
Tooltip.custom(tooltipParams);
}
/**
@ -120,65 +84,39 @@ function allocatedTooltipMarkUp(tooltipModel: TooltipModel<ChartType>): string {
}
const dataIndex = tooltipModel.dataPoints[0].dataIndex;
const dataPoint = new ChartTooltipData(props.allocatedData[dataIndex]);
const dataPoint = new ChartTooltipData(props.data[dataIndex]);
return `<div class='allocated-tooltip'>
<p class='settled-tooltip__title'>Allocated</p>
<p class='allocated-tooltip__value'>${dataPoint.date}<b class='allocated-tooltip__value__bold'> / ${dataPoint.value}</b></p>
<div class='allocated-tooltip__arrow'></div>
</div>`;
}
/**
* Returns settled bandwidth tooltip's html mark up.
*/
function settledTooltipMarkUp(tooltipModel: TooltipModel<ChartType>): string {
if (!tooltipModel.dataPoints) {
return '';
}
const dataIndex = tooltipModel.dataPoints[0].dataIndex;
const dataPoint = new ChartTooltipData(props.settledData[dataIndex]);
return `<div class='settled-tooltip'>
<div class='settled-tooltip__arrow'></div>
<p class='settled-tooltip__title'>Settled</p>
<p class='settled-tooltip__value'>${dataPoint.date}<b class='settled-tooltip__value__bold'> / ${dataPoint.value}</b></p>
</div>`;
}
watch(() => props.width, () => {
chartKey.value += 1;
});
</script>
<style lang="scss">
.settled-tooltip,
.allocated-tooltip {
margin: 8px;
position: relative;
border-radius: 14.5px;
box-shadow: 0 5px 14px rgb(9 87 203 / 26%);
border-radius: 100px;
padding-top: 8px;
width: 145px;
font-family: 'font_regular', sans-serif;
display: flex;
flex-direction: column;
align-items: center;
width: 120px;
&__title {
font-family: 'font_medium', sans-serif;
font-size: 14px;
line-height: 17px;
color: #fff;
align-self: flex-start;
}
background-color: var(--c-purple-3);
&__value {
font-size: 14px;
line-height: 26px;
text-align: center;
color: #fff;
color: var(--c-white);
white-space: nowrap;
align-self: flex-start;
&__bold {
font-family: 'font_medium', sans-serif;
@ -188,30 +126,10 @@ watch(() => props.width, () => {
&__arrow {
width: 12px;
height: 12px;
}
}
.settled-tooltip {
background-color: var(--c-purple-3);
padding: 4px 10px 8px;
&__arrow {
margin: -12px 0 4px;
border-radius: 0 0 0 8px;
transform: scale(1, 0.85) translate(0, 20%) rotate(-45deg);
border-radius: 8px 0 0;
transform: scale(1, 0.85) translate(0, 20%) rotate(45deg);
margin-bottom: -4px;
background-color: var(--c-purple-3);
}
}
.allocated-tooltip {
background-color: var(--c-purple-2);
padding: 8px 10px 0;
&__arrow {
margin-bottom: -4px;
border-radius: 8px 0 0;
transform: scale(1, 0.85) translate(0, 20%) rotate(45deg);
background-color: var(--c-purple-2);
}
}
</style>

View File

@ -67,16 +67,14 @@
<h3 class="project-dashboard__charts__container__header__title">Egress</h3>
<div class="project-dashboard__charts__container__header__right">
<span class="project-dashboard__charts__container__header__right__allocated-color" />
<p class="project-dashboard__charts__container__header__right__allocated-label">Allocated</p>
<span class="project-dashboard__charts__container__header__right__settled-color" />
<p class="project-dashboard__charts__container__header__right__settled-label">Settled</p>
<p class="project-dashboard__charts__container__header__right__allocated-label">Egress</p>
<VInfo class="project-dashboard__charts__container__header__right__info">
<template #icon>
<InfoIcon />
</template>
<template #message>
<p class="project-dashboard__charts__container__header__right__info__message">
The egress allocated takes few hours to be settled.
The most recent data points may change as traffic moves from "allocated" to "settled".
<a
class="project-dashboard__charts__container__header__right__info__message__link"
href="https://docs.storj.io/dcs/billing-payment-and-accounts-1/pricing/billing-and-payment#bandwidth-fee"
@ -93,13 +91,12 @@
<VLoader v-if="isDataFetching" class="project-dashboard__charts__container__loader" height="40px" width="40px" />
<template v-else>
<h2 class="project-dashboard__charts__container__dimension">
{{ getDimension([...settledBandwidthUsage, ...allocatedBandwidthUsage]) }}
{{ getDimension(allocatedBandwidthUsage) }}
</h2>
<BandwidthChart
:width="chartWidth"
:height="170"
:settled-data="settledBandwidthUsage"
:allocated-data="allocatedBandwidthUsage"
:data="allocatedBandwidthUsage"
:since="chartsSinceDate"
:before="chartsBeforeDate"
/>
@ -289,15 +286,6 @@ const storageUsage = computed((): DataStamp[] => {
);
});
/**
* Returns settled bandwidth chart data from store.
*/
const settledBandwidthUsage = computed((): DataStamp[] => {
return ChartUtils.populateEmptyUsage(
projectsStore.state.settledBandwidthChartData, chartsSinceDate.value, chartsBeforeDate.value,
);
});
/**
* Returns allocated bandwidth chart data from store.
*/
@ -540,7 +528,7 @@ onBeforeUnmount((): void => {
font-family: 'font_medium', sans-serif;
font-size: 16px;
line-height: 24px;
color: #000;
color: var(--c-black);
}
}
@ -567,7 +555,7 @@ onBeforeUnmount((): void => {
font-size: 24px;
line-height: 31px;
letter-spacing: -0.02em;
color: #000;
color: var(--c-black);
}
&__buttons {
@ -587,7 +575,7 @@ onBeforeUnmount((): void => {
&__container {
width: calc((100% - 20px) / 2);
background-color: #fff;
background-color: var(--c-white);
box-shadow: 0 0 32px rgb(0 0 0 / 4%);
border-radius: 10px;
@ -601,7 +589,7 @@ onBeforeUnmount((): void => {
font-family: 'font_medium', sans-serif;
font-size: 18px;
line-height: 27px;
color: #000;
color: var(--c-black);
}
&__right {
@ -609,49 +597,19 @@ onBeforeUnmount((): void => {
align-items: center;
margin: 16px 16px 0 0;
@media screen and (width <= 390px) {
flex-direction: column;
align-items: flex-end;
row-gap: 5px;
}
&__allocated-color,
&__settled-color {
&__allocated-color {
width: 10px;
height: 10px;
border-radius: 2px;
}
&__allocated-color {
background: var(--c-purple-2);
}
&__settled-color {
background: var(--c-purple-3);
}
&__allocated-label,
&__settled-label {
&__allocated-label {
font-size: 14px;
line-height: 17px;
color: #000;
color: var(--c-black);
margin-left: 5px;
}
&__allocated-label {
margin-right: 16px;
@media screen and (width <= 390px) {
margin-right: 0;
}
}
&__settled-label {
margin-right: 11px;
@media screen and (width <= 390px) {
margin-right: 0;
}
}
&__info {
@ -662,14 +620,14 @@ onBeforeUnmount((): void => {
font-size: 12px;
line-height: 18px;
text-align: center;
color: #fff;
color: var(--c-white);
&__link {
text-decoration: underline !important;
color: #fff;
color: var(--c-white);
&:visited {
color: #fff;
color: var(--c-white);
}
}
}
@ -692,7 +650,7 @@ onBeforeUnmount((): void => {
font-weight: 600;
font-size: 14px;
line-height: 20px;
color: #000;
color: var(--c-black);
}
}
}

View File

@ -114,7 +114,7 @@ watch(() => props.width, () => {
font-size: 14px;
line-height: 26px;
text-align: center;
color: #fff;
color: var(--c-white);
white-space: nowrap;
&__bold {

View File

@ -32,7 +32,6 @@ export class ProjectsState {
public cursor: ProjectsCursor = new ProjectsCursor();
public page: ProjectsPage = new ProjectsPage();
public allocatedBandwidthChartData: DataStamp[] = [];
public settledBandwidthChartData: DataStamp[] = [];
public storageChartData: DataStamp[] = [];
public chartDataSince: Date = new Date();
public chartDataBefore: Date = new Date();
@ -88,7 +87,6 @@ export const useProjectsStore = defineStore('projects', () => {
const usage: ProjectsStorageBandwidthDaily = await api.getDailyUsage(state.selectedProject.id, payload.since, payload.before);
state.allocatedBandwidthChartData = usage.allocatedBandwidth;
state.settledBandwidthChartData = usage.settledBandwidth;
state.storageChartData = usage.storage;
state.chartDataSince = payload.since;
state.chartDataBefore = payload.before;
@ -237,7 +235,6 @@ export const useProjectsStore = defineStore('projects', () => {
state.totalLimits = new ProjectLimits();
state.storageChartData = [];
state.allocatedBandwidthChartData = [];
state.settledBandwidthChartData = [];
state.chartDataSince = new Date();
state.chartDataBefore = new Date();
state.invitations = [];

View File

@ -236,7 +236,6 @@ export class ProjectsStorageBandwidthDaily {
public constructor(
public storage: DataStamp[] = [],
public allocatedBandwidth: DataStamp[] = [],
public settledBandwidth: DataStamp[] = [],
) {}
}

View File

@ -24,15 +24,13 @@
<v-col cols="12" md="6">
<v-card title="Bandwidth" variant="flat" :border="true" rounded="xlg">
<template v-if="!isDataFetching">
<h4 class="pl-4">{{ getDimension([...settledBandwidthUsage, ...allocatedBandwidthUsage]) }}</h4>
<h4 class="pl-4">{{ getDimension(allocatedBandwidthUsage) }}</h4>
<BandwidthChart
:width="chartWidth"
:height="170"
:settled-data="settledBandwidthUsage"
:allocated-data="allocatedBandwidthUsage"
:data="allocatedBandwidthUsage"
:since="chartsSinceDate"
:before="chartsBeforeDate"
is-vuetify
/>
</template>
</v-card>
@ -269,15 +267,6 @@ const storageUsage = computed((): DataStamp[] => {
);
});
/**
* Returns settled bandwidth chart data from store.
*/
const settledBandwidthUsage = computed((): DataStamp[] => {
return ChartUtils.populateEmptyUsage(
projectsStore.state.settledBandwidthChartData, chartsSinceDate.value, chartsBeforeDate.value,
);
});
/**
* Returns allocated bandwidth chart data from store.
*/