From f03b360b1a82af8b63a362688077dbcba71ebc11 Mon Sep 17 00:00:00 2001 From: Marco Zille Date: Tue, 23 Apr 2024 22:59:46 +0200 Subject: [PATCH 1/5] Changed timelogCreate mutation to not require the spentAt field Changelog: changed --- .../time_tracking/create_timelog_form.vue | 4 +--- app/graphql/mutations/timelogs/create.rb | 4 +++- doc/api/graphql/reference/index.md | 2 +- .../time_tracking/create_timelog_form_spec.js | 22 +++++++++++++++++++ .../timelogs/create_shared_examples.rb | 21 +++++++++++++++++- 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue b/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue index f55a2ea55086e6..423107447f1509 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue @@ -152,9 +152,7 @@ export default { variables: { input: { timeSpent: this.timeSpent, - spentAt: this.spentAt - ? formatDate(this.spentAt, 'isoDateTime') - : formatDate(Date.now(), 'isoDateTime'), + spentAt: this.spentAt ? formatDate(this.spentAt, 'isoDateTime') : null, summary: this.summary, issuableId: this.getIssuableId(), }, diff --git a/app/graphql/mutations/timelogs/create.rb b/app/graphql/mutations/timelogs/create.rb index 1be023eed8a8b2..a81c9d27039753 100644 --- a/app/graphql/mutations/timelogs/create.rb +++ b/app/graphql/mutations/timelogs/create.rb @@ -12,7 +12,7 @@ class Create < Base argument :spent_at, Types::TimeType, - required: true, + required: false, description: 'When the time was spent.' argument :summary, @@ -35,6 +35,8 @@ def resolve(issuable_id:, time_spent:, spent_at:, summary:, **args) issuable = authorized_find!(id: issuable_id) + spent_at = DateTime.current if spent_at.nil? + result = ::Timelogs::CreateService.new( issuable, parsed_time_spent, spent_at, summary, current_user ).execute diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 0273b6bbfd2a1a..b7e3ab89065115 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -8212,7 +8212,7 @@ Input type: `TimelogCreateInput` | ---- | ---- | ----------- | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `issuableId` | [`IssuableID!`](#issuableid) | Global ID of the issuable (Issue, WorkItem or MergeRequest). | -| `spentAt` | [`Time!`](#time) | When the time was spent. | +| `spentAt` | [`Time`](#time) | When the time was spent. | | `summary` | [`String!`](#string) | Summary of time spent. | | `timeSpent` | [`String!`](#string) | Amount of time spent. | diff --git a/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js b/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js index 44a13c00a9fa3d..eb7eb333edf759 100644 --- a/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js +++ b/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js @@ -188,6 +188,28 @@ describe('Create Timelog Form', () => { }); }, ); + + it('calls the mutation passing spent_at as null when not provided', async () => { + const timeSpent = '2d'; + const summary = 'Example'; + + mountComponent({ providedProps: { TYPENAME_ISSUE } }); + await findGlFormInput().vm.$emit('input', timeSpent); + await findGlFormTextarea().vm.$emit('input', summary); + + submitForm(); + + await waitForPromises(); + + expect(rejectedMutationMock).toHaveBeenCalledWith({ + input: { + timeSpent, + spentAt: null, + summary, + issuableId: convertToGraphQLId(TYPENAME_ISSUE, '1'), + }, + }); + }); }); describe('alert', () => { diff --git a/spec/support/shared_examples/graphql/mutations/timelogs/create_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/timelogs/create_shared_examples.rb index c6402a89f02dc2..fa86f06a4f76d1 100644 --- a/spec/support/shared_examples/graphql/mutations/timelogs/create_shared_examples.rb +++ b/spec/support/shared_examples/graphql/mutations/timelogs/create_shared_examples.rb @@ -2,10 +2,11 @@ RSpec.shared_examples 'issuable supports timelog creation mutation' do let(:mutation_response) { graphql_mutation_response(:timelog_create) } + let(:spent_at) { '2022-11-16T12:59:35+0100' } let(:mutation) do variables = { 'time_spent' => time_spent, - 'spent_at' => '2022-11-16T12:59:35+0100', + 'spent_at' => spent_at, 'summary' => 'Test summary', 'issuable_id' => issuable.to_global_id.to_s } @@ -56,6 +57,24 @@ end end + context 'when spent_at is not provided', time_travel_to: '2024-04-23 22:50:00 +0200' do + let(:spent_at) { nil } + + it 'creates the timelog using the current time' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + end.to change { Timelog.count }.by(1) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['errors']).to be_empty + expect(mutation_response['timelog']).to include( + 'timeSpent' => 3600, + 'spentAt' => '2024-04-23T20:50:00Z', + 'summary' => 'Test summary' + ) + end + end + context 'with invalid time_spent' do let(:time_spent) { '3h e' } -- GitLab From c6dd04c212ceb7290aee112eaa1b174307da9052 Mon Sep 17 00:00:00 2001 From: Marco Zille Date: Wed, 24 Apr 2024 13:27:22 +0000 Subject: [PATCH 2/5] Applied suggestions from review --- app/graphql/mutations/timelogs/create.rb | 2 +- doc/api/graphql/reference/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/graphql/mutations/timelogs/create.rb b/app/graphql/mutations/timelogs/create.rb index a81c9d27039753..6d4c3ef3820f8d 100644 --- a/app/graphql/mutations/timelogs/create.rb +++ b/app/graphql/mutations/timelogs/create.rb @@ -13,7 +13,7 @@ class Create < Base argument :spent_at, Types::TimeType, required: false, - description: 'When the time was spent.' + description: 'Timestamp of when the time was spent.' argument :summary, GraphQL::Types::String, diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index b7e3ab89065115..90413331bf2568 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -8212,7 +8212,7 @@ Input type: `TimelogCreateInput` | ---- | ---- | ----------- | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `issuableId` | [`IssuableID!`](#issuableid) | Global ID of the issuable (Issue, WorkItem or MergeRequest). | -| `spentAt` | [`Time`](#time) | When the time was spent. | +| `spentAt` | [`Time`](#time) | Timestamp of when the time was spent. | | `summary` | [`String!`](#string) | Summary of time spent. | | `timeSpent` | [`String!`](#string) | Amount of time spent. | -- GitLab From 3379058746378abf6688b5b03a28c057353fcc51 Mon Sep 17 00:00:00 2001 From: Marco Zille Date: Mon, 6 May 2024 22:16:24 +0200 Subject: [PATCH 3/5] Applied suggestions from review --- app/graphql/mutations/timelogs/create.rb | 6 +++--- doc/api/graphql/reference/index.md | 2 +- .../mutations/timelogs/create_shared_examples.rb | 15 +++++++++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/app/graphql/mutations/timelogs/create.rb b/app/graphql/mutations/timelogs/create.rb index 6d4c3ef3820f8d..4caea414175386 100644 --- a/app/graphql/mutations/timelogs/create.rb +++ b/app/graphql/mutations/timelogs/create.rb @@ -13,7 +13,7 @@ class Create < Base argument :spent_at, Types::TimeType, required: false, - description: 'Timestamp of when the time was spent.' + description: 'Timestamp of when the time was spent. If empty, defaults to current time.' argument :summary, GraphQL::Types::String, @@ -27,7 +27,7 @@ class Create < Base authorize :create_timelog - def resolve(issuable_id:, time_spent:, spent_at:, summary:, **args) + def resolve(issuable_id:, time_spent:, summary:, **args) parsed_time_spent = Gitlab::TimeTrackingFormatter.parse(time_spent) if parsed_time_spent.nil? return { timelog: nil, errors: [_('Time spent must be formatted correctly. For example: 1h 30m.')] } @@ -35,7 +35,7 @@ def resolve(issuable_id:, time_spent:, spent_at:, summary:, **args) issuable = authorized_find!(id: issuable_id) - spent_at = DateTime.current if spent_at.nil? + spent_at = args[:spent_at].nil? ? DateTime.current : args[:spent_at] result = ::Timelogs::CreateService.new( issuable, parsed_time_spent, spent_at, summary, current_user diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 90413331bf2568..0a8b39cf4059e4 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -8212,7 +8212,7 @@ Input type: `TimelogCreateInput` | ---- | ---- | ----------- | | `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | `issuableId` | [`IssuableID!`](#issuableid) | Global ID of the issuable (Issue, WorkItem or MergeRequest). | -| `spentAt` | [`Time`](#time) | Timestamp of when the time was spent. | +| `spentAt` | [`Time`](#time) | Timestamp of when the time was spent. If empty, defaults to current time. | | `summary` | [`String!`](#string) | Summary of time spent. | | `timeSpent` | [`String!`](#string) | Amount of time spent. | diff --git a/spec/support/shared_examples/graphql/mutations/timelogs/create_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/timelogs/create_shared_examples.rb index fa86f06a4f76d1..23dd195e626c24 100644 --- a/spec/support/shared_examples/graphql/mutations/timelogs/create_shared_examples.rb +++ b/spec/support/shared_examples/graphql/mutations/timelogs/create_shared_examples.rb @@ -3,14 +3,15 @@ RSpec.shared_examples 'issuable supports timelog creation mutation' do let(:mutation_response) { graphql_mutation_response(:timelog_create) } let(:spent_at) { '2022-11-16T12:59:35+0100' } - let(:mutation) do - variables = { + let(:mutation) { graphql_mutation(:timelogCreate, variables) } + + let(:variables) do + { 'time_spent' => time_spent, 'spent_at' => spent_at, 'summary' => 'Test summary', 'issuable_id' => issuable.to_global_id.to_s } - graphql_mutation(:timelogCreate, variables) end context 'when the user is anonymous' do @@ -58,7 +59,13 @@ end context 'when spent_at is not provided', time_travel_to: '2024-04-23 22:50:00 +0200' do - let(:spent_at) { nil } + let(:variables) do + { + 'time_spent' => time_spent, + 'summary' => 'Test summary', + 'issuable_id' => issuable.to_global_id.to_s + } + end it 'creates the timelog using the current time' do expect do -- GitLab From d528d9a81d02ca12e64cec467211ee71721db93b Mon Sep 17 00:00:00 2001 From: Marco Zille Date: Mon, 6 May 2024 22:22:33 +0200 Subject: [PATCH 4/5] Removed frontend changes --- .../time_tracking/create_timelog_form.vue | 4 +++- .../time_tracking/create_timelog_form_spec.js | 22 ------------------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue b/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue index 423107447f1509..f55a2ea55086e6 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/create_timelog_form.vue @@ -152,7 +152,9 @@ export default { variables: { input: { timeSpent: this.timeSpent, - spentAt: this.spentAt ? formatDate(this.spentAt, 'isoDateTime') : null, + spentAt: this.spentAt + ? formatDate(this.spentAt, 'isoDateTime') + : formatDate(Date.now(), 'isoDateTime'), summary: this.summary, issuableId: this.getIssuableId(), }, diff --git a/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js b/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js index eb7eb333edf759..44a13c00a9fa3d 100644 --- a/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js +++ b/spec/frontend/sidebar/components/time_tracking/create_timelog_form_spec.js @@ -188,28 +188,6 @@ describe('Create Timelog Form', () => { }); }, ); - - it('calls the mutation passing spent_at as null when not provided', async () => { - const timeSpent = '2d'; - const summary = 'Example'; - - mountComponent({ providedProps: { TYPENAME_ISSUE } }); - await findGlFormInput().vm.$emit('input', timeSpent); - await findGlFormTextarea().vm.$emit('input', summary); - - submitForm(); - - await waitForPromises(); - - expect(rejectedMutationMock).toHaveBeenCalledWith({ - input: { - timeSpent, - spentAt: null, - summary, - issuableId: convertToGraphQLId(TYPENAME_ISSUE, '1'), - }, - }); - }); }); describe('alert', () => { -- GitLab From a15d5379bb3c56dbd0bcd886b2ddd4312ce7e3b8 Mon Sep 17 00:00:00 2001 From: Marcin Sedlak-Jakubowski Date: Wed, 8 May 2024 15:05:01 +0000 Subject: [PATCH 5/5] Add doc update --- doc/user/project/time_tracking.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/user/project/time_tracking.md b/doc/user/project/time_tracking.md index b15966722b6609..03666abb09bc8f 100644 --- a/doc/user/project/time_tracking.md +++ b/doc/user/project/time_tracking.md @@ -83,6 +83,7 @@ Prerequisites: #### Using the user interface > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101563) in GitLab 15.7. +> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/150564) in GitLab 17.0. When you don't specify when time was spent, current time is used. To add a time entry using the user interface: @@ -90,7 +91,7 @@ To add a time entry using the user interface: 1. Enter: - The amount of time spent. - - Optional. When it was spent. + - Optional. When it was spent. If empty, uses current time. - Optional. A summary. 1. Select **Save**. -- GitLab