satellite/{console, web}: detailed usage report for a single project
Reworked usage report endpoint to return CSV for a single OR all the project user owns. Added buttons to download usage report CSV for a single project. Issue: https://github.com/storj/storj/issues/6154 Change-Id: I55104088180dcf6be49dcde6c9c495f07ba01c5a
This commit is contained in:
parent
f0f73fc8ae
commit
f6e357be52
@ -165,9 +165,17 @@ type BucketUsageRollup struct {
|
|||||||
Before time.Time `json:"before"`
|
Before time.Time `json:"before"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectBucketUsageRollup is total bucket usage info with project details for certain period.
|
||||||
|
type ProjectBucketUsageRollup struct {
|
||||||
|
ProjectName string `json:"projectName"`
|
||||||
|
|
||||||
|
BucketUsageRollup
|
||||||
|
}
|
||||||
|
|
||||||
// ToStringSlice converts rollup values to a slice of strings.
|
// ToStringSlice converts rollup values to a slice of strings.
|
||||||
func (b *BucketUsageRollup) ToStringSlice() []string {
|
func (b *ProjectBucketUsageRollup) ToStringSlice() []string {
|
||||||
return []string{
|
return []string{
|
||||||
|
b.ProjectName,
|
||||||
b.ProjectID.String(),
|
b.ProjectID.String(),
|
||||||
b.BucketName,
|
b.BucketName,
|
||||||
fmt.Sprintf("%f", b.TotalStoredData),
|
fmt.Sprintf("%f", b.TotalStoredData),
|
||||||
|
@ -106,8 +106,8 @@ func (ul *UsageLimits) TotalUsageLimits(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalUsageReport returns total usage report for all the projects that user owns.
|
// UsageReport returns usage report for all the projects that user owns or a single user's project.
|
||||||
func (ul *UsageLimits) TotalUsageReport(w http.ResponseWriter, r *http.Request) {
|
func (ul *UsageLimits) UsageReport(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
var err error
|
var err error
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
@ -126,7 +126,18 @@ func (ul *UsageLimits) TotalUsageReport(w http.ResponseWriter, r *http.Request)
|
|||||||
since := time.Unix(sinceStamp, 0).UTC()
|
since := time.Unix(sinceStamp, 0).UTC()
|
||||||
before := time.Unix(beforeStamp, 0).UTC()
|
before := time.Unix(beforeStamp, 0).UTC()
|
||||||
|
|
||||||
usage, err := ul.service.GetTotalUsageReport(ctx, since, before)
|
var projectID uuid.UUID
|
||||||
|
|
||||||
|
idParam := r.URL.Query().Get("projectID")
|
||||||
|
if idParam != "" {
|
||||||
|
projectID, err = uuid.FromString(idParam)
|
||||||
|
if err != nil {
|
||||||
|
ul.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("invalid project id: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usage, err := ul.service.GetUsageReport(ctx, since, before, projectID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if console.ErrUnauthorized.Has(err) {
|
if console.ErrUnauthorized.Has(err) {
|
||||||
ul.serveJSONError(ctx, w, http.StatusUnauthorized, err)
|
ul.serveJSONError(ctx, w, http.StatusUnauthorized, err)
|
||||||
@ -137,14 +148,15 @@ func (ul *UsageLimits) TotalUsageReport(w http.ResponseWriter, r *http.Request)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName := "storj-report-" + since.Format("2006-01-02") + "-to-" + before.Format("2006-01-02") + ".csv"
|
dateFormat := "2006-01-02"
|
||||||
|
fileName := "storj-report-" + idParam + "-" + since.Format(dateFormat) + "-to-" + before.Format(dateFormat) + ".csv"
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/csv")
|
w.Header().Set("Content-Type", "text/csv")
|
||||||
w.Header().Set("Content-Disposition", "attachment;filename="+fileName)
|
w.Header().Set("Content-Disposition", "attachment;filename="+fileName)
|
||||||
|
|
||||||
wr := csv.NewWriter(w)
|
wr := csv.NewWriter(w)
|
||||||
|
|
||||||
csvHeaders := []string{"ProjectID", "BucketName", "TotalStoredData GB-hour", "TotalSegments GB-hour", "ObjectCount GB-hour", "MetadataSize GB-hour", "RepairEgress GB", "GetEgress GB", "AuditEgress GB", "Since", "Before"}
|
csvHeaders := []string{"ProjectName", "ProjectID", "BucketName", "TotalStoredData GB-hour", "TotalSegments GB-hour", "ObjectCount GB-hour", "MetadataSize GB-hour", "RepairEgress GB", "GetEgress GB", "AuditEgress GB", "Since", "Before"}
|
||||||
|
|
||||||
err = wr.Write(csvHeaders)
|
err = wr.Write(csvHeaders)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -235,29 +235,48 @@ func Test_TotalUsageReport(t *testing.T) {
|
|||||||
err = satelliteSys.DB.ProjectAccounting().SaveTallies(ctx, inFiveMinutes, bucketTallies)
|
err = satelliteSys.DB.ProjectAccounting().SaveTallies(ctx, inFiveMinutes, bucketTallies)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
endpoint := fmt.Sprintf("projects/total-usage-report?since=%s&before=%s", since, before)
|
endpoint := fmt.Sprintf("projects/usage-report?since=%s&before=%s&projectID=", since, before)
|
||||||
body, status, err := doRequestWithAuth(ctx, t, satelliteSys, user, http.MethodGet, endpoint, nil)
|
body, status, err := doRequestWithAuth(ctx, t, satelliteSys, user, http.MethodGet, endpoint, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, http.StatusOK, status)
|
require.Equal(t, http.StatusOK, status)
|
||||||
|
|
||||||
content := string(body)
|
reader := csv.NewReader(strings.NewReader(string(body)))
|
||||||
reader := csv.NewReader(strings.NewReader(content))
|
|
||||||
records, err := reader.ReadAll()
|
records, err := reader.ReadAll()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, records, 3)
|
require.Len(t, records, 3)
|
||||||
|
|
||||||
expectedHeaders := []string{"ProjectID", "BucketName", "TotalStoredData GB-hour", "TotalSegments GB-hour", "ObjectCount GB-hour", "MetadataSize GB-hour", "RepairEgress GB", "GetEgress GB", "AuditEgress GB", "Since", "Before"}
|
expectedHeaders := []string{"ProjectName", "ProjectID", "BucketName", "TotalStoredData GB-hour", "TotalSegments GB-hour", "ObjectCount GB-hour", "MetadataSize GB-hour", "RepairEgress GB", "GetEgress GB", "AuditEgress GB", "Since", "Before"}
|
||||||
for i, header := range expectedHeaders {
|
for i, header := range expectedHeaders {
|
||||||
require.Equal(t, header, records[0][i])
|
require.Equal(t, header, records[0][i])
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, project1.PublicID.String(), records[1][0])
|
require.Equal(t, project1.Name, records[1][0])
|
||||||
require.Equal(t, project2.PublicID.String(), records[2][0])
|
require.Equal(t, project2.Name, records[2][0])
|
||||||
require.Equal(t, bucketName, records[1][1])
|
require.Equal(t, project1.PublicID.String(), records[1][1])
|
||||||
require.Equal(t, bucketName, records[2][1])
|
require.Equal(t, project2.PublicID.String(), records[2][1])
|
||||||
for i := 2; i < 9; i++ {
|
require.Equal(t, bucketName, records[1][2])
|
||||||
|
require.Equal(t, bucketName, records[2][2])
|
||||||
|
for i := 3; i < 10; i++ {
|
||||||
require.Equal(t, expectedCSVValue, records[1][i])
|
require.Equal(t, expectedCSVValue, records[1][i])
|
||||||
require.Equal(t, expectedCSVValue, records[2][i])
|
require.Equal(t, expectedCSVValue, records[2][i])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
endpoint = fmt.Sprintf("projects/usage-report?since=%s&before=%s&projectID=%s", since, before, project1.PublicID)
|
||||||
|
body, status, err = doRequestWithAuth(ctx, t, satelliteSys, user, http.MethodGet, endpoint, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, http.StatusOK, status)
|
||||||
|
|
||||||
|
reader = csv.NewReader(strings.NewReader(string(body)))
|
||||||
|
records, err = reader.ReadAll()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, records, 2)
|
||||||
|
|
||||||
|
require.Equal(t, project1.Name, records[1][0])
|
||||||
|
require.Equal(t, project1.PublicID.String(), records[1][1])
|
||||||
|
require.Equal(t, bucketName, records[1][2])
|
||||||
|
|
||||||
|
for i := 3; i < 10; i++ {
|
||||||
|
require.Equal(t, expectedCSVValue, records[1][i])
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -297,7 +297,7 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, oidc
|
|||||||
projectsRouter.Handle("/{id}/usage-limits", http.HandlerFunc(usageLimitsController.ProjectUsageLimits)).Methods(http.MethodGet, http.MethodOptions)
|
projectsRouter.Handle("/{id}/usage-limits", http.HandlerFunc(usageLimitsController.ProjectUsageLimits)).Methods(http.MethodGet, http.MethodOptions)
|
||||||
projectsRouter.Handle("/usage-limits", http.HandlerFunc(usageLimitsController.TotalUsageLimits)).Methods(http.MethodGet, http.MethodOptions)
|
projectsRouter.Handle("/usage-limits", http.HandlerFunc(usageLimitsController.TotalUsageLimits)).Methods(http.MethodGet, http.MethodOptions)
|
||||||
projectsRouter.Handle("/{id}/daily-usage", http.HandlerFunc(usageLimitsController.DailyUsage)).Methods(http.MethodGet, http.MethodOptions)
|
projectsRouter.Handle("/{id}/daily-usage", http.HandlerFunc(usageLimitsController.DailyUsage)).Methods(http.MethodGet, http.MethodOptions)
|
||||||
projectsRouter.Handle("/total-usage-report", http.HandlerFunc(usageLimitsController.TotalUsageReport)).Methods(http.MethodGet, http.MethodOptions)
|
projectsRouter.Handle("/usage-report", http.HandlerFunc(usageLimitsController.UsageReport)).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
authController := consoleapi.NewAuth(logger, service, accountFreezeService, mailService, server.cookieAuth, server.analytics, config.SatelliteName, server.config.ExternalAddress, config.LetUsKnowURL, config.TermsAndConditionsURL, config.ContactInfoURL, config.GeneralRequestURL)
|
authController := consoleapi.NewAuth(logger, service, accountFreezeService, mailService, server.cookieAuth, server.analytics, config.SatelliteName, server.config.ExternalAddress, config.LetUsKnowURL, config.TermsAndConditionsURL, config.ContactInfoURL, config.GeneralRequestURL)
|
||||||
authRouter := router.PathPrefix("/api/v0/auth").Subrouter()
|
authRouter := router.PathPrefix("/api/v0/auth").Subrouter()
|
||||||
|
@ -2723,22 +2723,35 @@ func (s *Service) GetAllBucketNames(ctx context.Context, projectID uuid.UUID) (_
|
|||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTotalUsageReport retrieves usage rollups for every bucket of all user owned projects for a given period.
|
// GetUsageReport retrieves usage rollups for every bucket of a single or all the user owned projects for a given period.
|
||||||
func (s *Service) GetTotalUsageReport(ctx context.Context, since, before time.Time) ([]accounting.BucketUsageRollup, error) {
|
func (s *Service) GetUsageReport(ctx context.Context, since, before time.Time, projectID uuid.UUID) ([]accounting.ProjectBucketUsageRollup, error) {
|
||||||
var err error
|
var err error
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
user, err := s.getUserAndAuditLog(ctx, "get user report")
|
user, err := s.getUserAndAuditLog(ctx, "get usage report")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Error.Wrap(err)
|
return nil, Error.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
projects, err := s.store.Projects().GetOwn(ctx, user.ID)
|
var projects []Project
|
||||||
|
|
||||||
|
if projectID.IsZero() {
|
||||||
|
pr, err := s.store.Projects().GetOwn(ctx, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Error.Wrap(err)
|
return nil, Error.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
usage := make([]accounting.BucketUsageRollup, 0)
|
projects = append(projects, pr...)
|
||||||
|
} else {
|
||||||
|
_, pr, err := s.isProjectOwner(ctx, user.ID, projectID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrUnauthorized.Wrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
projects = append(projects, *pr)
|
||||||
|
}
|
||||||
|
|
||||||
|
usage := make([]accounting.ProjectBucketUsageRollup, 0)
|
||||||
|
|
||||||
for _, p := range projects {
|
for _, p := range projects {
|
||||||
rollups, err := s.projectAccounting.GetBucketUsageRollups(ctx, p.ID, since, before)
|
rollups, err := s.projectAccounting.GetBucketUsageRollups(ctx, p.ID, since, before)
|
||||||
@ -2746,9 +2759,23 @@ func (s *Service) GetTotalUsageReport(ctx context.Context, since, before time.Ti
|
|||||||
return nil, Error.Wrap(err)
|
return nil, Error.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range rollups {
|
for _, r := range rollups {
|
||||||
rollups[i].ProjectID = p.PublicID
|
usage = append(usage, accounting.ProjectBucketUsageRollup{
|
||||||
usage = append(usage, rollups[i])
|
ProjectName: p.Name,
|
||||||
|
BucketUsageRollup: accounting.BucketUsageRollup{
|
||||||
|
ProjectID: p.PublicID,
|
||||||
|
BucketName: r.BucketName,
|
||||||
|
TotalStoredData: r.TotalStoredData,
|
||||||
|
TotalSegments: r.TotalSegments,
|
||||||
|
ObjectCount: r.ObjectCount,
|
||||||
|
MetadataSize: r.MetadataSize,
|
||||||
|
RepairEgress: r.RepairEgress,
|
||||||
|
GetEgress: r.GetEgress,
|
||||||
|
AuditEgress: r.AuditEgress,
|
||||||
|
Since: r.Since,
|
||||||
|
Before: r.Before,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,10 +204,10 @@ export class ProjectsHttpApi implements ProjectsApi {
|
|||||||
*
|
*
|
||||||
* @throws Error
|
* @throws Error
|
||||||
*/
|
*/
|
||||||
public getTotalUsageReportLink(start: Date, end: Date): string {
|
public getTotalUsageReportLink(start: Date, end: Date, projectID: string): string {
|
||||||
const since = Time.toUnixTimestamp(start).toString();
|
const since = Time.toUnixTimestamp(start).toString();
|
||||||
const before = Time.toUnixTimestamp(end).toString();
|
const before = Time.toUnixTimestamp(end).toString();
|
||||||
return `${this.ROOT_PATH}/total-usage-report?since=${since}&before=${before}`;
|
return `${this.ROOT_PATH}/usage-report?since=${since}&before=${before}&projectID=${projectID}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,8 +187,9 @@ function balanceClicked(): void {
|
|||||||
* Handles download usage report click logic.
|
* Handles download usage report click logic.
|
||||||
*/
|
*/
|
||||||
function downloadUsageReport(): void {
|
function downloadUsageReport(): void {
|
||||||
const link = projectsStore.getTotalUsageReportLink();
|
const link = projectsStore.getUsageReportLink();
|
||||||
Download.fileByLink(link);
|
Download.fileByLink(link);
|
||||||
|
notify.success('Usage report download started successfully.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +51,15 @@
|
|||||||
<p class="price">{{ centsToDollars(charge.segmentPrice) }}</p>
|
<p class="price">{{ centsToDollars(charge.segmentPrice) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<v-button
|
||||||
|
class="usage-charges-item-container__detailed-info-container__btn"
|
||||||
|
label="Download Report"
|
||||||
|
width="140px"
|
||||||
|
height="30px"
|
||||||
|
font-size="14px"
|
||||||
|
is-transparent
|
||||||
|
:on-press="downloadUsageReport"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@ -66,6 +75,10 @@ import { Size } from '@/utils/bytesSize';
|
|||||||
import { SHORT_MONTHS_NAMES } from '@/utils/constants/date';
|
import { SHORT_MONTHS_NAMES } from '@/utils/constants/date';
|
||||||
import { useBillingStore } from '@/store/modules/billingStore';
|
import { useBillingStore } from '@/store/modules/billingStore';
|
||||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||||
|
import { Download } from '@/utils/download';
|
||||||
|
import { useNotify } from '@/utils/hooks';
|
||||||
|
|
||||||
|
import VButton from '@/components/common/VButton.vue';
|
||||||
|
|
||||||
import GreyChevron from '@/../static/images/common/greyChevron.svg';
|
import GreyChevron from '@/../static/images/common/greyChevron.svg';
|
||||||
|
|
||||||
@ -86,6 +99,8 @@ const props = withDefaults(defineProps<{
|
|||||||
const billingStore = useBillingStore();
|
const billingStore = useBillingStore();
|
||||||
const projectsStore = useProjectsStore();
|
const projectsStore = useProjectsStore();
|
||||||
|
|
||||||
|
const notify = useNotify();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* isDetailedInfoShown indicates if area with detailed information about project charges is expanded.
|
* isDetailedInfoShown indicates if area with detailed information about project charges is expanded.
|
||||||
*/
|
*/
|
||||||
@ -118,6 +133,15 @@ const projectCharges = computed((): ProjectCharges => {
|
|||||||
return billingStore.state.projectCharges as ProjectCharges;
|
return billingStore.state.projectCharges as ProjectCharges;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles download usage report click logic.
|
||||||
|
*/
|
||||||
|
function downloadUsageReport(): void {
|
||||||
|
const link = projectsStore.getUsageReportLink(props.projectId);
|
||||||
|
Download.fileByLink(link);
|
||||||
|
notify.success('Usage report download started successfully.');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns project usage price model from store.
|
* Returns project usage price model from store.
|
||||||
*/
|
*/
|
||||||
@ -325,6 +349,10 @@ function toggleDetailedInfo(): void {
|
|||||||
width: 40%;
|
width: 40%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__btn {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,12 +49,12 @@ export const useProjectsStore = defineStore('projects', () => {
|
|||||||
|
|
||||||
const api: ProjectsApi = new ProjectsHttpApi();
|
const api: ProjectsApi = new ProjectsHttpApi();
|
||||||
|
|
||||||
function getTotalUsageReportLink(): string {
|
function getUsageReportLink(projectID = ''): string {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const endUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes()));
|
const endUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes()));
|
||||||
const startUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1, 0, 0));
|
const startUTC = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1, 0, 0));
|
||||||
|
|
||||||
return api.getTotalUsageReportLink(startUTC, endUTC);
|
return api.getTotalUsageReportLink(startUTC, endUTC, projectID);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getProjects(): Promise<Project[]> {
|
async function getProjects(): Promise<Project[]> {
|
||||||
@ -349,7 +349,7 @@ export const useProjectsStore = defineStore('projects', () => {
|
|||||||
requestLimitIncrease,
|
requestLimitIncrease,
|
||||||
getProjectLimits,
|
getProjectLimits,
|
||||||
getTotalLimits,
|
getTotalLimits,
|
||||||
getTotalUsageReportLink,
|
getUsageReportLink,
|
||||||
getProjectSalt,
|
getProjectSalt,
|
||||||
getUserInvitations,
|
getUserInvitations,
|
||||||
respondToInvitation,
|
respondToInvitation,
|
||||||
|
@ -69,7 +69,7 @@ export interface ProjectsApi {
|
|||||||
*
|
*
|
||||||
* @throws Error
|
* @throws Error
|
||||||
*/
|
*/
|
||||||
getTotalUsageReportLink(start: Date, end: Date): string
|
getTotalUsageReportLink(start: Date, end: Date, projectID: string): string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get project daily usage by specific date range.
|
* Get project daily usage by specific date range.
|
||||||
|
@ -63,6 +63,9 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</v-table>
|
</v-table>
|
||||||
|
<v-btn class="mt-4 ml-4" variant="outlined" color="default" size="small" @click="downloadReport">
|
||||||
|
Download Report
|
||||||
|
</v-btn>
|
||||||
</v-expansion-panel-text>
|
</v-expansion-panel-text>
|
||||||
</v-expansion-panel>
|
</v-expansion-panel>
|
||||||
</v-expansion-panels>
|
</v-expansion-panels>
|
||||||
@ -72,6 +75,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import {
|
import {
|
||||||
|
VBtn,
|
||||||
VCard,
|
VCard,
|
||||||
VCol,
|
VCol,
|
||||||
VExpansionPanel,
|
VExpansionPanel,
|
||||||
@ -89,6 +93,8 @@ import { Size } from '@/utils/bytesSize';
|
|||||||
import { SHORT_MONTHS_NAMES } from '@/utils/constants/date';
|
import { SHORT_MONTHS_NAMES } from '@/utils/constants/date';
|
||||||
import { useBillingStore } from '@/store/modules/billingStore';
|
import { useBillingStore } from '@/store/modules/billingStore';
|
||||||
import { useProjectsStore } from '@/store/modules/projectsStore';
|
import { useProjectsStore } from '@/store/modules/projectsStore';
|
||||||
|
import { Download } from '@/utils/download';
|
||||||
|
import { useNotify } from '@/utils/hooks';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HOURS_IN_MONTH constant shows amount of hours in 30-day month.
|
* HOURS_IN_MONTH constant shows amount of hours in 30-day month.
|
||||||
@ -107,6 +113,8 @@ const props = withDefaults(defineProps<{
|
|||||||
const billingStore = useBillingStore();
|
const billingStore = useBillingStore();
|
||||||
const projectsStore = useProjectsStore();
|
const projectsStore = useProjectsStore();
|
||||||
|
|
||||||
|
const notify = useNotify();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of tuples containing the partner name and usage charge for the specified project ID.
|
* An array of tuples containing the partner name and usage charge for the specified project ID.
|
||||||
*/
|
*/
|
||||||
@ -134,6 +142,15 @@ const projectCharges = computed((): ProjectCharges => {
|
|||||||
return billingStore.state.projectCharges as ProjectCharges;
|
return billingStore.state.projectCharges as ProjectCharges;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles download usage report click logic.
|
||||||
|
*/
|
||||||
|
function downloadReport(): void {
|
||||||
|
const link = projectsStore.getUsageReportLink(props.projectId);
|
||||||
|
Download.fileByLink(link);
|
||||||
|
notify.success('Usage report download started successfully.');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns project usage price model from store.
|
* Returns project usage price model from store.
|
||||||
*/
|
*/
|
||||||
|
@ -330,8 +330,9 @@ const isCouponActive = computed((): boolean => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function downloadReport(): void {
|
function downloadReport(): void {
|
||||||
const link = projectsStore.getTotalUsageReportLink();
|
const link = projectsStore.getUsageReportLink();
|
||||||
Download.fileByLink(link);
|
Download.fileByLink(link);
|
||||||
|
notify.success('Usage report download started successfully.');
|
||||||
}
|
}
|
||||||
|
|
||||||
function goToTransactionsTab() {
|
function goToTransactionsTab() {
|
||||||
|
Loading…
Reference in New Issue
Block a user