Commit f5020023 authored by Kirstie Cook's avatar Kirstie Cook Committed by Bob Van Landuyt

Add delete action for annotations in graphql

Update graphql schema
parent f77c146d
# frozen_string_literal: true
module Mutations
module Metrics
module Dashboard
module Annotations
class Base < BaseMutation
private
# This method is defined here in order to be used by `authorized_find!` in the subclasses.
def find_object(id:)
GitlabSchema.object_from_id(id)
end
end
end
end
end
end
# frozen_string_literal: true
module Mutations
module Metrics
module Dashboard
module Annotations
class Delete < Base
graphql_name 'DeleteAnnotation'
authorize :delete_metrics_dashboard_annotation
argument :id,
GraphQL::ID_TYPE,
required: true,
description: 'The global id of the annotation to delete'
def resolve(id:)
annotation = authorized_find!(id: id)
result = ::Metrics::Dashboard::Annotations::DeleteService.new(context[:current_user], annotation).execute
errors = Array.wrap(result[:message])
{
errors: errors
}
end
end
end
end
end
end
......@@ -26,6 +26,7 @@ module Types
mount_mutation Mutations::MergeRequests::SetWip, calls_gitaly: true
mount_mutation Mutations::MergeRequests::SetAssignees
mount_mutation Mutations::Metrics::Dashboard::Annotations::Create
mount_mutation Mutations::Metrics::Dashboard::Annotations::Delete
mount_mutation Mutations::Notes::Create::Note, calls_gitaly: true
mount_mutation Mutations::Notes::Create::DiffNote, calls_gitaly: true
mount_mutation Mutations::Notes::Create::ImageDiffNote, calls_gitaly: true
......
---
title: Added delete action for Dashboard Annotations in GraphQL
merge_request: 33468
author:
type: added
......@@ -1725,6 +1725,36 @@ type CreateSnippetPayload {
snippet: Snippet
}
"""
Autogenerated input type of DeleteAnnotation
"""
input DeleteAnnotationInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
The global id of the annotation to delete
"""
id: ID!
}
"""
Autogenerated return type of DeleteAnnotation
"""
type DeleteAnnotationPayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String
"""
Errors encountered during execution of the mutation.
"""
errors: [String!]!
}
"""
The response from the AdminSidekiqQueuesDeleteJobs mutation.
"""
......@@ -7210,6 +7240,7 @@ type Mutation {
createNote(input: CreateNoteInput!): CreateNotePayload
createRequirement(input: CreateRequirementInput!): CreateRequirementPayload
createSnippet(input: CreateSnippetInput!): CreateSnippetPayload
deleteAnnotation(input: DeleteAnnotationInput!): DeleteAnnotationPayload
designManagementDelete(input: DesignManagementDeleteInput!): DesignManagementDeletePayload
designManagementUpload(input: DesignManagementUploadInput!): DesignManagementUploadPayload
destroyNote(input: DestroyNoteInput!): DestroyNotePayload
......
......@@ -4570,6 +4570,94 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "DeleteAnnotationInput",
"description": "Autogenerated input type of DeleteAnnotation",
"fields": null,
"inputFields": [
{
"name": "id",
"description": "The global id of the annotation to delete",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "DeleteAnnotationPayload",
"description": "Autogenerated return type of DeleteAnnotation",
"fields": [
{
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "errors",
"description": "Errors encountered during execution of the mutation.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "DeleteJobsResponse",
......@@ -20521,6 +20609,33 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "deleteAnnotation",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "DeleteAnnotationInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "DeleteAnnotationPayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "designManagementDelete",
"description": null,
......@@ -305,6 +305,15 @@ Autogenerated return type of CreateSnippet
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `snippet` | Snippet | The snippet after mutation |
## DeleteAnnotationPayload
Autogenerated return type of DeleteAnnotation
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
## DeleteJobsResponse
The response from the AdminSidekiqQueuesDeleteJobs mutation.
......
# frozen_string_literal: true
require 'spec_helper'
describe Mutations::Metrics::Dashboard::Annotations::Delete do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project, :private, :repository) }
let_it_be(:environment) { create(:environment, project: project) }
let_it_be(:annotation) { create(:metrics_dashboard_annotation, environment: environment) }
let(:mutation) do
variables = {
id: GitlabSchema.id_from_object(annotation).to_s
}
graphql_mutation(:delete_annotation, variables)
end
def mutation_response
graphql_mutation_response(:delete_annotation)
end
specify { expect(described_class).to require_graphql_authorizations(:delete_metrics_dashboard_annotation) }
context 'when the user has permission to delete the annotation' do
before do
project.add_developer(current_user)
end
context 'with valid params' do
it 'deletes the annotation' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.to change { Metrics::Dashboard::Annotation.count }.by(-1)
end
end
context 'with invalid params' do
let(:mutation) do
variables = {
id: 'invalid_id'
}
graphql_mutation(:delete_annotation, variables)
end
it_behaves_like 'a mutation that returns top-level errors', errors: ['invalid_id is not a valid GitLab id.']
end
context 'when the delete fails' do
let(:service_response) { { message: 'Annotation has not been deleted', status: :error, last_step: :delete } }
before do
allow_next_instance_of(Metrics::Dashboard::Annotations::DeleteService) do |delete_service|
allow(delete_service).to receive(:execute).and_return(service_response)
end
end
it 'returns the error' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response['errors']).to eq([service_response[:message]])
end
end
end
context 'when the user does not have permission to delete the annotation' do
before do
project.add_reporter(current_user)
end
it_behaves_like 'a mutation that returns top-level errors', errors: [Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR]
it 'does not delete the annotation' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.not_to change { Metrics::Dashboard::Annotation.count }
end
end
end
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