diff --git a/app/assets/javascripts/merge_requests/list/queries/merge_request.fragment.graphql b/app/assets/javascripts/merge_requests/list/queries/merge_request.fragment.graphql index e800b37f9a2ced19cc58075efcb03164fb2a4375..abdf06db3c672f1979b3d6effd0d88edc94d79cb 100644 --- a/app/assets/javascripts/merge_requests/list/queries/merge_request.fragment.graphql +++ b/app/assets/javascripts/merge_requests/list/queries/merge_request.fragment.graphql @@ -9,6 +9,7 @@ fragment MergeRequestFragment on MergeRequest { state title updatedAt + mergedAt upvotes resolvedDiscussionsCount @include(if: $isSignedIn) resolvableDiscussionsCount @include(if: $isSignedIn) diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue index 2bc692d7b630282e04fb01c670bbfdb359447829..1cb9ac53453911deb0adf0c741d9255183676c7e 100644 --- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue +++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue @@ -166,6 +166,9 @@ export default { isClosed() { return [STATUS_CLOSED, STATE_CLOSED].includes(this.issuable.state); }, + statusTooltip() { + return this.issuable.mergedAt ? this.tooltipTitle(this.issuable.mergedAt) : ''; + }, timestamp() { return this.isClosed && this.issuable.closedAt ? this.issuable.closedAt @@ -495,7 +498,12 @@ export default { <ul v-if="showIssuableMeta" class="controls gl-gap-3"> <!-- eslint-disable-next-line @gitlab/vue-prefer-dollar-scopedslots --> <li v-if="$slots.status" data-testid="issuable-status" class="!gl-mr-0"> - <gl-badge v-if="!isOpen" :variant="statusBadgeVariant"> + <gl-badge + v-if="!isOpen" + v-gl-tooltip.top + :variant="statusBadgeVariant" + :title="statusTooltip" + > <slot name="status"></slot> </gl-badge> <slot v-else name="status"></slot> diff --git a/spec/frontend/merge_requests/list/mock_data.js b/spec/frontend/merge_requests/list/mock_data.js index 1dc2106426b20b891315f74f4a10612ed17cd554..a8d62027b065be02280af2ba5f7e93997030e05f 100644 --- a/spec/frontend/merge_requests/list/mock_data.js +++ b/spec/frontend/merge_requests/list/mock_data.js @@ -21,6 +21,7 @@ export const getQueryResponse = { state: 'opened', title: 'Merge request title', updatedAt: '2021-05-22T04:08:01Z', + mergedAt: '2021-05-22T04:08:01Z', upvotes: 3, resolvedDiscussionsCount: 4, resolvableDiscussionsCount: 4, diff --git a/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js b/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js index b9e66f94d021ac4c0671f1fd99a745ff682397a5..3fd59f4652fc19b13fa7e9d635a9aaaffdb746e0 100644 --- a/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js +++ b/spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js @@ -546,6 +546,45 @@ describe('IssuableItem', () => { expect(statusEl.text()).toBe(`${closedMockIssuable.state}`); }); + it('renders the mergedAt date as a tooltip of the status badge if the issuable has that value', () => { + const mergedMockIssuable = { + ...mockIssuable, + state: 'merged', + mergedAt: '2000-01-01T00:00:00Z', + }; + wrapper = createComponent({ + issuableSymbol: '!', + issuable: mergedMockIssuable, + slots: { + status: mergedMockIssuable.state, + }, + }); + const statusEl = findStatusEl(); + const statusBadge = statusEl.findComponent(GlBadge); + + expect(statusBadge.exists()).toBe(true); + expect(statusBadge.attributes('title')).toBe('January 1, 2000 at 12:00:00 AM GMT'); + }); + + it('does not render a tooltip if the issuable doesn\t have a mergedAt value', () => { + const mergedMockIssuable = { + ...mockIssuable, + state: 'merged', + }; + wrapper = createComponent({ + issuableSymbol: '!', + issuable: mergedMockIssuable, + slots: { + status: mergedMockIssuable.state, + }, + }); + const statusEl = findStatusEl(); + const statusBadge = statusEl.findComponent(GlBadge); + + expect(statusBadge.exists()).toBe(true); + expect(statusBadge.attributes('title')).toBe(''); + }); + it('renders issuable status without badge if open', () => { wrapper = createComponent({ issuableSymbol: '#',