Commit 2ed17c6e authored by Eulyeon Ko's avatar Eulyeon Ko Committed by Peter Hegman

Display iteration dates in issues filtered search

Auto-generated iterations (for a cadence) do not
hardcode start/due dates in their titles and
the frontend should utilize start/date attributes
and display them separately.
parent 1b3a4e6e
......@@ -329,13 +329,13 @@ export default {
class="board-title-main-text gl-text-truncate"
>
{{ listTitle }}
<div
<span
v-if="iterationCadencesAvailable"
class="gl-display-inline-block"
class="gl-display-inline-block gl-text-gray-400"
data-testid="board-list-iteration-period"
>
<time class="gl-text-gray-400">{{ listIterationPeriod }}</time>
</div>
{{ listIterationPeriod }}</span
>
</span>
<span
v-if="listType === 'assignee'"
......
fragment Iteration on Iteration {
id
title
startDate
dueDate
iterationCadence {
id
title
......
......@@ -4,6 +4,8 @@ import createFlash from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
import { formatDate } from '~/lib/utils/datetime_utility';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { DEFAULT_ITERATIONS } from '../constants';
export default {
......@@ -13,6 +15,7 @@ export default {
GlDropdownSectionHeader,
GlFilteredSearchSuggestion,
},
mixins: [glFeatureFlagMixin()],
props: {
active: {
type: Boolean,
......@@ -49,7 +52,11 @@ export default {
return;
}
const { title } = iteration.iterationCadence;
const cadenceIteration = { id: iteration.id, title: iteration.title };
const cadenceIteration = {
id: iteration.id,
title: iteration.title,
period: this.getIterationPeriod(iteration),
};
const cadence = cadences.find((cad) => cad.title === title);
if (cadence) {
cadence.iterations.push(cadenceIteration);
......@@ -76,6 +83,16 @@ export default {
getValue(iteration) {
return String(getIdFromGraphQLId(iteration.id));
},
/**
* TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/344619
* This method also exists as a utility function in ee/../iterations/utils.js
* Remove the duplication when iteration token is moved to EE.
*/
getIterationPeriod({ startDate, dueDate }) {
const start = formatDate(startDate, 'mmm d, yyyy', true);
const due = formatDate(dueDate, 'mmm d, yyyy', true);
return `${start} - ${due}`;
},
},
};
</script>
......@@ -111,6 +128,9 @@ export default {
:value="getValue(iteration)"
>
{{ iteration.title }}
<div v-if="glFeatures.iterationCadences" class="gl-text-gray-400">
{{ iteration.period }}
</div>
</gl-filtered-search-suggestion>
</template>
</template>
......
<template>
<div>
<time class="gl-text-gray-400">
<div class="gl-text-gray-400">
<slot></slot>
</time>
</div>
</template>
......@@ -123,18 +123,21 @@ RSpec.describe 'Filter issues by iteration', :js do
click_link '= is'
end
it 'shows cadence titles and iteration titles', :aggregate_failures do
it 'shows cadence titles, and iteration titles and dates', :aggregate_failures do
within '.gl-filtered-search-suggestion-list' do
# cadence 1 grouping
expect(page).to have_css('li:nth-child(5)', text: cadence_1.title)
expect(page).to have_css('li:nth-child(6)', text: iteration_1.title)
expect(page).to have_css('li:nth-child(7)', text: iteration_3.title)
expect(page).to have_css('li:nth-child(6)', text: "#{iteration_1.title} #{iteration_period(iteration_1)}")
expect(page).to have_css('li:nth-child(7)', text: "#{iteration_3.title} #{iteration_period(iteration_3)}")
# cadence 2 grouping
expect(page).to have_css('li:nth-child(9)', text: cadence_2.title)
expect(page).to have_css('li:nth-child(10)', text: iteration_2.title)
expect(page).to have_css('li:nth-child(10)', text: "#{iteration_2.title} #{iteration_period(iteration_2)}")
end
end
end
def iteration_period(iteration)
"#{iteration.start_date.to_s(:medium)} - #{iteration.due_date.to_s(:medium)}"
end
end
context 'project issues list' do
......
......@@ -111,6 +111,18 @@ export const mockIterationToken = {
fetchIterations: () => Promise.resolve(),
};
export const mockIterations = [
{
id: 1,
title: 'Iteration 1',
startDate: '2021-11-05',
dueDate: '2021-11-10',
iterationCadence: {
title: 'Cadence 1',
},
},
];
export const mockLabelToken = {
type: 'label_name',
icon: 'labels',
......
import { GlFilteredSearchToken, GlFilteredSearchTokenSegment } from '@gitlab/ui';
import {
GlFilteredSearchToken,
GlFilteredSearchTokenSegment,
GlFilteredSearchSuggestion,
} from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash';
import IterationToken from '~/vue_shared/components/filtered_search_bar/tokens/iteration_token.vue';
import { mockIterationToken } from '../mock_data';
import { mockIterationToken, mockIterations } from '../mock_data';
jest.mock('~/flash');
......@@ -11,10 +15,16 @@ describe('IterationToken', () => {
const id = 123;
let wrapper;
const createComponent = ({ config = mockIterationToken, value = { data: '' } } = {}) =>
const createComponent = ({
config = mockIterationToken,
value = { data: '' },
active = false,
stubs = {},
provide = {},
} = {}) =>
mount(IterationToken, {
propsData: {
active: false,
active,
config,
value,
},
......@@ -22,13 +32,39 @@ describe('IterationToken', () => {
portalName: 'fake target',
alignSuggestions: function fakeAlignSuggestions() {},
suggestionsListClass: () => 'custom-class',
...provide,
},
stubs,
});
afterEach(() => {
wrapper.destroy();
});
describe('when iteration cadence feature is available', () => {
beforeEach(async () => {
wrapper = createComponent({
active: true,
config: { ...mockIterationToken, initialIterations: mockIterations },
value: { data: 'i' },
stubs: { Portal: true },
provide: {
glFeatures: {
iterationCadences: true,
},
},
});
await wrapper.setData({ loading: false });
});
it('renders iteration start date and due date', () => {
const suggestions = wrapper.findAll(GlFilteredSearchSuggestion);
expect(suggestions.at(3).text()).toContain('Nov 5, 2021 - Nov 10, 2021');
});
});
it('renders iteration value', async () => {
wrapper = createComponent({ value: { data: id } });
......
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