add project usage to web app (#1669)
This commit is contained in:
parent
92c1121072
commit
bc7848fcaf
43
web/satellite/src/api/usage.ts
Normal file
43
web/satellite/src/api/usage.ts
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import apollo from '@/utils/apolloManager';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
// fetchProjectUsage retrieves total project usage for a given period
|
||||
export async function fetchProjectUsage(projectID: string, since: Date, before: Date): Promise<RequestResponse<ProjectUsage>> {
|
||||
let result: RequestResponse<ProjectUsage> = {
|
||||
errorMessage: '',
|
||||
isSuccess: false,
|
||||
data: {} as ProjectUsage
|
||||
};
|
||||
|
||||
let response: any = await apollo.query(
|
||||
{
|
||||
query: gql(`
|
||||
query {
|
||||
project(id: "${projectID}") {
|
||||
usage(since: "${since.toISOString()}", before: "${before.toISOString()}") {
|
||||
storage,
|
||||
egress,
|
||||
objectsCount,
|
||||
since,
|
||||
before
|
||||
}
|
||||
}
|
||||
}`
|
||||
),
|
||||
fetchPolicy: 'no-cache',
|
||||
errorPolicy: 'all'
|
||||
}
|
||||
);
|
||||
|
||||
if (response.errors) {
|
||||
result.errorMessage = response.errors[0].message;
|
||||
} else {
|
||||
result.isSuccess = true;
|
||||
result.data = response.data.project.usage;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
@ -32,16 +32,16 @@
|
||||
<div class="usage-report-container__main-area">
|
||||
<div class="usage-report-container__main-area__info-area">
|
||||
<div class="usage-report-container__main-area__info-area__item">
|
||||
<h1>Storage GB/H</h1>
|
||||
<h2>200.23</h2>
|
||||
<h1>Storage GB*H</h1>
|
||||
<h2>{{storage}}</h2>
|
||||
</div>
|
||||
<div class="usage-report-container__main-area__info-area__item">
|
||||
<h1>Egress GB/H</h1>
|
||||
<h2>944.23</h2>
|
||||
<h1>Egress GB</h1>
|
||||
<h2>{{egress}}</h2>
|
||||
</div>
|
||||
<div class="usage-report-container__main-area__info-area__item">
|
||||
<h1>Objects Count/H</h1>
|
||||
<h2>30 223</h2>
|
||||
<h1>Objects Count*H</h1>
|
||||
<h2>{{objectsCount}}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="usage-report-container__main-area__footer">
|
||||
@ -65,11 +65,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import ROUTES from '@/utils/constants/routerConstants';
|
||||
import Datepicker from '@/components/project/DatePicker.vue';
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import ROUTES from '@/utils/constants/routerConstants';
|
||||
import Datepicker from '@/components/project/DatePicker.vue';
|
||||
import { NOTIFICATION_ACTIONS, PROJECT_USAGE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
|
||||
@Component(
|
||||
@Component(
|
||||
{
|
||||
data: function () {
|
||||
const currentDate = new Date();
|
||||
@ -83,24 +84,29 @@
|
||||
dateRange: {
|
||||
startDate: previousDate,
|
||||
endDate: currentDate,
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
components: {
|
||||
Datepicker,
|
||||
},
|
||||
methods: {
|
||||
getDates: function(datesArray: string[]): void {
|
||||
getDates: async function(datesArray: string[]) {
|
||||
const firstDate = new Date(datesArray[0]);
|
||||
const secondDate = new Date(datesArray[1]);
|
||||
const isInverted = firstDate > secondDate;
|
||||
this.$data.dateRange.startDate = isInverted ? secondDate : firstDate;
|
||||
this.$data.dateRange.endDate = isInverted ? firstDate : secondDate;
|
||||
|
||||
const response = await this.$store.dispatch(PROJECT_USAGE_ACTIONS.FETCH, this.$data.dateRange);
|
||||
if (!response.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'Unable to fetch project usage');
|
||||
}
|
||||
},
|
||||
onBackClick: function (): void {
|
||||
this.$router.push(ROUTES.PROJECT_DETAILS);
|
||||
},
|
||||
onCurrentRollupClick: function (event: any) {
|
||||
onCurrentRollupClick: async function (event: any) {
|
||||
const currentDate = new Date();
|
||||
const previousDate = new Date();
|
||||
previousDate.setMonth(currentDate.getMonth() - 1);
|
||||
@ -108,8 +114,13 @@
|
||||
this.$data.dateRange.startDate = previousDate;
|
||||
this.$data.dateRange.endDate = currentDate;
|
||||
(this as any).onButtonClickAction(event);
|
||||
|
||||
const response = await this.$store.dispatch(PROJECT_USAGE_ACTIONS.FETCH, this.$data.dateRange);
|
||||
if (!response.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'Unable to fetch project usage');
|
||||
}
|
||||
},
|
||||
onPreviousRollupClick: function (event: any) {
|
||||
onPreviousRollupClick: async function (event: any) {
|
||||
const currentDate = new Date();
|
||||
const previousDate = new Date();
|
||||
currentDate.setMonth(currentDate.getMonth() - 1);
|
||||
@ -118,6 +129,11 @@
|
||||
this.$data.dateRange.startDate = previousDate;
|
||||
this.$data.dateRange.endDate = currentDate;
|
||||
(this as any).onButtonClickAction(event);
|
||||
|
||||
const response = await this.$store.dispatch(PROJECT_USAGE_ACTIONS.FETCH, this.$data.dateRange);
|
||||
if (!response.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'Unable to fetch project usage');
|
||||
}
|
||||
},
|
||||
onCustomDateClick: function (event: any) {
|
||||
(this as any).$refs.datePicker.showCheck();
|
||||
@ -148,6 +164,17 @@
|
||||
window.open(route.href, '_blank');
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
storage: function () {
|
||||
return this.$store.state.usageModule.projectUsage.storage.toPrecision(5);
|
||||
},
|
||||
egress: function () {
|
||||
return this.$store.state.usageModule.projectUsage.egress.toPrecision(5);
|
||||
},
|
||||
objectsCount: function () {
|
||||
return this.$store.state.usageModule.projectUsage.objectsCount.toPrecision(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -11,6 +11,7 @@ import { projectMembersModule } from '@/store/modules/projectMembers';
|
||||
import { notificationsModule } from '@/store/modules/notifications';
|
||||
import { appStateModule } from '@/store/modules/appState';
|
||||
import { apiKeysModule } from '@/store/modules/apiKeys';
|
||||
import { usageModule } from '@/store/modules/usage';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
@ -22,7 +23,8 @@ const store = new Vuex.Store({
|
||||
projectMembersModule,
|
||||
notificationsModule,
|
||||
appStateModule,
|
||||
apiKeysModule
|
||||
apiKeysModule,
|
||||
usageModule
|
||||
}
|
||||
});
|
||||
|
||||
|
36
web/satellite/src/store/modules/usage.ts
Normal file
36
web/satellite/src/store/modules/usage.ts
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2019 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import { PROJECT_USAGE_MUTATIONS } from '@/store/mutationConstants';
|
||||
import { PROJECT_USAGE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { fetchProjectUsage } from '@/api/usage';
|
||||
|
||||
export const usageModule = {
|
||||
state: {
|
||||
projectUsage: {storage: 0, egress: 0, objectsCount: 0} as ProjectUsage
|
||||
},
|
||||
mutations: {
|
||||
[PROJECT_USAGE_MUTATIONS.FETCH](state: any, projectUsage: ProjectUsage) {
|
||||
state.projectUsage = projectUsage;
|
||||
},
|
||||
[PROJECT_USAGE_MUTATIONS.CLEAR](state:any) {
|
||||
state.projectUsage = {storage: 0, egress: 0, objectsCount: 0} as ProjectUsage;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
[PROJECT_USAGE_ACTIONS.FETCH]: async function({commit, rootGetters}: any, {startDate, endDate}: any): Promise<RequestResponse<ProjectUsage>> {
|
||||
const projectID = rootGetters.selectedProject.id;
|
||||
|
||||
let result = await fetchProjectUsage(projectID, startDate, endDate);
|
||||
|
||||
if (result.isSuccess) {
|
||||
commit(PROJECT_USAGE_MUTATIONS.FETCH, result.data);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
[PROJECT_USAGE_ACTIONS.CLEAR]: function({commit}): void {
|
||||
commit(PROJECT_USAGE_MUTATIONS.CLEAR);
|
||||
}
|
||||
}
|
||||
};
|
@ -39,6 +39,11 @@ export const API_KEYS_MUTATIONS = {
|
||||
CLEAR: 'CLEAR_API_KEYS',
|
||||
};
|
||||
|
||||
export const PROJECT_USAGE_MUTATIONS = {
|
||||
FETCH: 'FETCH_PROJECT_USAGE',
|
||||
CLEAR: 'CLEAR_PROJECT_USAGE'
|
||||
};
|
||||
|
||||
export const NOTIFICATION_MUTATIONS = {
|
||||
ADD: 'ADD_NOTIFICATION',
|
||||
DELETE: 'DELETE_NOTIFICATION',
|
||||
|
9
web/satellite/src/types/projects.d.ts
vendored
9
web/satellite/src/types/projects.d.ts
vendored
@ -28,3 +28,12 @@ declare type TeamMemberModel = {
|
||||
}
|
||||
joinedAt: string,
|
||||
};
|
||||
|
||||
// ProjectUsage sums usage for given period
|
||||
declare type ProjectUsage = {
|
||||
storage: number,
|
||||
egress: number,
|
||||
objectsCount: number,
|
||||
since: Date,
|
||||
before: Date
|
||||
};
|
||||
|
@ -63,3 +63,8 @@ export const API_KEYS_ACTIONS = {
|
||||
TOGGLE_SELECTION: 'toggleAPIKeySelection',
|
||||
CLEAR_SELECTION: 'clearAPIKeySelection'
|
||||
};
|
||||
|
||||
export const PROJECT_USAGE_ACTIONS = {
|
||||
FETCH: 'fetchProjectUsage',
|
||||
CLEAR: 'clearProjectUsage',
|
||||
};
|
||||
|
@ -26,7 +26,8 @@ import {
|
||||
PROJETS_ACTIONS,
|
||||
PM_ACTIONS,
|
||||
USER_ACTIONS,
|
||||
API_KEYS_ACTIONS
|
||||
API_KEYS_ACTIONS,
|
||||
PROJECT_USAGE_ACTIONS
|
||||
} from '@/utils/constants/actionNames';
|
||||
import ROUTES from '@/utils/constants/routerConstants';
|
||||
import ProjectCreationSuccessPopup from '@/components/project/ProjectCreationSuccessPopup.vue';
|
||||
@ -66,6 +67,15 @@ import ProjectCreationSuccessPopup from '@/components/project/ProjectCreationSuc
|
||||
if (!keysResponse.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'Unable to fetch api keys');
|
||||
}
|
||||
|
||||
const currentDate = new Date();
|
||||
const previousDate = new Date();
|
||||
previousDate.setMonth(currentDate.getMonth() - 1);
|
||||
|
||||
const usageResponse = await this.$store.dispatch(PROJECT_USAGE_ACTIONS.FETCH, {startDate: previousDate, endDate: currentDate});
|
||||
if (!usageResponse.isSuccess) {
|
||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'Unable to fetch project usage');
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ProjectCreationSuccessPopup,
|
||||
|
Loading…
Reference in New Issue
Block a user