From c62c6dc6ff5cb3619241af96e19a012fea683baa Mon Sep 17 00:00:00 2001 From: Phil Hughes <me@iamphill.com> Date: Mon, 22 Apr 2024 14:25:18 +0100 Subject: [PATCH] Created merge request dashboard list item https://gitlab.com/gitlab-org/gitlab/-/issues/455598 --- .../components/merge_request.stories.js | 110 +++++++++++++++ .../components/merge_request.vue | 125 ++++++++++++++++++ locale/gitlab.pot | 12 ++ .../__snapshots__/merge_request_spec.js.snap | 115 ++++++++++++++++ .../components/merge_request_spec.js | 75 +++++++++++ 5 files changed, 437 insertions(+) create mode 100644 app/assets/javascripts/merge_request_dashboard/components/merge_request.stories.js create mode 100644 app/assets/javascripts/merge_request_dashboard/components/merge_request.vue create mode 100644 spec/frontend/merge_request_dashboard/components/__snapshots__/merge_request_spec.js.snap create mode 100644 spec/frontend/merge_request_dashboard/components/merge_request_spec.js diff --git a/app/assets/javascripts/merge_request_dashboard/components/merge_request.stories.js b/app/assets/javascripts/merge_request_dashboard/components/merge_request.stories.js new file mode 100644 index 0000000000000..978b9169f64c4 --- /dev/null +++ b/app/assets/javascripts/merge_request_dashboard/components/merge_request.stories.js @@ -0,0 +1,110 @@ +import MergeRequest from './merge_request.vue'; + +const Template = (_, { argTypes }) => { + return { + components: { MergeRequest }, + props: Object.keys(argTypes), + template: '<merge-request v-bind="$props" />', + }; +}; + +export default { + component: MergeRequest, + title: 'merge_requests_dashboard/merge_request', +}; + +export const Default = Template.bind({}); +Default.args = { + mergeRequest: { + reference: '!123456', + titleHtml: 'Merge request title', + author: { + name: 'John Smith', + webUrl: 'https://gitlab.com/root', + }, + milestone: { + title: '17.0', + }, + labels: { + nodes: [ + { + id: 'gid://gitlab/GroupLabel/992791', + color: '#428BCA', + title: 'Deliverable', + description: 'Label description', + }, + { + id: 'gid://gitlab/GroupLabel/3103452', + color: '#E44D2A', + title: 'devops::create', + description: 'Label description', + }, + { + id: 'gid://gitlab/GroupLabel/2975007', + color: '#F0AD4E', + title: 'feature::enhancement', + description: 'Label description', + }, + { + id: 'gid://gitlab/GroupLabel/3412464', + color: '#3cb371', + title: 'frontend', + description: 'Label description', + }, + { + id: 'gid://gitlab/GroupLabel/16934793', + color: '#A8D695', + title: 'group::code review', + description: 'Label description', + }, + { + id: 'gid://gitlab/GroupLabel/14918378', + color: '#F0AD4E', + title: 'section::dev', + description: 'Label description', + }, + { + id: 'gid://gitlab/GroupLabel/10230929', + color: '#009966', + title: 'type::feature', + description: 'Label description', + }, + ], + }, + assignees: { + nodes: [ + { + id: 'gid://gitlab/User/1', + avatarUrl: '', + name: 'John Smith', + username: 'jsmith', + webUrl: 'https://gitlab.com/root', + webPath: '/root', + }, + ], + }, + reviewers: { + nodes: [ + { + id: 'gid://gitlab/User/1', + avatarUrl: '', + name: 'John Smith', + username: 'jsmith', + webUrl: 'https://gitlab.com/root', + webPath: '/root', + }, + { + id: 'gid://gitlab/User/2', + avatarUrl: '', + name: 'John Smith', + username: 'jsmith', + webUrl: 'https://gitlab.com/root', + webPath: '/root', + }, + ], + }, + userDiscussionsCount: 5, + createdAt: '2024-04-22T10:13:09Z', + updatedAt: '2024-04-19T14:34:42Z', + }, +}; diff --git a/app/assets/javascripts/merge_request_dashboard/components/merge_request.vue b/app/assets/javascripts/merge_request_dashboard/components/merge_request.vue new file mode 100644 index 0000000000000..362f608bed2a2 --- /dev/null +++ b/app/assets/javascripts/merge_request_dashboard/components/merge_request.vue @@ -0,0 +1,125 @@ +<script> +import { GlLink, GlSprintf, GlIcon, GlLabel, GlTooltipDirective } from '@gitlab/ui'; +import { __, sprintf } from '~/locale'; +import SafeHtml from '~/vue_shared/directives/safe_html'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; +import { isScopedLabel } from '~/lib/utils/common_utils'; + +export default { + components: { + GlLink, + GlSprintf, + GlIcon, + GlLabel, + TimeAgoTooltip, + UserAvatarLink, + }, + directives: { + SafeHtml, + GlTooltip: GlTooltipDirective, + }, + props: { + mergeRequest: { + type: Object, + required: true, + }, + }, + methods: { + showScopedLabel(label) { + return isScopedLabel(label); + }, + assigneeTitle(assignee) { + return sprintf(__('Assigned to %{assignee}'), { assignee: assignee.name }); + }, + reviewerTitle(reviewer) { + return sprintf(__('Review requested %{reviewer}'), { reviewer: reviewer.name }); + }, + }, +}; +</script> + +<template> + <div class="gl-bg-white gl-p-5 gl-rounded-base"> + <div class="gl-display-flex gl-mb-2"> + <div class="gl-display-flex gl-flex-direction-column"> + <h4 class="gl-mb-0 gl-mt-0 gl-font-base"> + <gl-link + v-safe-html="mergeRequest.titleHtml" + href="#" + class="gl-text-body gl-hover-text-gray-900" + /> + </h4> + <div class="gl-font-sm gl-mt-2 gl-text-secondary"> + <gl-sprintf + :message="__('%{reference} %{divider} created %{createdAt} by %{author} %{milestone}')" + > + <template #reference>{{ mergeRequest.reference }}</template> + <template #divider>·</template> + <template #createdAt><time-ago-tooltip :time="mergeRequest.createdAt" /></template> + <template #author> + <gl-link :href="mergeRequest.author.webUrl" class="gl-text-secondary"> + {{ mergeRequest.author.name }} + </gl-link> + </template> + <template #milestone> + <gl-icon :size="16" class="gl-ml-2" name="milestone" /> + {{ mergeRequest.milestone.title }} + </template> + </gl-sprintf> + </div> + </div> + <div class="gl-ml-auto gl-display-flex gl-flex-direction-column"> + <ul class="gl-display-flex gl-justify-content-end gl-m-0 gl-p-0 gl-list-style-none"> + <li v-if="mergeRequest.assignees.nodes.length"> + <user-avatar-link + v-for="(assignee, index) in mergeRequest.assignees.nodes" + :key="`assignee_${assignee.id}`" + :link-href="assignee.webUrl" + :img-src="assignee.avatarUrl" + :img-size="24" + :tooltip-text="assigneeTitle(assignee)" + :class="{ 'gl-mr-2': index !== mergeRequest.assignees.nodes.length - 1 }" + /> + </li> + <li v-if="mergeRequest.reviewers.nodes.length" class="gl-ml-4"> + <user-avatar-link + v-for="(reviewer, index) in mergeRequest.reviewers.nodes" + :key="`reviewer_${reviewer.id}`" + :link-href="reviewer.webUrl" + :img-src="reviewer.avatarUrl" + :img-size="24" + :tooltip-text="reviewerTitle(reviewer)" + :class="{ 'gl-mr-2': index !== mergeRequest.reviewers.nodes.length - 1 }" + /> + </li> + <li + v-if="mergeRequest.userDiscussionsCount" + v-gl-tooltip="__('Comments')" + class="gl-align-self-center gl-ml-4" + > + <gl-icon name="comments" class="gl-vertical-align-middle!" /> + {{ mergeRequest.userDiscussionsCount }} + </li> + </ul> + <div v-if="mergeRequest.updatedAt" class="gl-font-sm gl-mt-2 gl-text-secondary"> + <gl-sprintf :message="__('Updated at %{updatedAt}')"> + <template #updatedAt><time-ago-tooltip :time="mergeRequest.updatedAt" /></template> + </gl-sprintf> + </div> + </div> + </div> + <div> + <gl-label + v-for="label in mergeRequest.labels.nodes" + :key="label.id" + :background-color="label.color" + :title="label.title" + :description="label.description" + size="sm" + :scoped="showScopedLabel(label)" + class="gl-mr-2" + /> + </div> + </div> +</template> diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d1f4bf53cdd50..804a447ed31b1 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1104,6 +1104,9 @@ msgstr "" msgid "%{project_path} is a project that you can use to add a README to your GitLab profile. Create a public project and initialize the repository with a README to get started. %{help_link_start}Learn more%{help_link_end}." msgstr "" +msgid "%{reference} %{divider} created %{createdAt} by %{author} %{milestone}" +msgstr "" + msgid "%{ref} cannot be added: %{error}" msgstr "" @@ -7111,6 +7114,9 @@ msgstr "" msgid "Assigned to %{assignee_name}" msgstr "" +msgid "Assigned to %{assignee}" +msgstr "" + msgid "Assigned to me" msgstr "" @@ -43577,6 +43583,9 @@ msgstr "" msgid "Review changes" msgstr "" +msgid "Review requested %{reviewer}" +msgstr "" + msgid "Review requests" msgstr "" @@ -55153,6 +55162,9 @@ msgstr "" msgid "Updated %{updated_at} by %{updated_by}" msgstr "" +msgid "Updated at %{updatedAt}" +msgstr "" + msgid "Updated date" msgstr "" diff --git a/spec/frontend/merge_request_dashboard/components/__snapshots__/merge_request_spec.js.snap b/spec/frontend/merge_request_dashboard/components/__snapshots__/merge_request_spec.js.snap new file mode 100644 index 0000000000000..c3e4d58f0e76f --- /dev/null +++ b/spec/frontend/merge_request_dashboard/components/__snapshots__/merge_request_spec.js.snap @@ -0,0 +1,115 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Merge request dashboard merge request component renders template 1`] = ` +<div + class="gl-bg-white gl-p-5 gl-rounded-base" +> + <div + class="gl-display-flex gl-mb-2" + > + <div + class="gl-display-flex gl-flex-direction-column" + > + <h4 + class="gl-font-base gl-mb-0 gl-mt-0" + > + <gl-link-stub + class="gl-hover-text-gray-900 gl-text-body" + href="#" + > + Merge request title + </gl-link-stub> + </h4> + <div + class="gl-font-sm gl-mt-2 gl-text-secondary" + > + <gl-sprintf-stub + message="%{reference} %{divider} created %{createdAt} by %{author} %{milestone}" + /> + </div> + </div> + <div + class="gl-display-flex gl-flex-direction-column gl-ml-auto" + > + <ul + class="gl-display-flex gl-justify-content-end gl-list-style-none gl-m-0 gl-p-0" + > + <li> + <user-avatar-link-stub + imgalt="" + imgcssclasses="" + imgcsswrapperclasses="" + imgsize="24" + imgsrc="" + linkhref="https://gitlab.com/root" + popoveruserid="" + popoverusername="" + tooltipplacement="top" + tooltiptext="Assigned to John Smith" + username="" + /> + </li> + <li + class="gl-ml-4" + > + <user-avatar-link-stub + class="gl-mr-2" + imgalt="" + imgcssclasses="" + imgcsswrapperclasses="" + imgsize="24" + imgsrc="" + linkhref="https://gitlab.com/root" + popoveruserid="" + popoverusername="" + tooltipplacement="top" + tooltiptext="Review requested John Smith" + username="" + /> + <user-avatar-link-stub + imgalt="" + imgcssclasses="" + imgcsswrapperclasses="" + imgsize="24" + imgsrc="" + linkhref="https://gitlab.com/root" + popoveruserid="" + popoverusername="" + tooltipplacement="top" + tooltiptext="Review requested John Smith" + username="" + /> + </li> + <li + class="gl-align-self-center gl-ml-4" + > + <gl-icon-stub + class="gl-vertical-align-middle!" + name="comments" + size="16" + /> + 5 + </li> + </ul> + <div + class="gl-font-sm gl-mt-2 gl-text-secondary" + > + <gl-sprintf-stub + message="Updated at %{updatedAt}" + /> + </div> + </div> + </div> + <div> + <gl-label-stub + backgroundcolor="#428BCA" + class="gl-mr-2" + description="Label description" + size="sm" + target="" + title="Deliverable" + tooltipplacement="top" + /> + </div> +</div> +`; diff --git a/spec/frontend/merge_request_dashboard/components/merge_request_spec.js b/spec/frontend/merge_request_dashboard/components/merge_request_spec.js new file mode 100644 index 0000000000000..709bbc46ae55e --- /dev/null +++ b/spec/frontend/merge_request_dashboard/components/merge_request_spec.js @@ -0,0 +1,75 @@ +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import MergeRequest from '~/merge_request_dashboard/components/merge_request.vue'; + +describe('Merge request dashboard merge request component', () => { + let wrapper; + + function createComponent() { + wrapper = shallowMountExtended(MergeRequest, { + propsData: { + mergeRequest: { + reference: '!123456', + titleHtml: 'Merge request title', + author: { + name: 'John Smith', + webUrl: 'https://gitlab.com/root', + }, + milestone: { + title: '17.0', + }, + labels: { + nodes: [ + { + id: 'gid://gitlab/GroupLabel/992791', + color: '#428BCA', + title: 'Deliverable', + description: 'Label description', + }, + ], + }, + assignees: { + nodes: [ + { + id: 'gid://gitlab/User/1', + avatarUrl: '', + name: 'John Smith', + username: 'jsmith', + webUrl: 'https://gitlab.com/root', + webPath: '/root', + }, + ], + }, + reviewers: { + nodes: [ + { + id: 'gid://gitlab/User/1', + avatarUrl: '', + name: 'John Smith', + username: 'jsmith', + webUrl: 'https://gitlab.com/root', + webPath: '/root', + }, + { + id: 'gid://gitlab/User/2', + avatarUrl: '', + name: 'John Smith', + username: 'jsmith', + webUrl: 'https://gitlab.com/root', + webPath: '/root', + }, + ], + }, + userDiscussionsCount: 5, + createdAt: '2024-04-22T10:13:09Z', + updatedAt: '2024-04-19T14:34:42Z', + }, + }, + }); + } + + it('renders template', () => { + createComponent(); + + expect(wrapper.element).toMatchSnapshot(); + }); +}); -- GitLab