Skip to content

Commit

Permalink
#1275 Deleting properties
Browse files Browse the repository at this point in the history
  • Loading branch information
dcoraboeuf committed Jun 2, 2024
1 parent b89429b commit 284b8e7
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class PropertiesMutations(
}

override val mutations: List<Mutation>
get() = listOf(genericMutation) + genericMutations + specificMutations
get() = listOf(genericMutation, genericDeleteMutation) + genericMutations + specificMutations

private val genericMutation: Mutation
get() = simpleMutation(
Expand All @@ -69,6 +69,22 @@ class PropertiesMutations(
)
}

private val genericDeleteMutation: Mutation
get() = unitMutation(
name = "deleteGenericProperty",
description = "Generic deletion for a property and an entity",
input = DeleteGenericPropertyInput::class,
) { input ->
// Gets the entity
val entity = structureService.findEntity<ProjectEntity>(input.entityType, input.entityId)
?: throw EntityNotFoundByIdException(input.entityType, input.entityId)
// Deleting the property
propertyService.deleteProperty(
entity = entity,
propertyTypeName = input.type,
)
}

private fun createGenericMutationById(type: ProjectEntityType) = object : Mutation {

override val name: String = "set${type.typeName}PropertyById"
Expand Down Expand Up @@ -136,7 +152,7 @@ class PropertiesMutations(
return object : Mutation {
override val name: String = "set${type.typeName}${provider.mutationNameFragment}PropertyById"
override val description: String =
"Set the ${propertyType.name.decapitalize()} property on a ${type.displayName}."
"Set the ${propertyType.name.replaceFirstChar { it.lowercase() }} property on a ${type.displayName}."

override fun inputFields(dictionary: MutableSet<GraphQLType>): List<GraphQLInputObjectField> = listOf(
id(type)
Expand Down Expand Up @@ -170,7 +186,7 @@ class PropertiesMutations(
return object : Mutation {
override val name: String = "set${type.typeName}${provider.mutationNameFragment}Property"
override val description: String =
"Set the ${propertyType.name.decapitalize()} property on a ${type.displayName} identified by name."
"Set the ${propertyType.name.replaceFirstChar { it.lowercase() }} property on a ${type.displayName} identified by name."

override fun inputFields(dictionary: MutableSet<GraphQLType>): List<GraphQLInputObjectField> =
type.names.map {
Expand Down Expand Up @@ -208,7 +224,7 @@ class PropertiesMutations(
return object : Mutation {
override val name: String = "delete${type.typeName}${provider.mutationNameFragment}Property"
override val description: String =
"Deletes the ${propertyType.name.decapitalize()} property on a ${type.displayName} identified by name."
"Deletes the ${propertyType.name.replaceFirstChar { it.lowercase() }} property on a ${type.displayName} identified by name."

override fun inputFields(dictionary: MutableSet<GraphQLType>): List<GraphQLInputObjectField> =
type.names.map {
Expand Down Expand Up @@ -244,7 +260,7 @@ class PropertiesMutations(
return object : Mutation {
override val name: String = "delete${type.typeName}${provider.mutationNameFragment}PropertyById"
override val description: String =
"Deletes the ${propertyType.name.decapitalize()} property on a ${type.displayName}."
"Deletes the ${propertyType.name.replaceFirstChar { it.lowercase() }} property on a ${type.displayName}."

// Only the ID is needed
override fun inputFields(dictionary: MutableSet<GraphQLType>): List<GraphQLInputObjectField> = listOf(
Expand Down Expand Up @@ -323,7 +339,7 @@ class PropertiesMutations(

private fun name(name: String): GraphQLInputObjectField = GraphQLInputObjectField.newInputObjectField()
.name(name)
.description("${name.capitalize()} name")
.description("${name.replaceFirstChar { it.uppercase() }} name")
.type(GraphQLNonNull(GraphQLString))
.build()

Expand All @@ -348,7 +364,7 @@ class PropertiesMutations(
private fun projectEntityTypeField(type: ProjectEntityType): GraphQLFieldDefinition =
GraphQLFieldDefinition.newFieldDefinition()
.name(type.varName)
.description("${type.displayName.capitalize()} updated")
.description("${type.displayName.replaceFirstChar { it.uppercase() }} updated")
.type(GraphQLTypeReference(type.typeName))
.build()

Expand All @@ -359,6 +375,12 @@ class PropertiesMutations(
val value: JsonNode,
)

data class DeleteGenericPropertyInput(
val entityType: ProjectEntityType,
val entityId: Int,
val type: String,
)

companion object {
const val ARG_ID = "id"
const val ARG_PROPERTY_TYPE = "property"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package net.nemerosa.ontrack.graphql.schema

import net.nemerosa.ontrack.extension.api.support.TestConfiguration
import net.nemerosa.ontrack.extension.api.support.TestProperty
import net.nemerosa.ontrack.extension.api.support.TestPropertyType
import net.nemerosa.ontrack.graphql.AbstractQLKTITSupport
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull

class PropertiesMutationsIT : AbstractQLKTITSupport() {

Expand Down Expand Up @@ -40,4 +43,37 @@ class PropertiesMutationsIT : AbstractQLKTITSupport() {
}
}

@Test
fun `Deleting a property using the generic mutation`() {
asAdmin {
project {
propertyService.editProperty(
this,
TestPropertyType::class.java,
TestProperty(
configuration = TestConfiguration("test-config", "user", "xxx"),
value = "test-value"
)
)
run(
"""
mutation {
deleteGenericProperty(input: {
entityType: PROJECT,
entityId: $id,
type: "${TestPropertyType::class.java.name}"
}) {
errors {
message
}
}
}
"""
)
val property = propertyService.getPropertyValue(this, TestPropertyType::class.java)
assertNull(property, "Property has been deleted")
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import InlineConfirmCommand from "@components/common/InlineConfirmCommand";
import {useGraphQLClient} from "@components/providers/ConnectionContextProvider";
import {useContext} from "react";
import {EventsContext} from "@components/common/EventsContext";
import {gql} from "graphql-request";

export default function PropertyDeleteButton({entityType, entityId, property}) {

const client = useGraphQLClient()
const eventsContext = useContext(EventsContext)

const deleteProperty = () => {
client.request(
gql`
mutation DeleteProperty(
$entityType: ProjectEntityType!,
$entityId: Int!,
$type: String!,
) {
deleteGenericProperty(input: {
entityType: $entityType,
entityId: $entityId,
type: $type,
}) {
errors {
message
}
}
}
`,
{
entityType,
entityId,
type: property.type.typeName,
}
).then(() => {
eventsContext.fireEvent("entity.properties.changed", {entity: {entityType, entityId}})
})
}

return (
<>
<InlineConfirmCommand
title="Deletes this property"
confirm="Do you really want to delete this property?"
onConfirm={deleteProperty}
/>
</>
)
}
18 changes: 13 additions & 5 deletions ontrack-web-core/components/framework/properties/PropertyTitle.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import {Space, Typography} from "antd";
import PropertyEditButton from "@components/core/model/properties/PropertyEditButton";
import PropertyDeleteButton from "@components/core/model/properties/PropertyDeleteButton";

export default function PropertyTitle({entityType, entityId, property}) {
return (
<>
<Space>
<Typography.Text>{property.type.name}</Typography.Text>
{
property.editable && <PropertyEditButton
entityType={entityType}
entityId={entityId}
property={property}
/>
property.editable && <>
<PropertyEditButton
entityType={entityType}
entityId={entityId}
property={property}
/>
<PropertyDeleteButton
entityType={entityType}
entityId={entityId}
property={property}
/>
</>
}
</Space>
</>
Expand Down
21 changes: 21 additions & 0 deletions ontrack-web-core/ontrack.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1272,6 +1272,12 @@ type DeleteConfigurationPayload implements Payload {
errors: [UserError]
}

"Output type for the deleteGenericProperty mutation."
type DeleteGenericPropertyPayload implements Payload {
"List of errors"
errors: [UserError]
}

"Output type for the deleteJenkinsConfiguration mutation."
type DeleteJenkinsConfigurationPayload implements Payload {
"List of errors"
Expand Down Expand Up @@ -3233,6 +3239,11 @@ type Mutation {
): DeleteConfigurationPayload
"Deletes a dashboard"
deleteDashboard(input: DeleteDashboardInput!): DeletionPayload
"Generic deletion for a property and an entity"
deleteGenericProperty(
"Input for the mutation"
input: DeleteGenericPropertyInput
): DeleteGenericPropertyPayload
"Deletes a Jenkins configuration"
deleteJenkinsConfiguration(
"Input for the mutation"
Expand Down Expand Up @@ -8166,6 +8177,16 @@ input DeleteDashboardInput {
uuid: String!
}

"Input type for the deleteGenericProperty mutation."
input DeleteGenericPropertyInput {
"entityId field"
entityId: Int!
"entityType field"
entityType: ProjectEntityType!
"type field"
type: String!
}

"Input type for the deleteJenkinsConfiguration mutation."
input DeleteJenkinsConfigurationInput {
"name field"
Expand Down

0 comments on commit 284b8e7

Please sign in to comment.