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:
parent
ec8f3b4528
commit
8f27425284
@ -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)
|
||||
},
|
||||
)
|
||||
|
@ -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);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
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);
|
||||
}
|
||||
const tooltipParams = new TooltipParams(tooltipModel, 'bandwidth-chart', 'allocated-bandwidth-tooltip',
|
||||
allocatedTooltipMarkUp(tooltipModel), 76, 81);
|
||||
|
||||
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);
|
||||
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);
|
||||
margin-bottom: -4px;
|
||||
background-color: var(--c-purple-3);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 = [];
|
||||
|
@ -236,7 +236,6 @@ export class ProjectsStorageBandwidthDaily {
|
||||
public constructor(
|
||||
public storage: DataStamp[] = [],
|
||||
public allocatedBandwidth: DataStamp[] = [],
|
||||
public settledBandwidth: DataStamp[] = [],
|
||||
) {}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user