summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEzekiel Kigbo <ekigbo@gitlab.com>2019-04-24 13:21:36 +0200
committerEzekiel Kigbo <ekigbo@gitlab.com>2019-04-26 19:31:39 +0200
commitad476c55c252cc283a20a884fe9236b44f594d6f (patch)
treef1240c55b4a91b807a9f0f0f6ba554f07696ead7
parent674e5e5baab6542eb35446fa46d45ce428c9ea1a (diff)
downloadgitlab-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.vue106
-rw-r--r--spec/javascripts/vue_shared/components/projects_list/project_counts_spec.js73
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);
+ });
+});