Commit 4dd1fd94 authored by Angelo Gulina's avatar Angelo Gulina Committed by Savas Vedova

Add Subscription details components

Prepare components for Subscription Details view
Add all the required translation strings
parent beba9e68
<script>
import { GlCard } from '@gitlab/ui';
import { detailsLabels } from '../constants';
import SubscriptionDetailsTable from './subscription_details_table.vue';
export default {
name: 'SubscriptionDetailsCard',
components: {
SubscriptionDetailsTable,
GlCard,
},
props: {
detailsFields: {
type: Array,
required: true,
},
headerText: {
type: String,
required: false,
default: '',
},
subscription: {
type: Object,
required: true,
},
},
computed: {
details() {
if (!Object.keys(this.subscription).length) {
return [];
}
return this.detailsFields.map((detail) => ({
canCopy: detail === 'id',
label: detailsLabels[detail],
value: this.subscription[detail],
}));
},
},
};
</script>
<template>
<gl-card>
<template v-if="headerText" #header>
<h6 class="gl-m-0">{{ headerText }}</h6>
</template>
<subscription-details-table :details="details" />
<template #footer>
<slot name="footer"></slot>
</template>
</gl-card>
</template>
<script>
import { GlSkeletonLoader } from '@gitlab/ui';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { copySubscriptionIdButtonText } from '../constants';
export default {
i18n: {
copySubscriptionIdButtonText,
},
name: 'SubscriptionDetailsTable',
components: {
ClipboardButton,
GlSkeletonLoader,
},
props: {
details: {
type: Array,
required: true,
},
},
methods: {
isNotLast(index) {
return index < this.details.length - 1;
},
},
};
</script>
<template>
<div v-if="!details.length">
<gl-skeleton-loader :lines="1" />
<gl-skeleton-loader :lines="1" />
</div>
<ul v-else class="gl-list-style-none gl-m-0 gl-p-0">
<li
v-for="(detail, index) in details"
:key="detail.label"
:class="{ 'gl-mb-3': isNotLast(index) }"
class="gl-display-flex"
>
<p class="gl-font-weight-bold gl-m-0" data-testid="details-label">{{ detail.label }}:</p>
<p class="gl-m-0 gl-ml-4" data-testid="details-content">{{ detail.value }}</p>
<clipboard-button
v-if="detail.canCopy"
:text="detail.value"
:title="$options.i18n.copySubscriptionIdButtonText"
category="tertiary"
class="gl-ml-2"
size="small"
/>
</li>
</ul>
</template>
import { __, s__ } from '~/locale';
export const subscriptionDetailsHeaderText = s__('CloudLicense|Subscription details');
export const licensedToHeaderText = s__('CloudLicense|Licensed to');
export const manageSubscriptionButtonText = s__('CloudLicense|Manage');
export const syncSubscriptionButtonText = s__('CloudLicense|Sync Subscription details');
export const copySubscriptionIdButtonText = __('Copy');
export const detailsLabels = {
address: __('Address'),
id: s__('CloudLicense|ID'),
company: __('Company'),
email: __('Email'),
lastSync: s__('CloudLicense|Last Sync'),
name: __('Name'),
plan: s__('CloudLicense|Plan'),
startsAt: s__('CloudLicense|Started'),
renews: s__('CloudLicense|Renews'),
};
import { GlCard } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import SubscriptionDetailsCard from 'ee/pages/admin/cloud_licenses/components/subscription_details_card.vue';
import SubscriptionDetailsTable from 'ee/pages/admin/cloud_licenses/components/subscription_details_table.vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { license } from '../mock_data';
describe('Subscription Details Card', () => {
let wrapper;
const findCard = () => wrapper.findComponent(GlCard);
const findCardHeader = () => findCard().find('.gl-card-header');
const findCardFooter = () => findCard().find('.gl-card-footer');
const findSubscriptionDetailsTable = () => wrapper.findComponent(SubscriptionDetailsTable);
const createComponent = (
{ detailsFields = ['id', 'plan'], headerText, subscription = license.ULTIMATE } = {},
slots,
) => {
wrapper = extendedWrapper(
shallowMount(SubscriptionDetailsCard, {
propsData: {
detailsFields,
headerText,
subscription,
},
stubs: {
GlCard,
},
slots,
}),
);
};
afterEach(() => {
wrapper.destroy();
});
describe('with data', () => {
beforeEach(() => {
createComponent({
headerText: 'Card header title',
});
});
it('displays a title', () => {
expect(findCard().text()).toBe('Card header title');
});
it('displays the details table component', () => {
expect(findSubscriptionDetailsTable().exists()).toBe(true);
});
it('passes the details to the table component', () => {
expect(findSubscriptionDetailsTable().props('details')).toEqual([
{
canCopy: true,
label: 'ID',
value: '1309188',
},
{
canCopy: false,
label: 'Plan',
value: 'Ultimate',
},
]);
});
});
describe('with empty subscription', () => {
it('passes an empty array to the table component', () => {
createComponent({ subscription: {} });
expect(findSubscriptionDetailsTable().props('details')).toEqual([]);
});
});
describe('with no title', () => {
it('does not display a title', () => {
createComponent();
expect(findCardHeader().exists()).toBe(false);
});
});
describe('with footer', () => {
beforeEach(() => {
createComponent(
{},
{
footer: '<div>Footer content</div>',
},
);
});
it('displays the footer', () => {
expect(findCardFooter().exists()).toBe(true);
});
it('displays the footer text', () => {
expect(findCardFooter().text()).toContain('Footer content');
});
});
});
import { GlSkeletonLoader } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import SubscriptionDetailsTable from 'ee/pages/admin/cloud_licenses/components/subscription_details_table.vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
const licenseDetails = [
{
label: 'Row label 1',
value: 'row content 1',
},
{
label: 'Row label 2',
value: 'row content 2',
},
];
const hasFontWeightBold = (wrapper) => wrapper.classes('gl-font-weight-bold');
describe('Subscription Details Table', () => {
let wrapper;
const findContentCells = () => wrapper.findAllByTestId('details-content');
const findLabelCells = () => wrapper.findAllByTestId('details-label');
const findLastRow = () => wrapper.findAll('li').wrappers.slice(-1).pop();
const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
const createComponent = (details = licenseDetails) => {
wrapper = extendedWrapper(shallowMount(SubscriptionDetailsTable, { propsData: { details } }));
};
afterEach(() => {
wrapper.destroy();
});
describe('with content', () => {
beforeEach(() => {
createComponent();
});
it('displays the correct number of rows', () => {
expect(findLabelCells()).toHaveLength(2);
expect(findContentCells()).toHaveLength(2);
});
it('displays the correct content for rows', () => {
expect(findLabelCells().at(0).text()).toBe('Row label 1:');
expect(findContentCells().at(0).text()).toBe('row content 1');
});
it('displays the labels in bold', () => {
expect(findLabelCells().wrappers.every(hasFontWeightBold)).toBe(true);
});
it('does not add space to the last row', () => {
expect(findLastRow().classes('gl-mb-3')).toBe(false);
});
it('does not show a clipboard button', () => {
expect(findClipboardButton().exists()).toBe(false);
});
});
describe('with copy-able detail', () => {
beforeEach(() => {
createComponent([
{
value: 'Something to copy',
canCopy: true,
},
]);
});
it('shows a clipboard button', () => {
expect(findClipboardButton().exists()).toBe(true);
});
it('passes the text to the clipboard', () => {
expect(findClipboardButton().props('text')).toBe('Something to copy');
});
});
describe('with no content', () => {
it('displays a loader', () => {
createComponent([]);
expect(wrapper.find(GlSkeletonLoader).exists()).toBe(true);
});
});
});
export const license = {
ULTIMATE: {
id: '1309188',
plan: 'Ultimate',
lastSync: 'just now - actual date',
startsAt: '22 February',
renews: 'in 11 months',
},
};
export const activateLicenseMutationResponse = {
FAILURE: [
{
......
......@@ -2076,6 +2076,9 @@ msgstr ""
msgid "Additional text"
msgstr ""
msgid "Address"
msgstr ""
msgid "Adds"
msgstr ""
......@@ -6429,12 +6432,39 @@ msgstr ""
msgid "CloudLicense|Activate"
msgstr ""
msgid "CloudLicense|ID"
msgstr ""
msgid "CloudLicense|Last Sync"
msgstr ""
msgid "CloudLicense|Licensed to"
msgstr ""
msgid "CloudLicense|Manage"
msgstr ""
msgid "CloudLicense|Paste your activation code"
msgstr ""
msgid "CloudLicense|Paste your activation code below"
msgstr ""
msgid "CloudLicense|Plan"
msgstr ""
msgid "CloudLicense|Renews"
msgstr ""
msgid "CloudLicense|Started"
msgstr ""
msgid "CloudLicense|Subscription details"
msgstr ""
msgid "CloudLicense|Sync Subscription details"
msgstr ""
msgid "CloudLicense|This instance is currently using the %{planName} plan."
msgstr ""
......@@ -7763,6 +7793,9 @@ msgstr ""
msgid "Community forum"
msgstr ""
msgid "Company"
msgstr ""
msgid "Company name"
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