Skip to content

Commit 284b8e7

Browse files
committed
#1275 Deleting properties
1 parent b89429b commit 284b8e7

5 files changed

Lines changed: 149 additions & 12 deletions

File tree

ontrack-ui-graphql/src/main/java/net/nemerosa/ontrack/graphql/schema/PropertiesMutations.kt

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class PropertiesMutations(
4242
}
4343

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

4747
private val genericMutation: Mutation
4848
get() = simpleMutation(
@@ -69,6 +69,22 @@ class PropertiesMutations(
6969
)
7070
}
7171

72+
private val genericDeleteMutation: Mutation
73+
get() = unitMutation(
74+
name = "deleteGenericProperty",
75+
description = "Generic deletion for a property and an entity",
76+
input = DeleteGenericPropertyInput::class,
77+
) { input ->
78+
// Gets the entity
79+
val entity = structureService.findEntity<ProjectEntity>(input.entityType, input.entityId)
80+
?: throw EntityNotFoundByIdException(input.entityType, input.entityId)
81+
// Deleting the property
82+
propertyService.deleteProperty(
83+
entity = entity,
84+
propertyTypeName = input.type,
85+
)
86+
}
87+
7288
private fun createGenericMutationById(type: ProjectEntityType) = object : Mutation {
7389

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

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

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

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

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

324340
private fun name(name: String): GraphQLInputObjectField = GraphQLInputObjectField.newInputObjectField()
325341
.name(name)
326-
.description("${name.capitalize()} name")
342+
.description("${name.replaceFirstChar { it.uppercase() }} name")
327343
.type(GraphQLNonNull(GraphQLString))
328344
.build()
329345

@@ -348,7 +364,7 @@ class PropertiesMutations(
348364
private fun projectEntityTypeField(type: ProjectEntityType): GraphQLFieldDefinition =
349365
GraphQLFieldDefinition.newFieldDefinition()
350366
.name(type.varName)
351-
.description("${type.displayName.capitalize()} updated")
367+
.description("${type.displayName.replaceFirstChar { it.uppercase() }} updated")
352368
.type(GraphQLTypeReference(type.typeName))
353369
.build()
354370

@@ -359,6 +375,12 @@ class PropertiesMutations(
359375
val value: JsonNode,
360376
)
361377

378+
data class DeleteGenericPropertyInput(
379+
val entityType: ProjectEntityType,
380+
val entityId: Int,
381+
val type: String,
382+
)
383+
362384
companion object {
363385
const val ARG_ID = "id"
364386
const val ARG_PROPERTY_TYPE = "property"

ontrack-ui-graphql/src/test/java/net/nemerosa/ontrack/graphql/schema/PropertiesMutationsIT.kt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package net.nemerosa.ontrack.graphql.schema
22

3+
import net.nemerosa.ontrack.extension.api.support.TestConfiguration
4+
import net.nemerosa.ontrack.extension.api.support.TestProperty
35
import net.nemerosa.ontrack.extension.api.support.TestPropertyType
46
import net.nemerosa.ontrack.graphql.AbstractQLKTITSupport
57
import org.junit.jupiter.api.Test
68
import kotlin.test.assertEquals
79
import kotlin.test.assertNotNull
10+
import kotlin.test.assertNull
811

912
class PropertiesMutationsIT : AbstractQLKTITSupport() {
1013

@@ -40,4 +43,37 @@ class PropertiesMutationsIT : AbstractQLKTITSupport() {
4043
}
4144
}
4245

46+
@Test
47+
fun `Deleting a property using the generic mutation`() {
48+
asAdmin {
49+
project {
50+
propertyService.editProperty(
51+
this,
52+
TestPropertyType::class.java,
53+
TestProperty(
54+
configuration = TestConfiguration("test-config", "user", "xxx"),
55+
value = "test-value"
56+
)
57+
)
58+
run(
59+
"""
60+
mutation {
61+
deleteGenericProperty(input: {
62+
entityType: PROJECT,
63+
entityId: $id,
64+
type: "${TestPropertyType::class.java.name}"
65+
}) {
66+
errors {
67+
message
68+
}
69+
}
70+
}
71+
"""
72+
)
73+
val property = propertyService.getPropertyValue(this, TestPropertyType::class.java)
74+
assertNull(property, "Property has been deleted")
75+
}
76+
}
77+
}
78+
4379
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import InlineConfirmCommand from "@components/common/InlineConfirmCommand";
2+
import {useGraphQLClient} from "@components/providers/ConnectionContextProvider";
3+
import {useContext} from "react";
4+
import {EventsContext} from "@components/common/EventsContext";
5+
import {gql} from "graphql-request";
6+
7+
export default function PropertyDeleteButton({entityType, entityId, property}) {
8+
9+
const client = useGraphQLClient()
10+
const eventsContext = useContext(EventsContext)
11+
12+
const deleteProperty = () => {
13+
client.request(
14+
gql`
15+
mutation DeleteProperty(
16+
$entityType: ProjectEntityType!,
17+
$entityId: Int!,
18+
$type: String!,
19+
) {
20+
deleteGenericProperty(input: {
21+
entityType: $entityType,
22+
entityId: $entityId,
23+
type: $type,
24+
}) {
25+
errors {
26+
message
27+
}
28+
}
29+
}
30+
`,
31+
{
32+
entityType,
33+
entityId,
34+
type: property.type.typeName,
35+
}
36+
).then(() => {
37+
eventsContext.fireEvent("entity.properties.changed", {entity: {entityType, entityId}})
38+
})
39+
}
40+
41+
return (
42+
<>
43+
<InlineConfirmCommand
44+
title="Deletes this property"
45+
confirm="Do you really want to delete this property?"
46+
onConfirm={deleteProperty}
47+
/>
48+
</>
49+
)
50+
}

ontrack-web-core/components/framework/properties/PropertyTitle.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
import {Space, Typography} from "antd";
22
import PropertyEditButton from "@components/core/model/properties/PropertyEditButton";
3+
import PropertyDeleteButton from "@components/core/model/properties/PropertyDeleteButton";
34

45
export default function PropertyTitle({entityType, entityId, property}) {
56
return (
67
<>
78
<Space>
89
<Typography.Text>{property.type.name}</Typography.Text>
910
{
10-
property.editable && <PropertyEditButton
11-
entityType={entityType}
12-
entityId={entityId}
13-
property={property}
14-
/>
11+
property.editable && <>
12+
<PropertyEditButton
13+
entityType={entityType}
14+
entityId={entityId}
15+
property={property}
16+
/>
17+
<PropertyDeleteButton
18+
entityType={entityType}
19+
entityId={entityId}
20+
property={property}
21+
/>
22+
</>
1523
}
1624
</Space>
1725
</>

ontrack-web-core/ontrack.graphql

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,12 @@ type DeleteConfigurationPayload implements Payload {
12721272
errors: [UserError]
12731273
}
12741274

1275+
"Output type for the deleteGenericProperty mutation."
1276+
type DeleteGenericPropertyPayload implements Payload {
1277+
"List of errors"
1278+
errors: [UserError]
1279+
}
1280+
12751281
"Output type for the deleteJenkinsConfiguration mutation."
12761282
type DeleteJenkinsConfigurationPayload implements Payload {
12771283
"List of errors"
@@ -3233,6 +3239,11 @@ type Mutation {
32333239
): DeleteConfigurationPayload
32343240
"Deletes a dashboard"
32353241
deleteDashboard(input: DeleteDashboardInput!): DeletionPayload
3242+
"Generic deletion for a property and an entity"
3243+
deleteGenericProperty(
3244+
"Input for the mutation"
3245+
input: DeleteGenericPropertyInput
3246+
): DeleteGenericPropertyPayload
32363247
"Deletes a Jenkins configuration"
32373248
deleteJenkinsConfiguration(
32383249
"Input for the mutation"
@@ -8166,6 +8177,16 @@ input DeleteDashboardInput {
81668177
uuid: String!
81678178
}
81688179
8180+
"Input type for the deleteGenericProperty mutation."
8181+
input DeleteGenericPropertyInput {
8182+
"entityId field"
8183+
entityId: Int!
8184+
"entityType field"
8185+
entityType: ProjectEntityType!
8186+
"type field"
8187+
type: String!
8188+
}
8189+
81698190
"Input type for the deleteJenkinsConfiguration mutation."
81708191
input DeleteJenkinsConfigurationInput {
81718192
"name field"

0 commit comments

Comments
 (0)