Commit 0d64f63f authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera

Merge branch '331420-time-tracking-report-is-bugged-on-graphql-boards' into 'master'

Resolve "Time tracking report is bugged on GraphQL boards"

See merge request gitlab-org/gitlab!62109
parents 0a9f56bd ff284318
...@@ -15,6 +15,7 @@ export default { ...@@ -15,6 +15,7 @@ export default {
<template> <template>
<issuable-time-tracker <issuable-time-tracker
:issuable-id="activeBoardItem.id.toString()"
:time-estimate="activeBoardItem.timeEstimate" :time-estimate="activeBoardItem.timeEstimate"
:time-spent="activeBoardItem.totalTimeSpent" :time-spent="activeBoardItem.totalTimeSpent"
:human-time-estimate="activeBoardItem.humanTimeEstimate" :human-time-estimate="activeBoardItem.humanTimeEstimate"
......
...@@ -13,13 +13,17 @@ export default { ...@@ -13,13 +13,17 @@ export default {
GlLoadingIcon, GlLoadingIcon,
GlTable, GlTable,
}, },
inject: ['issuableId', 'issuableType'], inject: ['issuableType'],
props: { props: {
limitToHours: { limitToHours: {
type: Boolean, type: Boolean,
default: false, default: false,
required: false, required: false,
}, },
issuableId: {
type: String,
required: true,
},
}, },
data() { data() {
return { report: [], isLoading: true }; return { report: [], isLoading: true };
......
...@@ -13,6 +13,12 @@ export default { ...@@ -13,6 +13,12 @@ export default {
components: { components: {
IssuableTimeTracker, IssuableTimeTracker,
}, },
props: {
issuableId: {
type: String,
required: true,
},
},
data() { data() {
return { return {
mediator: new Mediator(), mediator: new Mediator(),
...@@ -51,6 +57,7 @@ export default { ...@@ -51,6 +57,7 @@ export default {
<template> <template>
<div class="block"> <div class="block">
<issuable-time-tracker <issuable-time-tracker
:issuable-id="issuableId"
:time-estimate="store.timeEstimate" :time-estimate="store.timeEstimate"
:time-spent="store.totalTimeSpent" :time-spent="store.totalTimeSpent"
:human-time-estimate="store.humanTimeEstimate" :human-time-estimate="store.humanTimeEstimate"
......
<script> <script>
import { GlIcon, GlLink, GlModal, GlModalDirective } from '@gitlab/ui'; import { GlIcon, GlLink, GlModal, GlModalDirective } from '@gitlab/ui';
import { IssuableType } from '~/issue_show/constants';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
import TimeTrackingCollapsedState from './collapsed_state.vue'; import TimeTrackingCollapsedState from './collapsed_state.vue';
...@@ -27,6 +28,7 @@ export default { ...@@ -27,6 +28,7 @@ export default {
directives: { directives: {
GlModal: GlModalDirective, GlModal: GlModalDirective,
}, },
inject: ['issuableType'],
props: { props: {
timeEstimate: { timeEstimate: {
type: Number, type: Number,
...@@ -51,6 +53,11 @@ export default { ...@@ -51,6 +53,11 @@ export default {
default: false, default: false,
required: false, required: false,
}, },
issuableId: {
type: String,
required: false,
default: '',
},
/* /*
In issue list, "time-tracking-collapsed-state" is always rendered even if the sidebar isn't collapsed. In issue list, "time-tracking-collapsed-state" is always rendered even if the sidebar isn't collapsed.
The actual hiding is controlled with css classes: The actual hiding is controlled with css classes:
...@@ -94,6 +101,12 @@ export default { ...@@ -94,6 +101,12 @@ export default {
showHelpState() { showHelpState() {
return Boolean(this.showHelp); return Boolean(this.showHelp);
}, },
isTimeReportSupported() {
return (
[IssuableType.Issue, IssuableType.MergeRequest].includes(this.issuableType) &&
this.issuableId
);
},
}, },
created() { created() {
eventHub.$on('timeTracker:updateData', this.update); eventHub.$on('timeTracker:updateData', this.update);
...@@ -167,21 +180,23 @@ export default { ...@@ -167,21 +180,23 @@ export default {
:time-estimate-human-readable="humanTimeEstimate" :time-estimate-human-readable="humanTimeEstimate"
:limit-to-hours="limitToHours" :limit-to-hours="limitToHours"
/> />
<gl-link <template v-if="isTimeReportSupported">
v-if="hasTimeSpent" <gl-link
v-gl-modal="'time-tracking-report'" v-if="hasTimeSpent"
data-testid="reportLink" v-gl-modal="'time-tracking-report'"
href="#" data-testid="reportLink"
class="btn-link" href="#"
>{{ __('Time tracking report') }}</gl-link class="btn-link"
> >{{ __('Time tracking report') }}</gl-link
<gl-modal >
modal-id="time-tracking-report" <gl-modal
:title="__('Time tracking report')" modal-id="time-tracking-report"
:hide-footer="true" :title="__('Time tracking report')"
> :hide-footer="true"
<time-tracking-report :limit-to-hours="limitToHours" /> >
</gl-modal> <time-tracking-report :limit-to-hours="limitToHours" :issuable-id="issuableId" />
</gl-modal>
</template>
<transition name="help-state-toggle"> <transition name="help-state-toggle">
<time-tracking-help-state v-if="showHelpState" /> <time-tracking-help-state v-if="showHelpState" />
</transition> </transition>
......
import Vue from 'vue'; import Vue from 'vue';
import { IssuableType } from '~/issue_show/constants';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import timeTracker from './components/time_tracking/time_tracker.vue'; import timeTracker from './components/time_tracking/time_tracker.vue';
...@@ -8,7 +9,14 @@ export default class SidebarMilestone { ...@@ -8,7 +9,14 @@ export default class SidebarMilestone {
if (!el) return; if (!el) return;
const { timeEstimate, timeSpent, humanTimeEstimate, humanTimeSpent, limitToHours } = el.dataset; const {
timeEstimate,
timeSpent,
humanTimeEstimate,
humanTimeSpent,
limitToHours,
id,
} = el.dataset;
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Vue({ new Vue({
...@@ -16,6 +24,9 @@ export default class SidebarMilestone { ...@@ -16,6 +24,9 @@ export default class SidebarMilestone {
components: { components: {
timeTracker, timeTracker,
}, },
provide: {
issuableType: IssuableType.Milestone,
},
render: (createElement) => render: (createElement) =>
createElement('timeTracker', { createElement('timeTracker', {
props: { props: {
...@@ -24,6 +35,7 @@ export default class SidebarMilestone { ...@@ -24,6 +35,7 @@ export default class SidebarMilestone {
humanTimeEstimate, humanTimeEstimate,
humanTimeSpent, humanTimeSpent,
limitToHours: parseBoolean(limitToHours), limitToHours: parseBoolean(limitToHours),
issuableId: id.toString(),
}, },
}), }),
}); });
......
...@@ -383,8 +383,13 @@ function mountTimeTrackingComponent() { ...@@ -383,8 +383,13 @@ function mountTimeTrackingComponent() {
new Vue({ new Vue({
el, el,
apolloProvider, apolloProvider,
provide: { issuableId: id, issuableType }, provide: { issuableType },
render: (createElement) => createElement(SidebarTimeTracking, {}), render: (createElement) =>
createElement(SidebarTimeTracking, {
props: {
issuableId: id.toString(),
},
}),
}); });
} }
......
...@@ -4,4 +4,5 @@ ...@@ -4,4 +4,5 @@
":human-time-estimate" => "issue.humanTimeEstimate", ":human-time-estimate" => "issue.humanTimeEstimate",
":human-time-spent" => "issue.humanTimeSpent", ":human-time-spent" => "issue.humanTimeSpent",
":limit-to-hours" => "timeTrackingLimitToHours", ":limit-to-hours" => "timeTrackingLimitToHours",
":issuable-id" => "issue.id",
"root-path" => "#{root_url}" } "root-path" => "#{root_url}" }
...@@ -98,6 +98,7 @@ ...@@ -98,6 +98,7 @@
time_spent: @milestone.total_time_spent, time_spent: @milestone.total_time_spent,
human_time_estimate: @milestone.human_total_time_estimate, human_time_estimate: @milestone.human_total_time_estimate,
human_time_spent: @milestone.human_total_time_spent, human_time_spent: @milestone.human_total_time_spent,
id: @milestone.id,
limit_to_hours: Gitlab::CurrentSettings.time_tracking_limit_to_hours.to_s } } limit_to_hours: Gitlab::CurrentSettings.time_tracking_limit_to_hours.to_s } }
= render_if_exists 'shared/milestones/weight', milestone: milestone = render_if_exists 'shared/milestones/weight', milestone: milestone
......
---
title: Resolve Time tracking report is bugged on GraphQL boards
merge_request: 62109
author:
type: fixed
...@@ -26,6 +26,7 @@ describe('BoardSidebarTimeTracker', () => { ...@@ -26,6 +26,7 @@ describe('BoardSidebarTimeTracker', () => {
store = createStore(); store = createStore();
store.state.boardItems = { store.state.boardItems = {
1: { 1: {
id: 1,
timeEstimate: 3600, timeEstimate: 3600,
totalTimeSpent: 1800, totalTimeSpent: 1800,
humanTimeEstimate: '1h', humanTimeEstimate: '1h',
...@@ -52,6 +53,7 @@ describe('BoardSidebarTimeTracker', () => { ...@@ -52,6 +53,7 @@ describe('BoardSidebarTimeTracker', () => {
humanTimeSpent: '30min', humanTimeSpent: '30min',
limitToHours: timeTrackingLimitToHours, limitToHours: timeTrackingLimitToHours,
showCollapsed: false, showCollapsed: false,
issuableId: '1',
}); });
}, },
); );
......
...@@ -36,7 +36,7 @@ describe('Issuable Time Tracking Report', () => { ...@@ -36,7 +36,7 @@ describe('Issuable Time Tracking Report', () => {
issuableId: 1, issuableId: 1,
issuableType, issuableType,
}, },
propsData: { limitToHours }, propsData: { limitToHours, issuableId: '1' },
localVue, localVue,
apolloProvider: fakeApollo, apolloProvider: fakeApollo,
}); });
......
...@@ -18,15 +18,19 @@ describe('Issuable Time Tracker', () => { ...@@ -18,15 +18,19 @@ describe('Issuable Time Tracker', () => {
humanTimeEstimate: '2h 46m', humanTimeEstimate: '2h 46m',
humanTimeSpent: '1h 23m', humanTimeSpent: '1h 23m',
limitToHours: false, limitToHours: false,
issuableId: '1',
}; };
const mountComponent = ({ props = {} } = {}) => const mountComponent = ({ props = {}, issuableType = 'issue' } = {}) =>
mount(TimeTracker, { mount(TimeTracker, {
propsData: { ...defaultProps, ...props }, propsData: { ...defaultProps, ...props },
directives: { GlTooltip: createMockDirective() }, directives: { GlTooltip: createMockDirective() },
stubs: { stubs: {
transition: stubTransition(), transition: stubTransition(),
}, },
provide: {
issuableType,
},
}); });
afterEach(() => { afterEach(() => {
...@@ -210,13 +214,20 @@ describe('Issuable Time Tracker', () => { ...@@ -210,13 +214,20 @@ describe('Issuable Time Tracker', () => {
}); });
describe('When time spent', () => { describe('When time spent', () => {
beforeEach(() => { it('link should appear on issue', () => {
wrapper = mountComponent(); wrapper = mountComponent();
expect(findReportLink().exists()).toBe(true);
}); });
it('link should appear', () => { it('link should appear on merge request', () => {
wrapper = mountComponent({ issuableType: 'merge_request' });
expect(findReportLink().exists()).toBe(true); expect(findReportLink().exists()).toBe(true);
}); });
it('link should not appear on milestone', () => {
wrapper = mountComponent({ issuableType: 'milestone' });
expect(findReportLink().exists()).toBe(false);
});
}); });
}); });
......
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