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">
|
||||||
<div class="usage-report-container__main-area__info-area">
|
<div class="usage-report-container__main-area__info-area">
|
||||||
<div class="usage-report-container__main-area__info-area__item">
|
<div class="usage-report-container__main-area__info-area__item">
|
||||||
<h1>Storage GB/H</h1>
|
<h1>Storage GB*H</h1>
|
||||||
<h2>200.23</h2>
|
<h2>{{storage}}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="usage-report-container__main-area__info-area__item">
|
<div class="usage-report-container__main-area__info-area__item">
|
||||||
<h1>Egress GB/H</h1>
|
<h1>Egress GB</h1>
|
||||||
<h2>944.23</h2>
|
<h2>{{egress}}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="usage-report-container__main-area__info-area__item">
|
<div class="usage-report-container__main-area__info-area__item">
|
||||||
<h1>Objects Count/H</h1>
|
<h1>Objects Count*H</h1>
|
||||||
<h2>30 223</h2>
|
<h2>{{objectsCount}}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="usage-report-container__main-area__footer">
|
<div class="usage-report-container__main-area__footer">
|
||||||
@ -65,11 +65,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue } from 'vue-property-decorator';
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
import ROUTES from '@/utils/constants/routerConstants';
|
import ROUTES from '@/utils/constants/routerConstants';
|
||||||
import Datepicker from '@/components/project/DatePicker.vue';
|
import Datepicker from '@/components/project/DatePicker.vue';
|
||||||
|
import { NOTIFICATION_ACTIONS, PROJECT_USAGE_ACTIONS } from '@/utils/constants/actionNames';
|
||||||
|
|
||||||
@Component(
|
@Component(
|
||||||
{
|
{
|
||||||
data: function () {
|
data: function () {
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
@ -83,24 +84,29 @@
|
|||||||
dateRange: {
|
dateRange: {
|
||||||
startDate: previousDate,
|
startDate: previousDate,
|
||||||
endDate: currentDate,
|
endDate: currentDate,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Datepicker,
|
Datepicker,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getDates: function(datesArray: string[]): void {
|
getDates: async function(datesArray: string[]) {
|
||||||
const firstDate = new Date(datesArray[0]);
|
const firstDate = new Date(datesArray[0]);
|
||||||
const secondDate = new Date(datesArray[1]);
|
const secondDate = new Date(datesArray[1]);
|
||||||
const isInverted = firstDate > secondDate;
|
const isInverted = firstDate > secondDate;
|
||||||
this.$data.dateRange.startDate = isInverted ? secondDate : firstDate;
|
this.$data.dateRange.startDate = isInverted ? secondDate : firstDate;
|
||||||
this.$data.dateRange.endDate = isInverted ? firstDate : secondDate;
|
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 {
|
onBackClick: function (): void {
|
||||||
this.$router.push(ROUTES.PROJECT_DETAILS);
|
this.$router.push(ROUTES.PROJECT_DETAILS);
|
||||||
},
|
},
|
||||||
onCurrentRollupClick: function (event: any) {
|
onCurrentRollupClick: async function (event: any) {
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const previousDate = new Date();
|
const previousDate = new Date();
|
||||||
previousDate.setMonth(currentDate.getMonth() - 1);
|
previousDate.setMonth(currentDate.getMonth() - 1);
|
||||||
@ -108,8 +114,13 @@
|
|||||||
this.$data.dateRange.startDate = previousDate;
|
this.$data.dateRange.startDate = previousDate;
|
||||||
this.$data.dateRange.endDate = currentDate;
|
this.$data.dateRange.endDate = currentDate;
|
||||||
(this as any).onButtonClickAction(event);
|
(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 currentDate = new Date();
|
||||||
const previousDate = new Date();
|
const previousDate = new Date();
|
||||||
currentDate.setMonth(currentDate.getMonth() - 1);
|
currentDate.setMonth(currentDate.getMonth() - 1);
|
||||||
@ -118,6 +129,11 @@
|
|||||||
this.$data.dateRange.startDate = previousDate;
|
this.$data.dateRange.startDate = previousDate;
|
||||||
this.$data.dateRange.endDate = currentDate;
|
this.$data.dateRange.endDate = currentDate;
|
||||||
(this as any).onButtonClickAction(event);
|
(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) {
|
onCustomDateClick: function (event: any) {
|
||||||
(this as any).$refs.datePicker.showCheck();
|
(this as any).$refs.datePicker.showCheck();
|
||||||
@ -148,6 +164,17 @@
|
|||||||
window.open(route.href, '_blank');
|
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 { notificationsModule } from '@/store/modules/notifications';
|
||||||
import { appStateModule } from '@/store/modules/appState';
|
import { appStateModule } from '@/store/modules/appState';
|
||||||
import { apiKeysModule } from '@/store/modules/apiKeys';
|
import { apiKeysModule } from '@/store/modules/apiKeys';
|
||||||
|
import { usageModule } from '@/store/modules/usage';
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
|
|
||||||
@ -22,7 +23,8 @@ const store = new Vuex.Store({
|
|||||||
projectMembersModule,
|
projectMembersModule,
|
||||||
notificationsModule,
|
notificationsModule,
|
||||||
appStateModule,
|
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',
|
CLEAR: 'CLEAR_API_KEYS',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const PROJECT_USAGE_MUTATIONS = {
|
||||||
|
FETCH: 'FETCH_PROJECT_USAGE',
|
||||||
|
CLEAR: 'CLEAR_PROJECT_USAGE'
|
||||||
|
};
|
||||||
|
|
||||||
export const NOTIFICATION_MUTATIONS = {
|
export const NOTIFICATION_MUTATIONS = {
|
||||||
ADD: 'ADD_NOTIFICATION',
|
ADD: 'ADD_NOTIFICATION',
|
||||||
DELETE: 'DELETE_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,
|
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',
|
TOGGLE_SELECTION: 'toggleAPIKeySelection',
|
||||||
CLEAR_SELECTION: 'clearAPIKeySelection'
|
CLEAR_SELECTION: 'clearAPIKeySelection'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const PROJECT_USAGE_ACTIONS = {
|
||||||
|
FETCH: 'fetchProjectUsage',
|
||||||
|
CLEAR: 'clearProjectUsage',
|
||||||
|
};
|
||||||
|
@ -26,7 +26,8 @@ import {
|
|||||||
PROJETS_ACTIONS,
|
PROJETS_ACTIONS,
|
||||||
PM_ACTIONS,
|
PM_ACTIONS,
|
||||||
USER_ACTIONS,
|
USER_ACTIONS,
|
||||||
API_KEYS_ACTIONS
|
API_KEYS_ACTIONS,
|
||||||
|
PROJECT_USAGE_ACTIONS
|
||||||
} from '@/utils/constants/actionNames';
|
} from '@/utils/constants/actionNames';
|
||||||
import ROUTES from '@/utils/constants/routerConstants';
|
import ROUTES from '@/utils/constants/routerConstants';
|
||||||
import ProjectCreationSuccessPopup from '@/components/project/ProjectCreationSuccessPopup.vue';
|
import ProjectCreationSuccessPopup from '@/components/project/ProjectCreationSuccessPopup.vue';
|
||||||
@ -66,6 +67,15 @@ import ProjectCreationSuccessPopup from '@/components/project/ProjectCreationSuc
|
|||||||
if (!keysResponse.isSuccess) {
|
if (!keysResponse.isSuccess) {
|
||||||
this.$store.dispatch(NOTIFICATION_ACTIONS.ERROR, 'Unable to fetch api keys');
|
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: {
|
components: {
|
||||||
ProjectCreationSuccessPopup,
|
ProjectCreationSuccessPopup,
|
||||||
|
Loading…
Reference in New Issue
Block a user