diff options
Diffstat (limited to 'app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue')
-rw-r--r-- | app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue | 161 |
1 files changed, 111 insertions, 50 deletions
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue index 64f2ddc1d16..3feff8639a1 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue @@ -1,6 +1,9 @@ <script> -import { GlIcon, GlLink, GlModal, GlModalDirective } from '@gitlab/ui'; +import { GlIcon, GlLink, GlModal, GlModalDirective, GlLoadingIcon } from '@gitlab/ui'; +import { IssuableType } from '~/issue_show/constants'; import { s__, __ } from '~/locale'; +import { timeTrackingQueries } from '~/sidebar/constants'; + import eventHub from '../../event_hub'; import TimeTrackingCollapsedState from './collapsed_state.vue'; import TimeTrackingComparisonPane from './comparison_pane.vue'; @@ -18,6 +21,7 @@ export default { GlIcon, GlLink, GlModal, + GlLoadingIcon, TimeTrackingCollapsedState, TimeTrackingSpentOnlyPane, TimeTrackingComparisonPane, @@ -27,29 +31,27 @@ export default { directives: { GlModal: GlModalDirective, }, + inject: ['issuableType'], props: { - timeEstimate: { - type: Number, - required: true, - }, - timeSpent: { - type: Number, - required: true, + limitToHours: { + type: Boolean, + default: false, + required: false, }, - humanTimeEstimate: { + fullPath: { type: String, required: false, default: '', }, - humanTimeSpent: { + issuableIid: { type: String, required: false, default: '', }, - limitToHours: { - type: Boolean, - default: false, + initialTimeTracking: { + type: Object, required: false, + default: null, }, /* In issue list, "time-tracking-collapsed-state" is always rendered even if the sidebar isn't collapsed. @@ -70,47 +72,103 @@ export default { data() { return { showHelp: false, + timeTracking: { + ...this.initialTimeTracking, + }, }; }, + apollo: { + issuableTimeTracking: { + query() { + return timeTrackingQueries[this.issuableType].query; + }, + skip() { + // We don't fetch info via GraphQL in following cases + // 1. Time tracking info was provided via prop + // 2. issuableIid and fullPath are not provided. + if (!this.initialTimeTracking) { + return false; + } else if (this.issuableIid && this.fullPath) { + return false; + } + return true; + }, + variables() { + return { + iid: this.issuableIid, + fullPath: this.fullPath, + }; + }, + update(data) { + this.timeTracking = { + ...data.workspace?.issuable, + }; + }, + }, + }, computed: { - hasTimeSpent() { - return Boolean(this.timeSpent); + isTimeTrackingInfoLoading() { + return this.$apollo?.queries.issuableTimeTracking.loading ?? false; + }, + timeEstimate() { + return this.timeTracking?.timeEstimate || 0; + }, + totalTimeSpent() { + return this.timeTracking?.totalTimeSpent || 0; + }, + humanTimeEstimate() { + return this.timeTracking?.humanTimeEstimate || ''; + }, + humanTotalTimeSpent() { + return this.timeTracking?.humanTotalTimeSpent || ''; + }, + hasTotalTimeSpent() { + return Boolean(this.totalTimeSpent); }, hasTimeEstimate() { return Boolean(this.timeEstimate); }, showComparisonState() { - return this.hasTimeEstimate && this.hasTimeSpent; + return this.hasTimeEstimate && this.hasTotalTimeSpent; }, showEstimateOnlyState() { - return this.hasTimeEstimate && !this.hasTimeSpent; + return this.hasTimeEstimate && !this.hasTotalTimeSpent; }, showSpentOnlyState() { - return this.hasTimeSpent && !this.hasTimeEstimate; + return this.hasTotalTimeSpent && !this.hasTimeEstimate; }, showNoTimeTrackingState() { - return !this.hasTimeEstimate && !this.hasTimeSpent; + return !this.hasTimeEstimate && !this.hasTotalTimeSpent; }, showHelpState() { return Boolean(this.showHelp); }, + isTimeReportSupported() { + return ( + [IssuableType.Issue, IssuableType.MergeRequest].includes(this.issuableType) && + this.issuableIid + ); + }, + }, + watch: { + /** + * When `initialTimeTracking` is provided via prop, + * we don't query the same via GraphQl and instead + * monitor it for any updates (eg; Epic Swimlanes) + */ + initialTimeTracking(timeTracking) { + this.timeTracking = timeTracking; + }, }, created() { - eventHub.$on('timeTracker:updateData', this.update); + eventHub.$on('timeTracker:refresh', this.refresh); }, methods: { toggleHelpState(show) { this.showHelp = show; }, - update(data) { - const { timeEstimate, timeSpent, humanTimeEstimate, humanTimeSpent } = data; - - /* eslint-disable vue/no-mutating-props */ - this.timeEstimate = timeEstimate; - this.timeSpent = timeSpent; - this.humanTimeEstimate = humanTimeEstimate; - this.humanTimeSpent = humanTimeSpent; - /* eslint-enable vue/no-mutating-props */ + refresh() { + this.$apollo.queries.issuableTimeTracking.refetch(); }, }, }; @@ -125,11 +183,12 @@ export default { :show-help-state="showHelpState" :show-spent-only-state="showSpentOnlyState" :show-estimate-only-state="showEstimateOnlyState" - :time-spent-human-readable="humanTimeSpent" + :time-spent-human-readable="humanTotalTimeSpent" :time-estimate-human-readable="humanTimeEstimate" /> - <div class="title hide-collapsed gl-mb-3"> + <div class="hide-collapsed gl-line-height-20 gl-text-gray-900"> {{ __('Time tracking') }} + <gl-loading-icon v-if="isTimeTrackingInfoLoading" inline /> <div v-if="!showHelpState" data-testid="helpButton" @@ -147,14 +206,14 @@ export default { <gl-icon name="close" /> </div> </div> - <div class="time-tracking-content hide-collapsed"> + <div v-if="!isTimeTrackingInfoLoading" class="hide-collapsed"> <div v-if="showEstimateOnlyState" data-testid="estimateOnlyPane"> <span class="gl-font-weight-bold">{{ $options.i18n.estimatedOnlyText }} </span >{{ humanTimeEstimate }} </div> <time-tracking-spent-only-pane v-if="showSpentOnlyState" - :time-spent-human-readable="humanTimeSpent" + :time-spent-human-readable="humanTotalTimeSpent" /> <div v-if="showNoTimeTrackingState" data-testid="noTrackingPane"> <span class="gl-text-gray-500">{{ $options.i18n.noTimeTrackingText }}</span> @@ -162,26 +221,28 @@ export default { <time-tracking-comparison-pane v-if="showComparisonState" :time-estimate="timeEstimate" - :time-spent="timeSpent" - :time-spent-human-readable="humanTimeSpent" + :time-spent="totalTimeSpent" + :time-spent-human-readable="humanTotalTimeSpent" :time-estimate-human-readable="humanTimeEstimate" :limit-to-hours="limitToHours" /> - <gl-link - v-if="hasTimeSpent" - v-gl-modal="'time-tracking-report'" - data-testid="reportLink" - href="#" - class="btn-link" - >{{ __('Time tracking report') }}</gl-link - > - <gl-modal - modal-id="time-tracking-report" - :title="__('Time tracking report')" - :hide-footer="true" - > - <time-tracking-report :limit-to-hours="limitToHours" /> - </gl-modal> + <template v-if="isTimeReportSupported"> + <gl-link + v-if="hasTotalTimeSpent" + v-gl-modal="'time-tracking-report'" + data-testid="reportLink" + href="#" + > + {{ __('Time tracking report') }} + </gl-link> + <gl-modal + modal-id="time-tracking-report" + :title="__('Time tracking report')" + :hide-footer="true" + > + <time-tracking-report :limit-to-hours="limitToHours" :issuable-iid="issuableIid" /> + </gl-modal> + </template> <transition name="help-state-toggle"> <time-tracking-help-state v-if="showHelpState" /> </transition> |