diff options
author | Ezekiel Kigbo <ekigbo@gitlab.com> | 2019-04-24 13:21:36 +0200 |
---|---|---|
committer | Ezekiel Kigbo <ekigbo@gitlab.com> | 2019-04-26 19:31:39 +0200 |
commit | ad476c55c252cc283a20a884fe9236b44f594d6f (patch) | |
tree | f1240c55b4a91b807a9f0f0f6ba554f07696ead7 | |
parent | 674e5e5baab6542eb35446fa46d45ce428c9ea1a (diff) | |
download | gitlab-ce-56992-project-list-counts-component.tar.gz |
Create project list counts component56992-project-list-counts-component
Signed-off-by: Ezekiel Kigbo <ekigbo@gitlab.com>
-rw-r--r-- | app/assets/javascripts/vue_shared/components/projects_list/project_counts.vue | 106 | ||||
-rw-r--r-- | spec/javascripts/vue_shared/components/projects_list/project_counts_spec.js | 73 |
2 files changed, 179 insertions, 0 deletions
diff --git a/app/assets/javascripts/vue_shared/components/projects_list/project_counts.vue b/app/assets/javascripts/vue_shared/components/projects_list/project_counts.vue new file mode 100644 index 00000000000..5f8c5696528 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/projects_list/project_counts.vue @@ -0,0 +1,106 @@ +<script> +import Icon from '~/vue_shared/components/icon.vue'; + +/** + * Renders a project list item + */ +export default { + components: { + Icon, + }, + props: { + archived: { + type: Boolean, + default: false, + }, + starCount: { + type: Number, + required: true, + }, + forksCount: { + type: Number, + required: true, + }, + issuesCount: { + type: Number, + required: true, + }, + mergeRequestsCount: { + type: Number, + required: true, + }, + projectPath: { + type: String, + required: true, + }, + }, + data() { + return { baseClasses: 'align-items-center icon-wrapper has-tooltip' }; + }, + computed: { + items() { + return [ + { + slug: null, + title: 'Stars', + total: this.starCount, + icon: 'star', + class: 'd-flex stars', + }, + { + slug: 'forks', + title: 'Forks', + total: this.forksCount, + icon: 'fork', + class: 'forks', + }, + { + slug: 'issues', + title: 'Issues', + total: this.issuesCount, + icon: 'issues', + class: 'd-none d-xl-flex issues', + }, + { + slug: 'merge_requests', + title: 'Merge requests', + total: this.mergeRequestsCount, + icon: 'git-merge', + class: 'd-none d-xl-flex merge-requests', + }, + ]; + }, + }, +}; +</script> +<template> + <div class="icon-container d-flex align-items-center"> + <span v-if="archived" class="d-flex icon-wrapper badge badge-warning">archived</span> + <!-- TODO: re-usable --> + <template v-for="i in items"> + <a + v-if="i.slug" + :key="`project-count-${i.title}`" + :class="[baseClasses, i.class]" + :title="i.title" + :href="`${projectPath}/${i.slug}`" + data-container="body" + data-placement="top" + > + <icon :name="i.icon" :size="14" css-classes="append-right-4"/> + {{i.total}} + </a> + <span + v-else + :key="`project-count-${i.title}`" + :class="[baseClasses, i.class]" + :title="i.title" + data-container="body" + data-placement="top" + > + <icon :name="i.icon" :size="14" css-classes="append-right-4"/> + {{i.total}} + </span> + </template> + </div> +</template> diff --git a/spec/javascripts/vue_shared/components/projects_list/project_counts_spec.js b/spec/javascripts/vue_shared/components/projects_list/project_counts_spec.js new file mode 100644 index 00000000000..bbefa9360d6 --- /dev/null +++ b/spec/javascripts/vue_shared/components/projects_list/project_counts_spec.js @@ -0,0 +1,73 @@ +import Vue from 'vue'; +import ProjectListItem from '~/vue_shared/components/projects_list/project_list_item.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; + +// TODO: move to shallow mount / vue test utils ?? + +loadJSONFixtures('projects.json'); +const projects = getJSONFixture('projects.json'); +const selectedProject = projects[1]; + +const createComponent = (props, defaultComponent = ProjectListItem) => { + const Component = Vue.extend(defaultComponent); + + return mountComponent(Component, props); +}; + +describe('ProjectCounts', () => { + let vm; + const path = selectedProject.path_with_namespace; + const urls = { + forks: `/${path}/forks`, + issues: `/${path}/issues`, + 'merge-requests': `/${path}/merge_requests`, + }; + + beforeEach(() => { + vm = createComponent({ project: selectedProject }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders a warning if the project is archived', () => { + const archivedVm = createComponent({ project: { ...selectedProject, archived: true } }); + + expect(archivedVm.$el.querySelector('.icon-container .badge').textContent).toBe('archived'); + + expect(archivedVm.$el.querySelector('.icon-container .badge').classList).toContain( + 'badge-warning', + ); + }); + + it('renders the correct urls for forks, issues and merge requests', () => { + Object.entries(urls).forEach(([key, url]) => { + expect(vm.$el.querySelector(`.icon-container .${key}`).href).toContain(url); + }); + }); + + it('renders the correct star count', () => { + const stars = Number(vm.$el.querySelector('.stars').textContent); + + expect(stars).toEqual(selectedProject.star_count); + }); + + it('renders the correct fork count', () => { + const forks = Number(vm.$el.querySelector('.forks').textContent); + + expect(forks).toEqual(selectedProject.forks_count); + }); + + it('renders the correct issue count', () => { + const issues = Number(vm.$el.querySelector('.issues').textContent); + + expect(issues).toEqual(selectedProject.open_issues_count); + }); + + it('renders the correct merge request count', () => { + const mergeRequests = Number(vm.$el.querySelector('.merge-requests').textContent); + + expect(mergeRequests).toEqual(selectedProject.merge_requests_count); + }); +}); |