Commit 1e950e31 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch '40533-groups-tree-updates' into 'master'

Groups tree enhancements

Closes #40533

See merge request gitlab-org/gitlab-ce!15980
parents 51562aaf 703aa9d2
...@@ -77,7 +77,8 @@ export default { ...@@ -77,7 +77,8 @@ export default {
class="group-row" class="group-row"
> >
<div <div
class="group-row-contents"> class="group-row-contents"
:class="{ 'project-row-contents': !isGroup }">
<item-actions <item-actions
v-if="isGroup" v-if="isGroup"
:group="group" :group="group"
...@@ -97,7 +98,7 @@ export default { ...@@ -97,7 +98,7 @@ export default {
/> />
</div> </div>
<div <div
class="avatar-container s40 hidden-xs" class="avatar-container prepend-top-8 prepend-left-5 s24 hidden-xs"
:class="{ 'content-loading': group.isChildrenLoading }" :class="{ 'content-loading': group.isChildrenLoading }"
> >
<a <a
...@@ -106,11 +107,12 @@ export default { ...@@ -106,11 +107,12 @@ export default {
> >
<img <img
v-if="hasAvatar" v-if="hasAvatar"
class="avatar s40" class="avatar s24"
:src="group.avatarUrl" :src="group.avatarUrl"
/> />
<identicon <identicon
v-else v-else
size-class="s24"
:entity-id=group.id :entity-id=group.id
:entity-name="group.name" :entity-name="group.name"
/> />
...@@ -123,7 +125,7 @@ export default { ...@@ -123,7 +125,7 @@ export default {
:href="group.relativePath" :href="group.relativePath"
:title="group.fullName" :title="group.fullName"
class="no-expand" class="no-expand"
data-placement="top" data-placement="bottom"
>{{ >{{
// ending bracket must be by closing tag to prevent // ending bracket must be by closing tag to prevent
// link hover text-decoration from over-extending // link hover text-decoration from over-extending
......
<script> <script>
import { s__ } from '../../locale'; import { s__ } from '~/locale';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import modal from '../../vue_shared/components/modal.vue'; import icon from '~/vue_shared/components/icon.vue';
import modal from '~/vue_shared/components/modal.vue';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import { COMMON_STR } from '../constants'; import { COMMON_STR } from '../constants';
import Icon from '../../vue_shared/components/icon.vue';
export default { export default {
components: { components: {
Icon, icon,
modal, modal,
}, },
directives: { directives: {
...@@ -64,10 +64,9 @@ export default { ...@@ -64,10 +64,9 @@ export default {
:title="editBtnTitle" :title="editBtnTitle"
:aria-label="editBtnTitle" :aria-label="editBtnTitle"
data-container="body" data-container="body"
data-placement="bottom"
class="edit-group btn no-expand"> class="edit-group btn no-expand">
<icon <icon name="settings"/>
name="settings">
</icon>
</a> </a>
<a <a
v-tooltip v-tooltip
...@@ -77,10 +76,9 @@ export default { ...@@ -77,10 +76,9 @@ export default {
:title="leaveBtnTitle" :title="leaveBtnTitle"
:aria-label="leaveBtnTitle" :aria-label="leaveBtnTitle"
data-container="body" data-container="body"
data-placement="bottom"
class="leave-group btn no-expand"> class="leave-group btn no-expand">
<i <icon name="leave"/>
class="fa fa-sign-out"
aria-hidden="true"/>
</a> </a>
<modal <modal
v-show="modalStatus" v-show="modalStatus"
......
<script> <script>
import icon from '~/vue_shared/components/icon.vue';
export default { export default {
props: { props: {
isGroupOpen: { isGroupOpen: {
...@@ -7,9 +9,12 @@ export default { ...@@ -7,9 +9,12 @@ export default {
default: false, default: false,
}, },
}, },
components: {
icon,
},
computed: { computed: {
iconClass() { iconClass() {
return this.isGroupOpen ? 'fa-caret-down' : 'fa-caret-right'; return this.isGroupOpen ? 'angle-down' : 'angle-right';
}, },
}, },
}; };
...@@ -17,9 +22,9 @@ export default { ...@@ -17,9 +22,9 @@ export default {
<template> <template>
<span class="folder-caret"> <span class="folder-caret">
<i <icon
:class="iconClass" :size="12"
class="fa" :name="iconClass"
aria-hidden="true"/> />
</span> </span>
</template> </template>
<script> <script>
import tooltip from '../../vue_shared/directives/tooltip'; import icon from '~/vue_shared/components/icon.vue';
import timeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { ITEM_TYPE, VISIBILITY_TYPE_ICON, GROUP_VISIBILITY_TYPE, PROJECT_VISIBILITY_TYPE } from '../constants'; import { ITEM_TYPE, VISIBILITY_TYPE_ICON, GROUP_VISIBILITY_TYPE, PROJECT_VISIBILITY_TYPE } from '../constants';
import itemStatsValue from './item_stats_value.vue';
export default { export default {
directives: { components: {
tooltip, icon,
timeAgoTooltip,
itemStatsValue,
}, },
props: { props: {
item: { item: {
...@@ -34,65 +38,47 @@ export default { ...@@ -34,65 +38,47 @@ export default {
<template> <template>
<div class="stats"> <div class="stats">
<span <item-stats-value
v-tooltip
v-if="isGroup" v-if="isGroup"
css-class="number-subgroups"
icon-name="folder"
:title="s__('Subgroups')" :title="s__('Subgroups')"
class="number-subgroups" :value=item.subgroupCount
data-placement="top" />
data-container="body"> <item-stats-value
<i
class="fa fa-folder"
aria-hidden="true"
/>
{{item.subgroupCount}}
</span>
<span
v-tooltip
v-if="isGroup" v-if="isGroup"
css-class="number-projects"
icon-name="bookmark"
:title="s__('Projects')" :title="s__('Projects')"
class="number-projects" :value=item.projectCount
data-placement="top" />
data-container="body"> <item-stats-value
<i
class="fa fa-bookmark"
aria-hidden="true"
/>
{{item.projectCount}}
</span>
<span
v-tooltip
v-if="isGroup" v-if="isGroup"
css-class="number-users"
icon-name="users"
:title="s__('Members')" :title="s__('Members')"
class="number-users" :value=item.memberCount
data-placement="top" />
data-container="body"> <item-stats-value
<i
class="fa fa-users"
aria-hidden="true"
/>
{{item.memberCount}}
</span>
<span
v-if="isProject" v-if="isProject"
class="project-stars"> css-class="project-stars"
<i icon-name="star"
class="fa fa-star" :value=item.starCount
aria-hidden="true" />
/> <item-stats-value
{{item.starCount}} css-class="item-visibility"
</span> tooltip-placement="left"
<span :icon-name="visibilityIcon"
v-tooltip
:title="visibilityTooltip" :title="visibilityTooltip"
data-placement="left" />
data-container="body" <div
class="item-visibility"> class="last-updated"
<i v-if="isProject"
:class="visibilityIcon" >
class="fa" <time-ago-tooltip
aria-hidden="true" tooltip-placement="bottom"
:time="item.updatedAt"
/> />
</span> </div>
</div> </div>
</template> </template>
<script>
import tooltip from '~/vue_shared/directives/tooltip';
import icon from '~/vue_shared/components/icon.vue';
export default {
props: {
title: {
type: String,
required: false,
default: '',
},
cssClass: {
type: String,
required: false,
default: '',
},
iconName: {
type: String,
required: true,
},
tooltipPlacement: {
type: String,
required: false,
default: 'bottom',
},
/**
* value could either be number or string
* as `memberCount` is always passed as string
* while `subgroupCount` & `projectCount`
* are always number
*/
value: {
type: [Number, String],
required: false,
default: '',
},
},
directives: {
tooltip,
},
components: {
icon,
},
computed: {
isValuePresent() {
return this.value !== '';
},
},
};
</script>
<template>
<span
v-tooltip
data-container="body"
:data-placement="tooltipPlacement"
:class="cssClass"
:title="title"
>
<icon :name="iconName"/>
<span
v-if="isValuePresent"
class="stat-value"
>
{{value}}
</span>
</span>
</template>
<script> <script>
import icon from '~/vue_shared/components/icon.vue';
import { ITEM_TYPE } from '../constants'; import { ITEM_TYPE } from '../constants';
export default { export default {
components: {
icon,
},
props: { props: {
itemType: { itemType: {
type: String, type: String,
...@@ -16,9 +20,9 @@ export default { ...@@ -16,9 +20,9 @@ export default {
computed: { computed: {
iconClass() { iconClass() {
if (this.itemType === ITEM_TYPE.GROUP) { if (this.itemType === ITEM_TYPE.GROUP) {
return this.isGroupOpen ? 'fa-folder-open' : 'fa-folder'; return this.isGroupOpen ? 'folder-open' : 'folder';
} }
return 'fa-bookmark'; return 'bookmark';
}, },
}, },
}; };
...@@ -26,9 +30,6 @@ export default { ...@@ -26,9 +30,6 @@ export default {
<template> <template>
<span class="item-type-icon"> <span class="item-type-icon">
<i <icon :name="iconClass"/>
:class="iconClass"
class="fa"
aria-hidden="true"/>
</span> </span>
</template> </template>
...@@ -29,7 +29,7 @@ export const PROJECT_VISIBILITY_TYPE = { ...@@ -29,7 +29,7 @@ export const PROJECT_VISIBILITY_TYPE = {
}; };
export const VISIBILITY_TYPE_ICON = { export const VISIBILITY_TYPE_ICON = {
public: 'fa-globe', public: 'earth',
internal: 'fa-shield', internal: 'shield',
private: 'fa-lock', private: 'lock',
}; };
...@@ -91,6 +91,7 @@ export default class GroupsStore { ...@@ -91,6 +91,7 @@ export default class GroupsStore {
subgroupCount: rawGroupItem.subgroup_count, subgroupCount: rawGroupItem.subgroup_count,
memberCount: rawGroupItem.number_users_with_delimiter, memberCount: rawGroupItem.number_users_with_delimiter,
starCount: rawGroupItem.star_count, starCount: rawGroupItem.star_count,
updatedAt: rawGroupItem.updated_at,
}; };
} }
......
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
vertical-align: top; vertical-align: top;
&.s16 { font-size: 12px; line-height: 1.33; } &.s16 { font-size: 12px; line-height: 1.33; }
&.s24 { font-size: 14px; line-height: 1.8; } &.s24 { font-size: 13px; line-height: 1.8; }
&.s26 { font-size: 20px; line-height: 1.33; } &.s26 { font-size: 20px; line-height: 1.33; }
&.s32 { font-size: 20px; line-height: 30px; } &.s32 { font-size: 20px; line-height: 30px; }
&.s40 { font-size: 16px; line-height: 38px; } &.s40 { font-size: 16px; line-height: 38px; }
......
...@@ -126,10 +126,8 @@ ul.content-list { ...@@ -126,10 +126,8 @@ ul.content-list {
} }
.description { .description {
p { @include str-truncated;
@include str-truncated; color: $gl-text-color-secondary;
margin-bottom: 0;
}
} }
.controls { .controls {
...@@ -315,7 +313,7 @@ ul.indent-list { ...@@ -315,7 +313,7 @@ ul.indent-list {
border: 2px solid $white-normal; border: 2px solid $white-normal;
&.identicon { &.identicon {
line-height: 30px; line-height: 15px;
} }
} }
} }
...@@ -349,14 +347,19 @@ ul.indent-list { ...@@ -349,14 +347,19 @@ ul.indent-list {
.folder-caret { .folder-caret {
width: 15px; width: 15px;
svg {
margin-bottom: 2px;
}
} }
.item-type-icon { .item-type-icon {
margin-top: 2px;
width: 20px; width: 20px;
} }
> .group-row:not(.has-children) { > .group-row:not(.has-children) {
.folder-caret .fa { .folder-caret {
opacity: 0; opacity: 0;
} }
} }
...@@ -439,12 +442,61 @@ ul.indent-list { ...@@ -439,12 +442,61 @@ ul.indent-list {
.avatar-container > a { .avatar-container > a {
width: 100%; width: 100%;
text-decoration: none;
} }
&.has-more-items { &.has-more-items {
display: block; display: block;
padding: 20px 10px; padding: 20px 10px;
} }
.stats {
position: relative;
line-height: 46px;
> span {
display: inline-flex;
align-items: center;
height: 16px;
min-width: 30px;
}
> span:last-child {
margin-right: 0;
}
.stat-value {
margin: 2px 0 0 5px;
}
}
.controls {
margin-left: 5px;
> .btn {
margin-right: $btn-xs-side-margin;
}
}
}
.project-row-contents .stats {
line-height: inherit;
> span:first-child {
margin-left: 25px;
}
.item-visibility {
margin-right: 0;
}
.last-updated {
position: absolute;
right: 12px;
min-width: 250px;
text-align: right;
color: $gl-text-color-secondary;
}
} }
} }
...@@ -456,12 +508,12 @@ ul.indent-list { ...@@ -456,12 +508,12 @@ ul.indent-list {
ul.group-list-tree { ul.group-list-tree {
li.group-row { li.group-row {
&.has-description .title { > .group-row-contents .title {
line-height: inherit; line-height: $list-text-height;
} }
&:not(.has-description) .title { &.has-description > .group-row-contents .title {
line-height: $list-text-height; line-height: inherit;
} }
} }
} }
......
---
title: Update groups tree to use GitLab SVG icons, add last updated at information
for projects
merge_request: 15980
author:
type: changed
...@@ -94,22 +94,14 @@ feature 'Dashboard Groups page', :js do ...@@ -94,22 +94,14 @@ feature 'Dashboard Groups page', :js do
end end
it 'can toggle parent group' do it 'can toggle parent group' do
# Collapsed by default
expect(page).not_to have_selector("#group-#{group.id} .fa-caret-down", count: 1)
expect(page).to have_selector("#group-#{group.id} .fa-caret-right")
# expand # expand
click_group_caret(group) click_group_caret(group)
expect(page).to have_selector("#group-#{group.id} .fa-caret-down")
expect(page).not_to have_selector("#group-#{group.id} .fa-caret-right", count: 1)
expect(page).to have_selector("#group-#{group.id} #group-#{subgroup.id}") expect(page).to have_selector("#group-#{group.id} #group-#{subgroup.id}")
# collapse # collapse
click_group_caret(group) click_group_caret(group)
expect(page).not_to have_selector("#group-#{group.id} .fa-caret-down", count: 1)
expect(page).to have_selector("#group-#{group.id} .fa-caret-right")
expect(page).not_to have_selector("#group-#{group.id} #group-#{subgroup.id}") expect(page).not_to have_selector("#group-#{group.id} #group-#{subgroup.id}")
end end
end end
......
...@@ -16,24 +16,20 @@ describe('ItemCaretComponent', () => { ...@@ -16,24 +16,20 @@ describe('ItemCaretComponent', () => {
describe('template', () => { describe('template', () => {
it('should render component template correctly', () => { it('should render component template correctly', () => {
const vm = createComponent(); const vm = createComponent();
vm.$mount();
expect(vm.$el.classList.contains('folder-caret')).toBeTruthy(); expect(vm.$el.classList.contains('folder-caret')).toBeTruthy();
expect(vm.$el.querySelectorAll('svg').length).toBe(1);
vm.$destroy(); vm.$destroy();
}); });
it('should render caret down icon if `isGroupOpen` prop is `true`', () => { it('should render caret down icon if `isGroupOpen` prop is `true`', () => {
const vm = createComponent(true); const vm = createComponent(true);
vm.$mount(); expect(vm.$el.querySelector('svg use').getAttribute('xlink:href')).toContain('angle-down');
expect(vm.$el.querySelectorAll('i.fa.fa-caret-down').length).toBe(1);
expect(vm.$el.querySelectorAll('i.fa.fa-caret-right').length).toBe(0);
vm.$destroy(); vm.$destroy();
}); });
it('should render caret right icon if `isGroupOpen` prop is `false`', () => { it('should render caret right icon if `isGroupOpen` prop is `false`', () => {
const vm = createComponent(); const vm = createComponent();
vm.$mount(); expect(vm.$el.querySelector('svg use').getAttribute('xlink:href')).toContain('angle-right');
expect(vm.$el.querySelectorAll('i.fa.fa-caret-down').length).toBe(0);
expect(vm.$el.querySelectorAll('i.fa.fa-caret-right').length).toBe(1);
vm.$destroy(); vm.$destroy();
}); });
}); });
......
...@@ -26,7 +26,6 @@ describe('ItemStatsComponent', () => { ...@@ -26,7 +26,6 @@ describe('ItemStatsComponent', () => {
Object.keys(VISIBILITY_TYPE_ICON).forEach((visibility) => { Object.keys(VISIBILITY_TYPE_ICON).forEach((visibility) => {
const item = Object.assign({}, mockParentGroupItem, { visibility }); const item = Object.assign({}, mockParentGroupItem, { visibility });
const vm = createComponent(item); const vm = createComponent(item);
vm.$mount();
expect(vm.visibilityIcon).toBe(VISIBILITY_TYPE_ICON[visibility]); expect(vm.visibilityIcon).toBe(VISIBILITY_TYPE_ICON[visibility]);
vm.$destroy(); vm.$destroy();
}); });
...@@ -41,7 +40,6 @@ describe('ItemStatsComponent', () => { ...@@ -41,7 +40,6 @@ describe('ItemStatsComponent', () => {
type: ITEM_TYPE.GROUP, type: ITEM_TYPE.GROUP,
}); });
const vm = createComponent(item); const vm = createComponent(item);
vm.$mount();
expect(vm.visibilityTooltip).toBe(GROUP_VISIBILITY_TYPE[visibility]); expect(vm.visibilityTooltip).toBe(GROUP_VISIBILITY_TYPE[visibility]);
vm.$destroy(); vm.$destroy();
}); });
...@@ -54,7 +52,6 @@ describe('ItemStatsComponent', () => { ...@@ -54,7 +52,6 @@ describe('ItemStatsComponent', () => {
type: ITEM_TYPE.PROJECT, type: ITEM_TYPE.PROJECT,
}); });
const vm = createComponent(item); const vm = createComponent(item);
vm.$mount();
expect(vm.visibilityTooltip).toBe(PROJECT_VISIBILITY_TYPE[visibility]); expect(vm.visibilityTooltip).toBe(PROJECT_VISIBILITY_TYPE[visibility]);
vm.$destroy(); vm.$destroy();
}); });
...@@ -68,13 +65,11 @@ describe('ItemStatsComponent', () => { ...@@ -68,13 +65,11 @@ describe('ItemStatsComponent', () => {
item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.PROJECT }); item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.PROJECT });
vm = createComponent(item); vm = createComponent(item);
vm.$mount();
expect(vm.isProject).toBeTruthy(); expect(vm.isProject).toBeTruthy();
vm.$destroy(); vm.$destroy();
item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.GROUP }); item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.GROUP });
vm = createComponent(item); vm = createComponent(item);
vm.$mount();
expect(vm.isProject).toBeFalsy(); expect(vm.isProject).toBeFalsy();
vm.$destroy(); vm.$destroy();
}); });
...@@ -87,13 +82,11 @@ describe('ItemStatsComponent', () => { ...@@ -87,13 +82,11 @@ describe('ItemStatsComponent', () => {
item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.GROUP }); item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.GROUP });
vm = createComponent(item); vm = createComponent(item);
vm.$mount();
expect(vm.isGroup).toBeTruthy(); expect(vm.isGroup).toBeTruthy();
vm.$destroy(); vm.$destroy();
item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.PROJECT }); item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.PROJECT });
vm = createComponent(item); vm = createComponent(item);
vm.$mount();
expect(vm.isGroup).toBeFalsy(); expect(vm.isGroup).toBeFalsy();
vm.$destroy(); vm.$destroy();
}); });
...@@ -101,57 +94,37 @@ describe('ItemStatsComponent', () => { ...@@ -101,57 +94,37 @@ describe('ItemStatsComponent', () => {
}); });
describe('template', () => { describe('template', () => {
it('should render component template correctly', () => { it('renders component container element correctly', () => {
const vm = createComponent(); const vm = createComponent();
vm.$mount();
const visibilityIconEl = vm.$el.querySelector('.item-visibility'); expect(vm.$el.classList.contains('stats')).toBeTruthy();
expect(vm.$el.classList.contains('.stats')).toBeDefined();
expect(visibilityIconEl).toBeDefined();
expect(visibilityIconEl.dataset.originalTitle).toBe(vm.visibilityTooltip);
expect(visibilityIconEl.querySelector('i.fa')).toBeDefined();
vm.$destroy(); vm.$destroy();
}); });
it('should render stat icons if `item.type` is Group', () => { it('renders item visibility icon and tooltip correctly', () => {
const item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.GROUP }); const vm = createComponent();
const vm = createComponent(item);
vm.$mount(); const visibilityIconEl = vm.$el.querySelector('.item-visibility');
expect(visibilityIconEl).not.toBe(null);
const subgroupIconEl = vm.$el.querySelector('span.number-subgroups'); expect(visibilityIconEl.dataset.originalTitle).toBe(vm.visibilityTooltip);
expect(subgroupIconEl).toBeDefined(); expect(visibilityIconEl.querySelectorAll('svg').length > 0).toBeTruthy();
expect(subgroupIconEl.dataset.originalTitle).toBe('Subgroups');
expect(subgroupIconEl.querySelector('i.fa.fa-folder')).toBeDefined();
expect(subgroupIconEl.innerText.trim()).toBe(`${vm.item.subgroupCount}`);
const projectsIconEl = vm.$el.querySelector('span.number-projects');
expect(projectsIconEl).toBeDefined();
expect(projectsIconEl.dataset.originalTitle).toBe('Projects');
expect(projectsIconEl.querySelector('i.fa.fa-bookmark')).toBeDefined();
expect(projectsIconEl.innerText.trim()).toBe(`${vm.item.projectCount}`);
const membersIconEl = vm.$el.querySelector('span.number-users');
expect(membersIconEl).toBeDefined();
expect(membersIconEl.dataset.originalTitle).toBe('Members');
expect(membersIconEl.querySelector('i.fa.fa-users')).toBeDefined();
expect(membersIconEl.innerText.trim()).toBe(`${vm.item.memberCount}`);
vm.$destroy(); vm.$destroy();
}); });
it('should render stat icons if `item.type` is Project', () => { it('renders start count and last updated information for project item correctly', () => {
const item = Object.assign({}, mockParentGroupItem, { const item = Object.assign({}, mockParentGroupItem, {
type: ITEM_TYPE.PROJECT, type: ITEM_TYPE.PROJECT,
starCount: 4, starCount: 4,
}); });
const vm = createComponent(item); const vm = createComponent(item);
vm.$mount();
const projectStarIconEl = vm.$el.querySelector('.project-stars'); const projectStarIconEl = vm.$el.querySelector('.project-stars');
expect(projectStarIconEl).toBeDefined(); expect(projectStarIconEl).not.toBe(null);
expect(projectStarIconEl.querySelector('i.fa.fa-star')).toBeDefined(); expect(projectStarIconEl.querySelectorAll('svg').length > 0).toBeTruthy();
expect(projectStarIconEl.innerText.trim()).toBe(`${vm.item.starCount}`); expect(projectStarIconEl.querySelectorAll('.stat-value').length > 0).toBeTruthy();
expect(vm.$el.querySelectorAll('.last-updated').length > 0).toBeTruthy();
vm.$destroy(); vm.$destroy();
}); });
......
import Vue from 'vue';
import itemStatsValueComponent from '~/groups/components/item_stats_value.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = ({ title, cssClass, iconName, tooltipPlacement, value }) => {
const Component = Vue.extend(itemStatsValueComponent);
return mountComponent(Component, {
title,
cssClass,
iconName,
tooltipPlacement,
value,
});
};
describe('ItemStatsValueComponent', () => {
describe('computed', () => {
let vm;
const itemConfig = {
title: 'Subgroups',
cssClass: 'number-subgroups',
iconName: 'folder',
tooltipPlacement: 'left',
};
describe('isValuePresent', () => {
it('returns true if non-empty `value` is present', () => {
vm = createComponent(Object.assign({}, itemConfig, { value: 10 }));
expect(vm.isValuePresent).toBeTruthy();
});
it('returns false if empty `value` is present', () => {
vm = createComponent(itemConfig);
expect(vm.isValuePresent).toBeFalsy();
});
afterEach(() => {
vm.$destroy();
});
});
});
describe('template', () => {
let vm;
beforeEach(() => {
vm = createComponent({
title: 'Subgroups',
cssClass: 'number-subgroups',
iconName: 'folder',
tooltipPlacement: 'left',
value: 10,
});
});
it('renders component element correctly', () => {
expect(vm.$el.classList.contains('number-subgroups')).toBeTruthy();
expect(vm.$el.querySelectorAll('svg').length > 0).toBeTruthy();
expect(vm.$el.querySelectorAll('.stat-value').length > 0).toBeTruthy();
});
it('renders element tooltip correctly', () => {
expect(vm.$el.dataset.originalTitle).toBe('Subgroups');
expect(vm.$el.dataset.placement).toBe('left');
});
it('renders element icon correctly', () => {
expect(vm.$el.querySelector('svg use').getAttribute('xlink:href')).toContain('folder');
});
it('renders value count correctly', () => {
expect(vm.$el.querySelector('.stat-value').innerText.trim()).toContain('10');
});
afterEach(() => {
vm.$destroy();
});
});
});
...@@ -28,12 +28,12 @@ describe('ItemTypeIconComponent', () => { ...@@ -28,12 +28,12 @@ describe('ItemTypeIconComponent', () => {
vm = createComponent(ITEM_TYPE.GROUP, true); vm = createComponent(ITEM_TYPE.GROUP, true);
vm.$mount(); vm.$mount();
expect(vm.$el.querySelector('i.fa.fa-folder-open')).toBeDefined(); expect(vm.$el.querySelector('use').getAttribute('xlink:href')).toContain('folder-open');
vm.$destroy(); vm.$destroy();
vm = createComponent(ITEM_TYPE.GROUP); vm = createComponent(ITEM_TYPE.GROUP);
vm.$mount(); vm.$mount();
expect(vm.$el.querySelector('i.fa.fa-folder')).toBeDefined(); expect(vm.$el.querySelector('use').getAttribute('xlink:href')).toContain('folder');
vm.$destroy(); vm.$destroy();
}); });
...@@ -42,12 +42,12 @@ describe('ItemTypeIconComponent', () => { ...@@ -42,12 +42,12 @@ describe('ItemTypeIconComponent', () => {
vm = createComponent(ITEM_TYPE.PROJECT); vm = createComponent(ITEM_TYPE.PROJECT);
vm.$mount(); vm.$mount();
expect(vm.$el.querySelectorAll('i.fa.fa-bookmark').length).toBe(1); expect(vm.$el.querySelector('use').getAttribute('xlink:href')).toContain('bookmark');
vm.$destroy(); vm.$destroy();
vm = createComponent(ITEM_TYPE.GROUP); vm = createComponent(ITEM_TYPE.GROUP);
vm.$mount(); vm.$mount();
expect(vm.$el.querySelectorAll('i.fa.fa-bookmark').length).toBe(0); expect(vm.$el.querySelector('use').getAttribute('xlink:href')).not.toContain('bookmark');
vm.$destroy(); vm.$destroy();
}); });
}); });
......
...@@ -18,9 +18,9 @@ export const PROJECT_VISIBILITY_TYPE = { ...@@ -18,9 +18,9 @@ export const PROJECT_VISIBILITY_TYPE = {
}; };
export const VISIBILITY_TYPE_ICON = { export const VISIBILITY_TYPE_ICON = {
public: 'fa-globe', public: 'earth',
internal: 'fa-shield', internal: 'shield',
private: 'fa-lock', private: 'lock',
}; };
export const mockParentGroupItem = { export const mockParentGroupItem = {
...@@ -46,6 +46,7 @@ export const mockParentGroupItem = { ...@@ -46,6 +46,7 @@ export const mockParentGroupItem = {
isOpen: true, isOpen: true,
isChildrenLoading: false, isChildrenLoading: false,
isBeingRemoved: false, isBeingRemoved: false,
updatedAt: '2017-04-09T18:40:39.101Z',
}; };
export const mockRawChildren = [ export const mockRawChildren = [
...@@ -69,6 +70,7 @@ export const mockRawChildren = [ ...@@ -69,6 +70,7 @@ export const mockRawChildren = [
subgroup_count: 2, subgroup_count: 2,
can_leave: false, can_leave: false,
children: [], children: [],
updated_at: '2017-04-09T18:40:39.101Z',
}, },
]; ];
...@@ -96,6 +98,7 @@ export const mockChildren = [ ...@@ -96,6 +98,7 @@ export const mockChildren = [
isOpen: true, isOpen: true,
isChildrenLoading: false, isChildrenLoading: false,
isBeingRemoved: false, isBeingRemoved: false,
updatedAt: '2017-04-09T18:40:39.101Z',
}, },
]; ];
...@@ -119,6 +122,7 @@ export const mockGroups = [ ...@@ -119,6 +122,7 @@ export const mockGroups = [
project_count: 2, project_count: 2,
subgroup_count: 0, subgroup_count: 0,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
}, },
{ {
id: 67, id: 67,
...@@ -139,6 +143,7 @@ export const mockGroups = [ ...@@ -139,6 +143,7 @@ export const mockGroups = [
project_count: 0, project_count: 0,
subgroup_count: 0, subgroup_count: 0,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
}, },
{ {
id: 54, id: 54,
...@@ -159,6 +164,7 @@ export const mockGroups = [ ...@@ -159,6 +164,7 @@ export const mockGroups = [
project_count: 0, project_count: 0,
subgroup_count: 1, subgroup_count: 1,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
}, },
{ {
id: 5, id: 5,
...@@ -179,6 +185,7 @@ export const mockGroups = [ ...@@ -179,6 +185,7 @@ export const mockGroups = [
project_count: 1, project_count: 1,
subgroup_count: 0, subgroup_count: 0,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
}, },
{ {
id: 4, id: 4,
...@@ -199,6 +206,7 @@ export const mockGroups = [ ...@@ -199,6 +206,7 @@ export const mockGroups = [
project_count: 2, project_count: 2,
subgroup_count: 0, subgroup_count: 0,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
}, },
{ {
id: 3, id: 3,
...@@ -219,6 +227,7 @@ export const mockGroups = [ ...@@ -219,6 +227,7 @@ export const mockGroups = [
project_count: 1, project_count: 1,
subgroup_count: 0, subgroup_count: 0,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
}, },
{ {
id: 2, id: 2,
...@@ -239,6 +248,7 @@ export const mockGroups = [ ...@@ -239,6 +248,7 @@ export const mockGroups = [
project_count: 4, project_count: 4,
subgroup_count: 0, subgroup_count: 0,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
}, },
]; ];
...@@ -262,6 +272,7 @@ export const mockSearchedGroups = [ ...@@ -262,6 +272,7 @@ export const mockSearchedGroups = [
project_count: 1, project_count: 1,
subgroup_count: 2, subgroup_count: 2,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
children: [ children: [
{ {
id: 57, id: 57,
...@@ -282,6 +293,7 @@ export const mockSearchedGroups = [ ...@@ -282,6 +293,7 @@ export const mockSearchedGroups = [
project_count: 4, project_count: 4,
subgroup_count: 2, subgroup_count: 2,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
children: [ children: [
{ {
id: 60, id: 60,
...@@ -302,6 +314,7 @@ export const mockSearchedGroups = [ ...@@ -302,6 +314,7 @@ export const mockSearchedGroups = [
project_count: 0, project_count: 0,
subgroup_count: 1, subgroup_count: 1,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
children: [ children: [
{ {
id: 61, id: 61,
...@@ -322,6 +335,7 @@ export const mockSearchedGroups = [ ...@@ -322,6 +335,7 @@ export const mockSearchedGroups = [
project_count: 2, project_count: 2,
subgroup_count: 0, subgroup_count: 0,
can_leave: false, can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
children: [ children: [
{ {
id: 17, id: 17,
...@@ -336,6 +350,7 @@ export const mockSearchedGroups = [ ...@@ -336,6 +350,7 @@ export const mockSearchedGroups = [
permission: null, permission: null,
edit_path: '/platform/hardware/bsp/kernel/common/v4.4/edit', edit_path: '/platform/hardware/bsp/kernel/common/v4.4/edit',
star_count: 0, star_count: 0,
updated_at: '2017-09-12T06:37:04.925Z',
}, },
{ {
id: 16, id: 16,
...@@ -350,6 +365,7 @@ export const mockSearchedGroups = [ ...@@ -350,6 +365,7 @@ export const mockSearchedGroups = [
permission: null, permission: null,
edit_path: '/platform/hardware/bsp/kernel/common/v4.1/edit', edit_path: '/platform/hardware/bsp/kernel/common/v4.1/edit',
star_count: 0, star_count: 0,
updated_at: '2017-04-09T18:41:03.112Z',
}, },
], ],
}, },
......
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