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

Groups tree enhancements

Closes #40533

See merge request gitlab-org/gitlab-ce!15980
This commit is contained in:
Filipa Lacerda 2018-01-04 13:38:43 +00:00
commit 1e950e3148
17 changed files with 336 additions and 159 deletions

View file

@ -77,7 +77,8 @@ export default {
class="group-row"
>
<div
class="group-row-contents">
class="group-row-contents"
:class="{ 'project-row-contents': !isGroup }">
<item-actions
v-if="isGroup"
:group="group"
@ -97,7 +98,7 @@ export default {
/>
</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 }"
>
<a
@ -106,11 +107,12 @@ export default {
>
<img
v-if="hasAvatar"
class="avatar s40"
class="avatar s24"
:src="group.avatarUrl"
/>
<identicon
v-else
size-class="s24"
:entity-id=group.id
:entity-name="group.name"
/>
@ -123,7 +125,7 @@ export default {
:href="group.relativePath"
:title="group.fullName"
class="no-expand"
data-placement="top"
data-placement="bottom"
>{{
// ending bracket must be by closing tag to prevent
// link hover text-decoration from over-extending

View file

@ -1,14 +1,14 @@
<script>
import { s__ } from '../../locale';
import tooltip from '../../vue_shared/directives/tooltip';
import modal from '../../vue_shared/components/modal.vue';
import { s__ } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip';
import icon from '~/vue_shared/components/icon.vue';
import modal from '~/vue_shared/components/modal.vue';
import eventHub from '../event_hub';
import { COMMON_STR } from '../constants';
import Icon from '../../vue_shared/components/icon.vue';
export default {
components: {
Icon,
icon,
modal,
},
directives: {
@ -64,10 +64,9 @@ export default {
:title="editBtnTitle"
:aria-label="editBtnTitle"
data-container="body"
data-placement="bottom"
class="edit-group btn no-expand">
<icon
name="settings">
</icon>
<icon name="settings"/>
</a>
<a
v-tooltip
@ -77,10 +76,9 @@ export default {
:title="leaveBtnTitle"
:aria-label="leaveBtnTitle"
data-container="body"
data-placement="bottom"
class="leave-group btn no-expand">
<i
class="fa fa-sign-out"
aria-hidden="true"/>
<icon name="leave"/>
</a>
<modal
v-show="modalStatus"

View file

@ -1,4 +1,6 @@
<script>
import icon from '~/vue_shared/components/icon.vue';
export default {
props: {
isGroupOpen: {
@ -7,9 +9,12 @@ export default {
default: false,
},
},
components: {
icon,
},
computed: {
iconClass() {
return this.isGroupOpen ? 'fa-caret-down' : 'fa-caret-right';
return this.isGroupOpen ? 'angle-down' : 'angle-right';
},
},
};
@ -17,9 +22,9 @@ export default {
<template>
<span class="folder-caret">
<i
:class="iconClass"
class="fa"
aria-hidden="true"/>
<icon
:size="12"
:name="iconClass"
/>
</span>
</template>

View file

@ -1,10 +1,14 @@
<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 itemStatsValue from './item_stats_value.vue';
export default {
directives: {
tooltip,
components: {
icon,
timeAgoTooltip,
itemStatsValue,
},
props: {
item: {
@ -34,65 +38,47 @@ export default {
<template>
<div class="stats">
<span
v-tooltip
<item-stats-value
v-if="isGroup"
css-class="number-subgroups"
icon-name="folder"
:title="s__('Subgroups')"
class="number-subgroups"
data-placement="top"
data-container="body">
<i
class="fa fa-folder"
aria-hidden="true"
/>
{{item.subgroupCount}}
</span>
<span
v-tooltip
:value=item.subgroupCount
/>
<item-stats-value
v-if="isGroup"
css-class="number-projects"
icon-name="bookmark"
:title="s__('Projects')"
class="number-projects"
data-placement="top"
data-container="body">
<i
class="fa fa-bookmark"
aria-hidden="true"
/>
{{item.projectCount}}
</span>
<span
v-tooltip
:value=item.projectCount
/>
<item-stats-value
v-if="isGroup"
css-class="number-users"
icon-name="users"
:title="s__('Members')"
class="number-users"
data-placement="top"
data-container="body">
<i
class="fa fa-users"
aria-hidden="true"
/>
{{item.memberCount}}
</span>
<span
:value=item.memberCount
/>
<item-stats-value
v-if="isProject"
class="project-stars">
<i
class="fa fa-star"
aria-hidden="true"
/>
{{item.starCount}}
</span>
<span
v-tooltip
css-class="project-stars"
icon-name="star"
:value=item.starCount
/>
<item-stats-value
css-class="item-visibility"
tooltip-placement="left"
:icon-name="visibilityIcon"
:title="visibilityTooltip"
data-placement="left"
data-container="body"
class="item-visibility">
<i
:class="visibilityIcon"
class="fa"
aria-hidden="true"
/>
<div
class="last-updated"
v-if="isProject"
>
<time-ago-tooltip
tooltip-placement="bottom"
:time="item.updatedAt"
/>
</span>
</div>
</div>
</template>

View file

@ -0,0 +1,68 @@
<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>

View file

@ -1,7 +1,11 @@
<script>
import icon from '~/vue_shared/components/icon.vue';
import { ITEM_TYPE } from '../constants';
export default {
components: {
icon,
},
props: {
itemType: {
type: String,
@ -16,9 +20,9 @@ export default {
computed: {
iconClass() {
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 {
<template>
<span class="item-type-icon">
<i
:class="iconClass"
class="fa"
aria-hidden="true"/>
<icon :name="iconClass"/>
</span>
</template>

View file

@ -29,7 +29,7 @@ export const PROJECT_VISIBILITY_TYPE = {
};
export const VISIBILITY_TYPE_ICON = {
public: 'fa-globe',
internal: 'fa-shield',
private: 'fa-lock',
public: 'earth',
internal: 'shield',
private: 'lock',
};

View file

@ -91,6 +91,7 @@ export default class GroupsStore {
subgroupCount: rawGroupItem.subgroup_count,
memberCount: rawGroupItem.number_users_with_delimiter,
starCount: rawGroupItem.star_count,
updatedAt: rawGroupItem.updated_at,
};
}

View file

@ -71,7 +71,7 @@
vertical-align: top;
&.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; }
&.s32 { font-size: 20px; line-height: 30px; }
&.s40 { font-size: 16px; line-height: 38px; }

View file

@ -126,10 +126,8 @@ ul.content-list {
}
.description {
p {
@include str-truncated;
margin-bottom: 0;
}
@include str-truncated;
color: $gl-text-color-secondary;
}
.controls {
@ -315,7 +313,7 @@ ul.indent-list {
border: 2px solid $white-normal;
&.identicon {
line-height: 30px;
line-height: 15px;
}
}
}
@ -349,14 +347,19 @@ ul.indent-list {
.folder-caret {
width: 15px;
svg {
margin-bottom: 2px;
}
}
.item-type-icon {
margin-top: 2px;
width: 20px;
}
> .group-row:not(.has-children) {
.folder-caret .fa {
.folder-caret {
opacity: 0;
}
}
@ -439,12 +442,61 @@ ul.indent-list {
.avatar-container > a {
width: 100%;
text-decoration: none;
}
&.has-more-items {
display: block;
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 {
ul.group-list-tree {
li.group-row {
&.has-description .title {
line-height: inherit;
> .group-row-contents .title {
line-height: $list-text-height;
}
&:not(.has-description) .title {
line-height: $list-text-height;
&.has-description > .group-row-contents .title {
line-height: inherit;
}
}
}

View file

@ -0,0 +1,6 @@
---
title: Update groups tree to use GitLab SVG icons, add last updated at information
for projects
merge_request: 15980
author:
type: changed

View file

@ -94,22 +94,14 @@ feature 'Dashboard Groups page', :js do
end
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
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}")
# collapse
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}")
end
end

View file

@ -16,24 +16,20 @@ describe('ItemCaretComponent', () => {
describe('template', () => {
it('should render component template correctly', () => {
const vm = createComponent();
vm.$mount();
expect(vm.$el.classList.contains('folder-caret')).toBeTruthy();
expect(vm.$el.querySelectorAll('svg').length).toBe(1);
vm.$destroy();
});
it('should render caret down icon if `isGroupOpen` prop is `true`', () => {
const vm = createComponent(true);
vm.$mount();
expect(vm.$el.querySelectorAll('i.fa.fa-caret-down').length).toBe(1);
expect(vm.$el.querySelectorAll('i.fa.fa-caret-right').length).toBe(0);
expect(vm.$el.querySelector('svg use').getAttribute('xlink:href')).toContain('angle-down');
vm.$destroy();
});
it('should render caret right icon if `isGroupOpen` prop is `false`', () => {
const vm = createComponent();
vm.$mount();
expect(vm.$el.querySelectorAll('i.fa.fa-caret-down').length).toBe(0);
expect(vm.$el.querySelectorAll('i.fa.fa-caret-right').length).toBe(1);
expect(vm.$el.querySelector('svg use').getAttribute('xlink:href')).toContain('angle-right');
vm.$destroy();
});
});

View file

@ -26,7 +26,6 @@ describe('ItemStatsComponent', () => {
Object.keys(VISIBILITY_TYPE_ICON).forEach((visibility) => {
const item = Object.assign({}, mockParentGroupItem, { visibility });
const vm = createComponent(item);
vm.$mount();
expect(vm.visibilityIcon).toBe(VISIBILITY_TYPE_ICON[visibility]);
vm.$destroy();
});
@ -41,7 +40,6 @@ describe('ItemStatsComponent', () => {
type: ITEM_TYPE.GROUP,
});
const vm = createComponent(item);
vm.$mount();
expect(vm.visibilityTooltip).toBe(GROUP_VISIBILITY_TYPE[visibility]);
vm.$destroy();
});
@ -54,7 +52,6 @@ describe('ItemStatsComponent', () => {
type: ITEM_TYPE.PROJECT,
});
const vm = createComponent(item);
vm.$mount();
expect(vm.visibilityTooltip).toBe(PROJECT_VISIBILITY_TYPE[visibility]);
vm.$destroy();
});
@ -68,13 +65,11 @@ describe('ItemStatsComponent', () => {
item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.PROJECT });
vm = createComponent(item);
vm.$mount();
expect(vm.isProject).toBeTruthy();
vm.$destroy();
item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.GROUP });
vm = createComponent(item);
vm.$mount();
expect(vm.isProject).toBeFalsy();
vm.$destroy();
});
@ -87,13 +82,11 @@ describe('ItemStatsComponent', () => {
item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.GROUP });
vm = createComponent(item);
vm.$mount();
expect(vm.isGroup).toBeTruthy();
vm.$destroy();
item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.PROJECT });
vm = createComponent(item);
vm.$mount();
expect(vm.isGroup).toBeFalsy();
vm.$destroy();
});
@ -101,57 +94,37 @@ describe('ItemStatsComponent', () => {
});
describe('template', () => {
it('should render component template correctly', () => {
it('renders component container element correctly', () => {
const vm = createComponent();
expect(vm.$el.classList.contains('stats')).toBeTruthy();
vm.$destroy();
});
it('renders item visibility icon and tooltip correctly', () => {
const vm = createComponent();
vm.$mount();
const visibilityIconEl = vm.$el.querySelector('.item-visibility');
expect(vm.$el.classList.contains('.stats')).toBeDefined();
expect(visibilityIconEl).toBeDefined();
expect(visibilityIconEl).not.toBe(null);
expect(visibilityIconEl.dataset.originalTitle).toBe(vm.visibilityTooltip);
expect(visibilityIconEl.querySelector('i.fa')).toBeDefined();
expect(visibilityIconEl.querySelectorAll('svg').length > 0).toBeTruthy();
vm.$destroy();
});
it('should render stat icons if `item.type` is Group', () => {
const item = Object.assign({}, mockParentGroupItem, { type: ITEM_TYPE.GROUP });
const vm = createComponent(item);
vm.$mount();
const subgroupIconEl = vm.$el.querySelector('span.number-subgroups');
expect(subgroupIconEl).toBeDefined();
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();
});
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, {
type: ITEM_TYPE.PROJECT,
starCount: 4,
});
const vm = createComponent(item);
vm.$mount();
const projectStarIconEl = vm.$el.querySelector('.project-stars');
expect(projectStarIconEl).toBeDefined();
expect(projectStarIconEl.querySelector('i.fa.fa-star')).toBeDefined();
expect(projectStarIconEl.innerText.trim()).toBe(`${vm.item.starCount}`);
expect(projectStarIconEl).not.toBe(null);
expect(projectStarIconEl.querySelectorAll('svg').length > 0).toBeTruthy();
expect(projectStarIconEl.querySelectorAll('.stat-value').length > 0).toBeTruthy();
expect(vm.$el.querySelectorAll('.last-updated').length > 0).toBeTruthy();
vm.$destroy();
});

View file

@ -0,0 +1,81 @@
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();
});
});
});

View file

@ -28,12 +28,12 @@ describe('ItemTypeIconComponent', () => {
vm = createComponent(ITEM_TYPE.GROUP, true);
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 = createComponent(ITEM_TYPE.GROUP);
vm.$mount();
expect(vm.$el.querySelector('i.fa.fa-folder')).toBeDefined();
expect(vm.$el.querySelector('use').getAttribute('xlink:href')).toContain('folder');
vm.$destroy();
});
@ -42,12 +42,12 @@ describe('ItemTypeIconComponent', () => {
vm = createComponent(ITEM_TYPE.PROJECT);
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 = createComponent(ITEM_TYPE.GROUP);
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();
});
});

View file

@ -18,9 +18,9 @@ export const PROJECT_VISIBILITY_TYPE = {
};
export const VISIBILITY_TYPE_ICON = {
public: 'fa-globe',
internal: 'fa-shield',
private: 'fa-lock',
public: 'earth',
internal: 'shield',
private: 'lock',
};
export const mockParentGroupItem = {
@ -46,6 +46,7 @@ export const mockParentGroupItem = {
isOpen: true,
isChildrenLoading: false,
isBeingRemoved: false,
updatedAt: '2017-04-09T18:40:39.101Z',
};
export const mockRawChildren = [
@ -69,6 +70,7 @@ export const mockRawChildren = [
subgroup_count: 2,
can_leave: false,
children: [],
updated_at: '2017-04-09T18:40:39.101Z',
},
];
@ -96,6 +98,7 @@ export const mockChildren = [
isOpen: true,
isChildrenLoading: false,
isBeingRemoved: false,
updatedAt: '2017-04-09T18:40:39.101Z',
},
];
@ -119,6 +122,7 @@ export const mockGroups = [
project_count: 2,
subgroup_count: 0,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
},
{
id: 67,
@ -139,6 +143,7 @@ export const mockGroups = [
project_count: 0,
subgroup_count: 0,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
},
{
id: 54,
@ -159,6 +164,7 @@ export const mockGroups = [
project_count: 0,
subgroup_count: 1,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
},
{
id: 5,
@ -179,6 +185,7 @@ export const mockGroups = [
project_count: 1,
subgroup_count: 0,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
},
{
id: 4,
@ -199,6 +206,7 @@ export const mockGroups = [
project_count: 2,
subgroup_count: 0,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
},
{
id: 3,
@ -219,6 +227,7 @@ export const mockGroups = [
project_count: 1,
subgroup_count: 0,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
},
{
id: 2,
@ -239,6 +248,7 @@ export const mockGroups = [
project_count: 4,
subgroup_count: 0,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
},
];
@ -262,6 +272,7 @@ export const mockSearchedGroups = [
project_count: 1,
subgroup_count: 2,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
children: [
{
id: 57,
@ -282,6 +293,7 @@ export const mockSearchedGroups = [
project_count: 4,
subgroup_count: 2,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
children: [
{
id: 60,
@ -302,6 +314,7 @@ export const mockSearchedGroups = [
project_count: 0,
subgroup_count: 1,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
children: [
{
id: 61,
@ -322,6 +335,7 @@ export const mockSearchedGroups = [
project_count: 2,
subgroup_count: 0,
can_leave: false,
updated_at: '2017-04-09T18:40:39.101Z',
children: [
{
id: 17,
@ -336,6 +350,7 @@ export const mockSearchedGroups = [
permission: null,
edit_path: '/platform/hardware/bsp/kernel/common/v4.4/edit',
star_count: 0,
updated_at: '2017-09-12T06:37:04.925Z',
},
{
id: 16,
@ -350,6 +365,7 @@ export const mockSearchedGroups = [
permission: null,
edit_path: '/platform/hardware/bsp/kernel/common/v4.1/edit',
star_count: 0,
updated_at: '2017-04-09T18:41:03.112Z',
},
],
},