Commit a3a6a5c0 authored by Filipa Lacerda's avatar Filipa Lacerda

Adds total usage in storage quotas

Renders the storage usage total in the
usage quotas page
Updates the graphql query and adds it to the
vue application

Adds jsdoc to the query update function
parent d84472a1
<script>
import { GlLink } from '@gitlab/ui';
import Project from './project.vue';
import query from '../queries/storage.graphql';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import Icon from '~/vue_shared/components/icon.vue';
export default {
components: {
Project,
GlLink,
Icon,
},
props: {
namespacePath: {
type: String,
required: true,
},
helpPagePath: {
type: String,
required: true,
},
},
apollo: {
namespace: {
......@@ -20,8 +29,18 @@ export default {
fullPath: this.namespacePath,
};
},
/**
* `rootStorageStatistics` will be sent as null until an
* event happens to trigger the storage count.
* For that reason we have to verify if `storageSize` is sent or
* if we should render N/A
*/
update: data => ({
projects: data.namespace.projects.edges.map(({ node }) => node),
totalUsage:
data.namespace.rootStorageStatistics && data.namespace.rootStorageStatistics.storageSize
? numberToHumanSize(data.namespace.rootStorageStatistics.storageSize)
: 'N/A',
}),
},
},
......@@ -33,19 +52,40 @@ export default {
};
</script>
<template>
<div class="ci-table" role="grid">
<div
class="gl-responsive-table-row table-row-header bg-gray-light pl-2 border-top mt-3 lh-100"
role="row"
>
<div class="table-section section-70 font-weight-bold" role="columnheader">
{{ __('Project') }}
</div>
<div class="table-section section-30 font-weight-bold" role="columnheader">
{{ __('Usage') }}
<div>
<div class="pipeline-quota container-fluid">
<div class="row">
<div class="col-sm-6">
<strong>{{ s__('UsageQuota|Usage since') }}</strong>
<div>
<span class="js-total-usage">
{{ namespace.totalUsage }}
<gl-link
:href="helpPagePath"
target="_blank"
:aria-label="__('Usage quotas help link')"
>
<icon name="question" :size="12" />
</gl-link>
</span>
</div>
</div>
</div>
</div>
<div class="ci-table" role="grid">
<div
class="gl-responsive-table-row table-row-header bg-gray-light pl-2 border-top mt-3 lh-100"
role="row"
>
<div class="table-section section-70 font-weight-bold" role="columnheader">
{{ __('Project') }}
</div>
<div class="table-section section-30 font-weight-bold" role="columnheader">
{{ __('Usage') }}
</div>
</div>
<project v-for="project in namespace.projects" :key="project.id" :project="project" />
<project v-for="project in namespace.projects" :key="project.id" :project="project" />
</div>
</div>
</template>
......@@ -7,7 +7,7 @@ Vue.use(VueApollo);
export default () => {
const el = document.getElementById('js-storage-counter-app');
const { namespacePath } = el.dataset;
const { namespacePath, helpPagePath } = el.dataset;
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
......@@ -20,6 +20,7 @@ export default () => {
return h(App, {
props: {
namespacePath,
helpPagePath,
},
});
},
......
query getStorageCounter($fullPath: ID!) {
namespace(fullPath: $fullPath) {
id
rootStorageStatistics {
storageSize
}
projects(includeSubgroups: true) {
edges {
node {
......
......@@ -23,5 +23,5 @@
= render "namespaces/pipelines_quota/list",
locals: { namespace: @group, projects: @projects }
.tab-pane#storage-quota-tab
#js-storage-counter-app{ data: { namespace_path: @group.full_path } }
#js-storage-counter-app{ data: { namespace_path: @group.full_path, help_page_path: help_page_path('user/group', anchor: 'storage-usage-quota-starter')} }
---
title: Adds total usage information to the usage quotas page
merge_request:
author:
type: added
import { shallowMount } from '@vue/test-utils';
import StorageApp from 'ee/storage_counter/components/app.vue';
import Project from 'ee/storage_counter/components/project.vue';
import { projects } from '../data';
import { projects, withRootStorageStatistics } from '../data';
describe('Storage counter app', () => {
let wrapper;
......@@ -16,19 +16,47 @@ describe('Storage counter app', () => {
};
wrapper = shallowMount(StorageApp, {
propsData: { namespacePath: 'h5bp' },
propsData: { namespacePath: 'h5bp', helpPagePath: 'help' },
mocks: { $apollo },
sync: true,
});
}
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('renders the 2 projects', () => {
wrapper.setData({
namespace: projects,
});
});
it('renders the 2 projects', () => {
expect(wrapper.findAll(Project).length).toEqual(2);
});
describe('with rootStorageStatistics information', () => {
it('renders total usage', () => {
wrapper.setData({
namespace: withRootStorageStatistics,
});
expect(wrapper.find('.js-total-usage').text()).toContain(
withRootStorageStatistics.totalUsage,
);
});
});
describe('without rootStorageStatistics information', () => {
it('renders N/A', () => {
wrapper.setData({
namespace: projects,
});
expect(wrapper.find('.js-total-usage').text()).toContain('N/A');
});
});
});
// eslint-disable-next-line import/prefer-default-export
export const projects = {
totalUsage: 'N/A',
projects: [
{
id: '24',
......@@ -35,3 +35,7 @@ export const projects = {
},
],
};
export const withRootStorageStatistics = Object.assign({}, projects, {
totalUsage: 3261070,
});
......@@ -16553,6 +16553,9 @@ msgstr ""
msgid "Usage ping is not enabled"
msgstr ""
msgid "Usage quotas help link"
msgstr ""
msgid "Usage statistics"
msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment