summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2019-06-20 13:14:34 +0000
committerFilipa Lacerda <filipa@gitlab.com>2019-06-20 13:14:34 +0000
commit429f6b629b691945d8cd187b79e00cfa7eed6fa2 (patch)
tree9262c5b483ce1d5d304fc58d7002942fd1e800b4
parent788690304a495aa6c4d3e2fa163753f28fbdb82f (diff)
parentbf6b70662bb9512e7d0e179358c174ad59c49156 (diff)
downloadgitlab-ce-429f6b629b691945d8cd187b79e00cfa7eed6fa2.tar.gz
Merge branch 'last-commit-repo-widget' into 'master'
Render last commit widget with Vue Closes #62766 See merge request gitlab-org/gitlab-ce!29419
-rw-r--r--app/assets/javascripts/repository/components/last_commit.vue145
-rw-r--r--app/assets/javascripts/repository/index.js19
-rw-r--r--app/assets/javascripts/repository/queries/pathLastCommit.query.graphql29
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap98
-rw-r--r--spec/frontend/repository/components/last_commit_spec.js103
6 files changed, 397 insertions, 0 deletions
diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue
new file mode 100644
index 00000000000..b1565699432
--- /dev/null
+++ b/app/assets/javascripts/repository/components/last_commit.vue
@@ -0,0 +1,145 @@
+<script>
+import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
+import { sprintf, s__ } from '~/locale';
+import Icon from '../../vue_shared/components/icon.vue';
+import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
+import TimeagoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
+import CommitPipelineStatus from '../../projects/tree/components/commit_pipeline_status_component.vue';
+import CiIcon from '../../vue_shared/components/ci_icon.vue';
+import ClipboardButton from '../../vue_shared/components/clipboard_button.vue';
+import getRefMixin from '../mixins/get_ref';
+import getProjectPath from '../queries/getProjectPath.graphql';
+import pathLastCommit from '../queries/pathLastCommit.query.graphql';
+
+export default {
+ components: {
+ Icon,
+ UserAvatarLink,
+ TimeagoTooltip,
+ CommitPipelineStatus,
+ ClipboardButton,
+ CiIcon,
+ GlLink,
+ GlButton,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [getRefMixin],
+ apollo: {
+ projectPath: {
+ query: getProjectPath,
+ },
+ commit: {
+ query: pathLastCommit,
+ variables() {
+ return {
+ projectPath: this.projectPath,
+ ref: this.ref,
+ path: this.currentPath.replace(/^\//, ''),
+ };
+ },
+ update: data => data.project.repository.tree.commit,
+ },
+ },
+ props: {
+ currentPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ projectPath: '',
+ commit: {},
+ showDescription: false,
+ };
+ },
+ computed: {
+ statusTitle() {
+ return sprintf(s__('Commits|Commit: %{commitText}'), {
+ commitText: this.commit.pipeline.detailedStatus.text,
+ });
+ },
+ isLoading() {
+ return this.$apollo.queries.commit.loading;
+ },
+ showCommitId() {
+ return this.commit.id.substr(0, 8);
+ },
+ },
+ methods: {
+ toggleShowDescription() {
+ this.showDescription = !this.showDescription;
+ },
+ },
+};
+</script>
+
+<template>
+ <div v-if="!isLoading" class="info-well d-none d-sm-flex project-last-commit commit p-3">
+ <user-avatar-link
+ v-if="commit.author"
+ :link-href="commit.author.webUrl"
+ :img-src="commit.author.avatarUrl"
+ :img-size="40"
+ class="avatar-cell"
+ />
+ <div class="commit-detail flex-list">
+ <div class="commit-content qa-commit-content">
+ <gl-link :href="commit.webUrl" class="commit-row-message item-title">
+ {{ commit.title }}
+ </gl-link>
+ <gl-button
+ v-if="commit.description"
+ :class="{ open: showDescription }"
+ :aria-label="__('Show commit description')"
+ class="text-expander"
+ @click="toggleShowDescription"
+ >
+ <icon name="ellipsis_h" />
+ </gl-button>
+ <div class="committer">
+ <gl-link
+ v-if="commit.author"
+ :href="commit.author.webUrl"
+ class="commit-author-link js-user-link"
+ >
+ {{ commit.author.name }}
+ </gl-link>
+ authored
+ <timeago-tooltip :time="commit.authoredDate" tooltip-placement="bottom" />
+ </div>
+ <pre
+ v-if="commit.description"
+ v-show="showDescription"
+ class="commit-row-description append-bottom-8"
+ >
+ {{ commit.description }}
+ </pre>
+ </div>
+ <div class="commit-actions flex-row">
+ <gl-link
+ v-if="commit.pipeline"
+ v-gl-tooltip
+ :href="commit.pipeline.detailedStatus.detailsPath"
+ :title="statusTitle"
+ class="js-commit-pipeline"
+ >
+ <ci-icon :status="commit.pipeline.detailedStatus" :size="24" :aria-label="statusTitle" />
+ </gl-link>
+ <div class="commit-sha-group d-flex">
+ <div class="label label-monospace monospace">
+ {{ showCommitId }}
+ </div>
+ <clipboard-button
+ :text="commit.id"
+ :title="__('Copy commit SHA to clipboard')"
+ tooltip-placement="bottom"
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js
index 52f53be045b..d9216e88676 100644
--- a/app/assets/javascripts/repository/index.js
+++ b/app/assets/javascripts/repository/index.js
@@ -2,6 +2,7 @@ import Vue from 'vue';
import createRouter from './router';
import App from './components/app.vue';
import Breadcrumbs from './components/breadcrumbs.vue';
+import LastCommit from './components/last_commit.vue';
import apolloProvider from './graphql';
import { setTitle } from './utils/title';
@@ -48,6 +49,24 @@ export default function setupVueRepositoryList() {
},
});
+ const commitEl = document.getElementById('js-last-commit');
+
+ if (commitEl) {
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: commitEl,
+ router,
+ apolloProvider,
+ render(h) {
+ return h(LastCommit, {
+ props: {
+ currentPath: this.$route.params.pathMatch,
+ },
+ });
+ },
+ });
+ }
+
return new Vue({
el,
router,
diff --git a/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql b/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql
new file mode 100644
index 00000000000..90901f54d54
--- /dev/null
+++ b/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql
@@ -0,0 +1,29 @@
+query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) {
+ project(fullPath: $projectPath) {
+ repository {
+ tree(path: $path, ref: $ref) {
+ commit {
+ id
+ title
+ message
+ webUrl
+ authoredDate
+ author {
+ name
+ avatarUrl
+ webUrl
+ }
+ pipeline {
+ detailedStatus {
+ detailsPath
+ icon
+ tooltip
+ text
+ group
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 0cabaeabb9a..e89b1e754f2 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -9140,6 +9140,9 @@ msgstr ""
msgid "Show comments only"
msgstr ""
+msgid "Show commit description"
+msgstr ""
+
msgid "Show complete raw log"
msgstr ""
diff --git a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
new file mode 100644
index 00000000000..3ad6bfa9e5f
--- /dev/null
+++ b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
@@ -0,0 +1,98 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Repository last commit component renders commit widget 1`] = `
+<div
+ class="info-well d-none d-sm-flex project-last-commit commit p-3"
+>
+ <useravatarlink-stub
+ class="avatar-cell"
+ imgalt=""
+ imgcssclasses=""
+ imgsize="40"
+ imgsrc="https://test.com"
+ linkhref="https://test.com/test"
+ tooltipplacement="top"
+ tooltiptext=""
+ username=""
+ />
+
+ <div
+ class="commit-detail flex-list"
+ >
+ <div
+ class="commit-content qa-commit-content"
+ >
+ <gllink-stub
+ class="commit-row-message item-title"
+ href="https://test.com/commit/123"
+ >
+
+ Commit title
+
+ </gllink-stub>
+
+ <!---->
+
+ <div
+ class="committer"
+ >
+ <gllink-stub
+ class="commit-author-link js-user-link"
+ href="https://test.com/test"
+ >
+
+ Test
+
+ </gllink-stub>
+
+ authored
+
+ <timeagotooltip-stub
+ cssclass=""
+ time="2019-01-01"
+ tooltipplacement="bottom"
+ />
+ </div>
+
+ <!---->
+ </div>
+
+ <div
+ class="commit-actions flex-row"
+ >
+ <gllink-stub
+ class="js-commit-pipeline"
+ data-original-title="Commit: failed"
+ href="https://test.com/pipeline"
+ title=""
+ >
+ <ciicon-stub
+ aria-label="Commit: failed"
+ cssclasses=""
+ size="24"
+ status="[object Object]"
+ />
+ </gllink-stub>
+
+ <div
+ class="commit-sha-group d-flex"
+ >
+ <div
+ class="label label-monospace monospace"
+ >
+
+ 12345678
+
+ </div>
+
+ <clipboardbutton-stub
+ cssclass="btn-default"
+ text="123456789"
+ title="Copy commit SHA to clipboard"
+ tooltipplacement="bottom"
+ />
+ </div>
+ </div>
+ </div>
+</div>
+`;
diff --git a/spec/frontend/repository/components/last_commit_spec.js b/spec/frontend/repository/components/last_commit_spec.js
new file mode 100644
index 00000000000..972690a60f6
--- /dev/null
+++ b/spec/frontend/repository/components/last_commit_spec.js
@@ -0,0 +1,103 @@
+import { shallowMount } from '@vue/test-utils';
+import LastCommit from '~/repository/components/last_commit.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+
+let vm;
+
+function createCommitData(data = {}) {
+ return {
+ id: '123456789',
+ title: 'Commit title',
+ message: 'Commit message',
+ webUrl: 'https://test.com/commit/123',
+ authoredDate: '2019-01-01',
+ author: {
+ name: 'Test',
+ avatarUrl: 'https://test.com',
+ webUrl: 'https://test.com/test',
+ },
+ pipeline: {
+ detailedStatus: {
+ detailsPath: 'https://test.com/pipeline',
+ icon: 'failed',
+ tooltip: 'failed',
+ text: 'failed',
+ group: {},
+ },
+ },
+ ...data,
+ };
+}
+
+function factory(commit = createCommitData(), loading = false) {
+ vm = shallowMount(LastCommit, {
+ mocks: {
+ $apollo: {
+ queries: {
+ commit: {
+ loading: true,
+ },
+ },
+ },
+ },
+ });
+ vm.setData({ commit });
+ vm.vm.$apollo.queries.commit.loading = loading;
+}
+
+describe('Repository last commit component', () => {
+ afterEach(() => {
+ vm.destroy();
+ });
+
+ it.each`
+ loading | label
+ ${true} | ${'hides'}
+ ${false} | ${'shows'}
+ `('$label when $loading is true', ({ loading }) => {
+ factory(createCommitData(), loading);
+
+ expect(vm.isEmpty()).toBe(loading);
+ });
+
+ it('renders commit widget', () => {
+ factory();
+
+ expect(vm.element).toMatchSnapshot();
+ });
+
+ it('renders short commit ID', () => {
+ factory();
+
+ expect(vm.find('.label-monospace').text()).toEqual('12345678');
+ });
+
+ it('hides pipeline components when pipeline does not exist', () => {
+ factory(createCommitData({ pipeline: null }));
+
+ expect(vm.find('.js-commit-pipeline').exists()).toBe(false);
+ });
+
+ it('hides author component when author does not exist', () => {
+ factory(createCommitData({ author: null }));
+
+ expect(vm.find('.js-user-link').exists()).toBe(false);
+ expect(vm.find(UserAvatarLink).exists()).toBe(false);
+ });
+
+ it('does not render description expander when description is null', () => {
+ factory(createCommitData({ description: null }));
+
+ expect(vm.find('.text-expander').exists()).toBe(false);
+ expect(vm.find('.commit-row-description').exists()).toBe(false);
+ });
+
+ it('expands commit description when clicking expander', () => {
+ factory(createCommitData({ description: 'Test description' }));
+
+ vm.find('.text-expander').vm.$emit('click');
+
+ expect(vm.find('.commit-row-description').isVisible()).toBe(true);
+ expect(vm.find('.text-expander').classes('open')).toBe(true);
+ });
+});