Commit 9fafab8b authored by Coung Ngo's avatar Coung Ngo Committed by Brandon Labuschagne

Simplify issuable_list markup

parent 7f9d4c2a
<script> <script>
import { GlLink, GlIcon, GlLabel, GlFormCheckbox, GlTooltipDirective } from '@gitlab/ui'; import { GlLink, GlIcon, GlLabel, GlFormCheckbox, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { isScopedLabel } from '~/lib/utils/common_utils'; import { isScopedLabel } from '~/lib/utils/common_utils';
...@@ -15,6 +15,7 @@ export default { ...@@ -15,6 +15,7 @@ export default {
GlIcon, GlIcon,
GlLabel, GlLabel,
GlFormCheckbox, GlFormCheckbox,
GlSprintf,
IssuableAssignees, IssuableAssignees,
}, },
directives: { directives: {
...@@ -82,9 +83,7 @@ export default { ...@@ -82,9 +83,7 @@ export default {
return this.issuable.assignees?.nodes || this.issuable.assignees || []; return this.issuable.assignees?.nodes || this.issuable.assignees || [];
}, },
createdAt() { createdAt() {
return sprintf(__('created %{timeAgo}'), { return getTimeago().format(this.issuable.createdAt);
timeAgo: getTimeago().format(this.issuable.createdAt),
});
}, },
updatedAt() { updatedAt() {
return sprintf(__('updated %{timeAgo}'), { return sprintf(__('updated %{timeAgo}'), {
...@@ -164,24 +163,21 @@ export default { ...@@ -164,24 +163,21 @@ export default {
<template> <template>
<li <li
:id="`issuable_${issuableId}`" :id="`issuable_${issuableId}`"
class="issue gl-px-5!" class="issue gl-display-flex! gl-px-5!"
:class="{ closed: issuable.closedAt, today: createdInPastDay }" :class="{ closed: issuable.closedAt, today: createdInPastDay }"
:data-labels="labelIdsString" :data-labels="labelIdsString"
> >
<div class="issuable-info-container">
<div v-if="showCheckbox" class="issue-check">
<gl-form-checkbox <gl-form-checkbox
class="gl-mr-0" v-if="showCheckbox"
class="issue-check gl-mr-0"
:checked="checked" :checked="checked"
:data-id="issuableId" :data-id="issuableId"
@input="$emit('checked-input', $event)" @input="$emit('checked-input', $event)"
> >
<span class="gl-sr-only">{{ issuable.title }}</span> <span class="gl-sr-only">{{ issuable.title }}</span>
</gl-form-checkbox> </gl-form-checkbox>
</div>
<div class="issuable-main-info"> <div class="issuable-main-info">
<div data-testid="issuable-title" class="issue-title title"> <div data-testid="issuable-title" class="issue-title title">
<span class="issue-title-text" dir="auto">
<gl-icon <gl-icon
v-if="issuable.confidential" v-if="issuable.confidential"
v-gl-tooltip v-gl-tooltip
...@@ -189,11 +185,10 @@ export default { ...@@ -189,11 +185,10 @@ export default {
:title="__('Confidential')" :title="__('Confidential')"
:aria-label="__('Confidential')" :aria-label="__('Confidential')"
/> />
<gl-link :href="webUrl" v-bind="issuableTitleProps"> <gl-link class="issue-title-text" dir="auto" :href="webUrl" v-bind="issuableTitleProps">
{{ issuable.title {{ issuable.title }}
}}<gl-icon v-if="isIssuableUrlExternal" name="external-link" class="gl-ml-2" <gl-icon v-if="isIssuableUrlExternal" name="external-link" class="gl-ml-2" />
/></gl-link> </gl-link>
</span>
<span <span
v-if="taskStatus" v-if="taskStatus"
class="task-status gl-display-none gl-sm-display-inline-block! gl-ml-3" class="task-status gl-display-none gl-sm-display-inline-block! gl-ml-3"
...@@ -207,15 +202,20 @@ export default { ...@@ -207,15 +202,20 @@ export default {
<span v-else data-testid="issuable-reference" class="issuable-reference"> <span v-else data-testid="issuable-reference" class="issuable-reference">
{{ reference }} {{ reference }}
</span> </span>
<span class="issuable-authored gl-display-none gl-sm-display-inline-block! gl-mr-3"> <span class="gl-display-none gl-sm-display-inline-block">
<span aria-hidden="true">&middot;</span> <span aria-hidden="true">&middot;</span>
<span class="issuable-authored gl-mr-3">
<gl-sprintf :message="__('created %{timeAgo} by %{author}')">
<template #timeAgo>
<span <span
v-gl-tooltip:tooltipcontainer.bottom v-gl-tooltip.bottom
data-testid="issuable-created-at"
:title="tooltipTitle(issuable.createdAt)" :title="tooltipTitle(issuable.createdAt)"
>{{ createdAt }}</span data-testid="issuable-created-at"
> >
{{ __('by') }} {{ createdAt }}
</span>
</template>
<template #author>
<slot v-if="hasSlotContents('author')" name="author"></slot> <slot v-if="hasSlotContents('author')" name="author"></slot>
<gl-link <gl-link
v-else v-else
...@@ -229,8 +229,11 @@ export default { ...@@ -229,8 +229,11 @@ export default {
> >
<span class="author">{{ author.name }}</span> <span class="author">{{ author.name }}</span>
</gl-link> </gl-link>
</template>
</gl-sprintf>
</span> </span>
<slot name="timeframe"></slot> <slot name="timeframe"></slot>
</span>
&nbsp; &nbsp;
<span v-if="labels.length" role="group" :aria-label="__('Labels')"> <span v-if="labels.length" role="group" :aria-label="__('Labels')">
<gl-label <gl-label
...@@ -252,7 +255,7 @@ export default { ...@@ -252,7 +255,7 @@ export default {
<li v-if="hasSlotContents('status')" class="issuable-status"> <li v-if="hasSlotContents('status')" class="issuable-status">
<slot name="status"></slot> <slot name="status"></slot>
</li> </li>
<li v-if="assignees.length" class="gl-display-flex"> <li v-if="assignees.length">
<issuable-assignees <issuable-assignees
:assignees="assignees" :assignees="assignees"
:icon-size="16" :icon-size="16"
...@@ -268,7 +271,7 @@ export default { ...@@ -268,7 +271,7 @@ export default {
class="issuable-comments gl-display-none gl-sm-display-block" class="issuable-comments gl-display-none gl-sm-display-block"
> >
<gl-link <gl-link
v-gl-tooltip:tooltipcontainer.top v-gl-tooltip.top
:title="__('Comments')" :title="__('Comments')"
:href="issuableNotesLink" :href="issuableNotesLink"
:class="{ 'no-comments': !notesCount }" :class="{ 'no-comments': !notesCount }"
...@@ -280,16 +283,12 @@ export default { ...@@ -280,16 +283,12 @@ export default {
</li> </li>
</ul> </ul>
<div <div
data-testid="issuable-updated-at" v-gl-tooltip.bottom
class="float-right issuable-updated-at gl-display-none gl-sm-display-inline-block" class="gl-text-gray-500 gl-display-none gl-sm-display-inline-block"
>
<span
v-gl-tooltip:tooltipcontainer.bottom
:title="tooltipTitle(issuable.updatedAt)" :title="tooltipTitle(issuable.updatedAt)"
class="issuable-updated-at" data-testid="issuable-updated-at"
>{{ updatedAt }}</span
> >
</div> {{ updatedAt }}
</div> </div>
</div> </div>
</li> </li>
......
...@@ -284,7 +284,6 @@ export default { ...@@ -284,7 +284,6 @@ export default {
<slot name="sidebar-items" :checked-issuables="bulkEditIssuables"></slot> <slot name="sidebar-items" :checked-issuables="bulkEditIssuables"></slot>
</template> </template>
</issuable-bulk-edit-sidebar> </issuable-bulk-edit-sidebar>
<div class="issuables-holder">
<ul v-if="issuablesLoading" class="content-list"> <ul v-if="issuablesLoading" class="content-list">
<li v-for="n in skeletonItemCount" :key="n" class="issue gl-px-5! gl-py-5!"> <li v-for="n in skeletonItemCount" :key="n" class="issue gl-px-5! gl-py-5!">
<gl-skeleton-loading /> <gl-skeleton-loading />
...@@ -351,5 +350,4 @@ export default { ...@@ -351,5 +350,4 @@ export default {
@input="$emit('page-change', $event)" @input="$emit('page-change', $event)"
/> />
</div> </div>
</div>
</template> </template>
...@@ -85,7 +85,7 @@ export default { ...@@ -85,7 +85,7 @@ export default {
<span> <span>
<span <span
v-if="issue.milestone" v-if="issue.milestone"
class="issuable-milestone gl-display-none gl-sm-display-inline-block! gl-mr-3" class="issuable-milestone gl-mr-3"
data-testid="issuable-milestone" data-testid="issuable-milestone"
> >
<gl-link v-gl-tooltip :href="milestoneLink" :title="milestoneDate"> <gl-link v-gl-tooltip :href="milestoneLink" :title="milestoneDate">
...@@ -96,7 +96,7 @@ export default { ...@@ -96,7 +96,7 @@ export default {
<span <span
v-if="issue.dueDate" v-if="issue.dueDate"
v-gl-tooltip v-gl-tooltip
class="issuable-due-date gl-display-none gl-sm-display-inline-block! gl-mr-3" class="issuable-due-date gl-mr-3"
:class="{ 'gl-text-red-500': showDueDateInRed }" :class="{ 'gl-text-red-500': showDueDateInRed }"
:title="__('Due date')" :title="__('Due date')"
data-testid="issuable-due-date" data-testid="issuable-due-date"
...@@ -107,21 +107,14 @@ export default { ...@@ -107,21 +107,14 @@ export default {
<span <span
v-if="timeEstimate" v-if="timeEstimate"
v-gl-tooltip v-gl-tooltip
class="gl-display-none gl-sm-display-inline-block! gl-mr-3" class="gl-mr-3"
:title="__('Estimate')" :title="__('Estimate')"
data-testid="time-estimate" data-testid="time-estimate"
> >
<gl-icon name="timer" /> <gl-icon name="timer" />
{{ timeEstimate }} {{ timeEstimate }}
</span> </span>
<weight-count <weight-count class="issuable-weight gl-mr-3" :weight="issue.weight" />
class="issuable-weight gl-display-none gl-sm-display-inline-block gl-mr-3" <issue-health-status v-if="showHealthStatus" :health-status="healthStatus" />
:weight="issue.weight"
/>
<issue-health-status
v-if="showHealthStatus"
class="gl-display-none gl-sm-display-inline-block"
:health-status="healthStatus"
/>
</span> </span>
</template> </template>
...@@ -77,7 +77,7 @@ export default { ...@@ -77,7 +77,7 @@ export default {
}; };
</script> </script>
<template> <template>
<div class="issue-assignees"> <div>
<user-avatar-link <user-avatar-link
v-for="assignee in assigneesToShow" v-for="assignee in assigneesToShow"
:key="assignee.id" :key="assignee.id"
...@@ -97,10 +97,9 @@ export default { ...@@ -97,10 +97,9 @@ export default {
</user-avatar-link> </user-avatar-link>
<span <span
v-if="numHiddenAssignees > 0" v-if="numHiddenAssignees > 0"
v-gl-tooltip v-gl-tooltip.bottom
:title="assigneesCounterTooltip" :title="assigneesCounterTooltip"
class="avatar-counter" class="avatar-counter"
data-placement="bottom"
data-qa-selector="avatar_counter_content" data-qa-selector="avatar_counter_content"
>{{ assigneeCounterLabel }}</span >{{ assigneeCounterLabel }}</span
> >
......
...@@ -673,6 +673,7 @@ ...@@ -673,6 +673,7 @@
.issuable-info-container { .issuable-info-container {
flex: 1; flex: 1;
display: flex; display: flex;
}
.issuable-main-info { .issuable-main-info {
flex: 1 auto; flex: 1 auto;
...@@ -709,7 +710,6 @@ ...@@ -709,7 +710,6 @@
} }
} }
} }
}
.issue-check { .issue-check {
padding-right: $gl-padding; padding-right: $gl-padding;
......
...@@ -24,11 +24,11 @@ export default { ...@@ -24,11 +24,11 @@ export default {
</script> </script>
<template> <template>
<div class="health-status"> <span class="health-status">
<span class="gl-label gl-label-sm" :class="statusClass"> <span class="gl-label gl-label-sm" :class="statusClass">
<span v-gl-tooltip class="gl-label-text" :title="__('Health status')"> <span v-gl-tooltip class="gl-label-text" :title="__('Health status')">
{{ statusText }} {{ statusText }}
</span> </span>
</span> </span>
</div> </span>
</template> </template>
...@@ -240,20 +240,19 @@ RSpec.describe 'epics list', :js do ...@@ -240,20 +240,19 @@ RSpec.describe 'epics list', :js do
end end
it 'renders epics item with metadata', :aggregate_failures do it 'renders epics item with metadata', :aggregate_failures do
page.within('.issuable-list-container .issuable-list') do page.within('.issuable-list .issue:first-of-type') do
expect(page.all('.issuable-info-container')[0].find('.issue-title')).to have_content(epic2.title) expect(page).to have_link(epic2.title)
expect(page.all('.issuable-info-container')[0].find('.issuable-reference')).to have_content("&#{epic2.iid}") expect(page).to have_text("&#{epic2.iid}")
expect(page.all('.issuable-info-container')[0].find('.issuable-authored')).to have_content('created') expect(page).to have_text("created just now by #{epic2.author.name}")
expect(page.all('.issuable-info-container')[0].find('.issuable-authored')).to have_content("by #{epic2.author.name}")
end end
end end
it 'renders epic item timeframe', :aggregate_failures do it 'renders epic item timeframe', :aggregate_failures do
page.within('.issuable-list-container .issuable-list') do issues = page.all('.issue')
expect(page.all('.issuable-info-container')[0].find('.issuable-info')).to have_content('Dec 15, 2020 – No due date')
expect(page.all('.issuable-info-container')[1].find('.issuable-info')).to have_content('Dec 15, 2020 – Jan 15, 2021') expect(issues[0]).to have_text('Dec 15, 2020 – No due date')
expect(page.all('.issuable-info-container')[2].find('.issuable-info')).to have_content('No start date – Jan 15, 2021') expect(issues[1]).to have_text('Dec 15, 2020 – Jan 15, 2021')
end expect(issues[2]).to have_text('No start date – Jan 15, 2021')
end end
end end
......
...@@ -74,12 +74,11 @@ RSpec.describe 'Test Cases', :js do ...@@ -74,12 +74,11 @@ RSpec.describe 'Test Cases', :js do
it 'shows test cases title and metadata' do it 'shows test cases title and metadata' do
page.within('.issuable-list-container .issuable-list li.issue', match: :first) do page.within('.issuable-list-container .issuable-list li.issue', match: :first) do
expect(page.find('.issue-title')).to have_content(test_case1.title) expect(page).to have_link(test_case1.title)
expect(page.find('.issuable-reference')).to have_content("##{test_case1.iid}") expect(page).to have_text("##{test_case1.iid}")
expect(page.find('.issuable-info')).to have_link(label.title, href: "?label_name[]=#{label.title}") expect(page).to have_link(label.title, href: "?label_name[]=#{label.title}")
expect(page.find('.issuable-authored')).to have_content('created 5 days ago by') expect(page).to have_text("created 5 days ago by #{user.name}")
expect(page.find('.author')).to have_content(user.name) expect(page).to have_text('updated 2 days ago')
expect(page.find('div.issuable-updated-at')).to have_content('updated 2 days ago')
end end
end end
end end
......
...@@ -39900,6 +39900,9 @@ msgstr "" ...@@ -39900,6 +39900,9 @@ msgstr ""
msgid "created %{timeAgo}" msgid "created %{timeAgo}"
msgstr "" msgstr ""
msgid "created %{timeAgo} by %{author}"
msgstr ""
msgid "created by" msgid "created by"
msgstr "" msgstr ""
......
import { GlLink, GlLabel, GlIcon, GlFormCheckbox } from '@gitlab/ui'; import { GlLink, GlLabel, GlIcon, GlFormCheckbox, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { useFakeDate } from 'helpers/fake_date'; import { useFakeDate } from 'helpers/fake_date';
import IssuableItem from '~/issuable_list/components/issuable_item.vue'; import IssuableItem from '~/issuable_list/components/issuable_item.vue';
...@@ -16,6 +16,9 @@ const createComponent = ({ issuableSymbol = '#', issuable = mockIssuable, slots ...@@ -16,6 +16,9 @@ const createComponent = ({ issuableSymbol = '#', issuable = mockIssuable, slots
showCheckbox: false, showCheckbox: false,
}, },
slots, slots,
stubs: {
GlSprintf,
},
}); });
const MOCK_GITLAB_URL = 'http://0.0.0.0:3000'; const MOCK_GITLAB_URL = 'http://0.0.0.0:3000';
...@@ -135,13 +138,6 @@ describe('IssuableItem', () => { ...@@ -135,13 +138,6 @@ describe('IssuableItem', () => {
}); });
}); });
describe('createdAt', () => {
it('returns string containing timeago string based on `issuable.createdAt`', () => {
expect(wrapper.vm.createdAt).toContain('created');
expect(wrapper.vm.createdAt).toContain('ago');
});
});
describe('updatedAt', () => { describe('updatedAt', () => {
it('returns string containing timeago string based on `issuable.updatedAt`', () => { it('returns string containing timeago string based on `issuable.updatedAt`', () => {
expect(wrapper.vm.updatedAt).toContain('updated'); expect(wrapper.vm.updatedAt).toContain('updated');
...@@ -449,8 +445,7 @@ describe('IssuableItem', () => { ...@@ -449,8 +445,7 @@ describe('IssuableItem', () => {
it('renders issuable updatedAt info', () => { it('renders issuable updatedAt info', () => {
const updatedAtEl = wrapper.find('[data-testid="issuable-updated-at"]'); const updatedAtEl = wrapper.find('[data-testid="issuable-updated-at"]');
expect(updatedAtEl.exists()).toBe(true); expect(updatedAtEl.attributes('title')).toBe('Sep 10, 2020 11:41am UTC');
expect(updatedAtEl.find('span').attributes('title')).toBe('Sep 10, 2020 11:41am UTC');
expect(updatedAtEl.text()).toBe(wrapper.vm.updatedAt); expect(updatedAtEl.text()).toBe(wrapper.vm.updatedAt);
}); });
......
...@@ -94,10 +94,6 @@ describe('IssueAssigneesComponent', () => { ...@@ -94,10 +94,6 @@ describe('IssueAssigneesComponent', () => {
expect(vm.avatarUrlTitle(mockAssigneesList[0])).toBe('Assigned to Terrell Graham'); expect(vm.avatarUrlTitle(mockAssigneesList[0])).toBe('Assigned to Terrell Graham');
}); });
it('renders component root element with class `issue-assignees`', () => {
expect(wrapper.element.classList.contains('issue-assignees')).toBe(true);
});
it('renders assignee', () => { it('renders assignee', () => {
const data = findAvatars().wrappers.map((x) => ({ const data = findAvatars().wrappers.map((x) => ({
...x.props(), ...x.props(),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment