From af0d8b77a55eb0e860b4309bc26547a98c959b3e Mon Sep 17 00:00:00 2001 From: Thomas Boksberger Date: Tue, 7 Apr 2026 07:56:38 +0200 Subject: [PATCH] load selectValues from Tags-endpoint --- .idea/ktlint-plugin.xml | 6 ++++ httpClient/anyType.http | 5 +++ src/main/kotlin/ch/ergon/anytask/Main.kt | 2 +- .../kotlin/ch/ergon/anytask/api/AnyTypeApi.kt | 9 ++++++ .../ch/ergon/anytask/config/Configuration.kt | 2 +- .../ch/ergon/anytask/ui/SettingsWindow.kt | 19 +----------- .../kotlin/ch/ergon/anytask/ui/TaskWindow.kt | 31 ++++++++++++++----- 7 files changed, 47 insertions(+), 27 deletions(-) create mode 100644 .idea/ktlint-plugin.xml diff --git a/.idea/ktlint-plugin.xml b/.idea/ktlint-plugin.xml new file mode 100644 index 0000000..3c1c38c --- /dev/null +++ b/.idea/ktlint-plugin.xml @@ -0,0 +1,6 @@ + + + + DEFAULT + + \ No newline at end of file diff --git a/httpClient/anyType.http b/httpClient/anyType.http index 835a532..c9e9da3 100644 --- a/httpClient/anyType.http +++ b/httpClient/anyType.http @@ -27,6 +27,11 @@ GET http://localhost:31009/v1/spaces/{{spaceId}}/properties/{{priorityPropertyId Authorization: Bearer {{apiKey}} Anytype-Version: 0.1 +### Get Property Tags +GET http://localhost:31009/v1/spaces/{{spaceId}}/properties/{{priorityPropertyId}}/tags +Authorization: Bearer {{apiKey}} +Anytype-Version: 0.1 + ### Get Templates GET http://localhost:31009/v1/spaces/{{spaceId}}/types/{{taskTypeId}}/templates Authorization: Bearer {{apiKey}} diff --git a/src/main/kotlin/ch/ergon/anytask/Main.kt b/src/main/kotlin/ch/ergon/anytask/Main.kt index dc2b153..e7bd0af 100644 --- a/src/main/kotlin/ch/ergon/anytask/Main.kt +++ b/src/main/kotlin/ch/ergon/anytask/Main.kt @@ -152,7 +152,7 @@ private fun setupSystemTray(onShow: () -> Unit, onSettings: () -> Unit, onExit: val icon = createTrayIcon(size) val menu = PopupMenu().apply { - add(MenuItem("Open").also { it.addActionListener { onShow() } }) + add(MenuItem("Create Task").also { it.addActionListener { onShow() } }) add(MenuItem("Settings").also { it.addActionListener { onSettings() } }) addSeparator() add(MenuItem("Quit").also { it.addActionListener { onExit() } }) diff --git a/src/main/kotlin/ch/ergon/anytask/api/AnyTypeApi.kt b/src/main/kotlin/ch/ergon/anytask/api/AnyTypeApi.kt index 432a176..8f531bd 100644 --- a/src/main/kotlin/ch/ergon/anytask/api/AnyTypeApi.kt +++ b/src/main/kotlin/ch/ergon/anytask/api/AnyTypeApi.kt @@ -88,6 +88,15 @@ class AnyTypeApi( response.body().data } + suspend fun getTags(propertyId: String): Result> = + runCatching { + val response = http.get("$baseUrl/v1/spaces/$spaceId/properties/$propertyId/tags") { + header("Anytype-Version", "2025-11-08") + bearerAuth(apiKey) + } + response.body().data + } + suspend fun getTemplates(typeId: String): Result> = runCatching { val response = http.get("$baseUrl/v1/spaces/$spaceId/types/$typeId/templates") { diff --git a/src/main/kotlin/ch/ergon/anytask/config/Configuration.kt b/src/main/kotlin/ch/ergon/anytask/config/Configuration.kt index b16b1d6..a30e1b5 100644 --- a/src/main/kotlin/ch/ergon/anytask/config/Configuration.kt +++ b/src/main/kotlin/ch/ergon/anytask/config/Configuration.kt @@ -17,10 +17,10 @@ data class Connection( @Serializable data class PropertyConfig( val key: String, + val id: String = "", val name: String = "", val format: String = "", val indicator: String = "", - @SerialName("possible_values") val possibleValues: List = emptyList(), @SerialName("object_type_key") val objectTypeKey: String = "", ) diff --git a/src/main/kotlin/ch/ergon/anytask/ui/SettingsWindow.kt b/src/main/kotlin/ch/ergon/anytask/ui/SettingsWindow.kt index 1c0fcf8..3527563 100644 --- a/src/main/kotlin/ch/ergon/anytask/ui/SettingsWindow.kt +++ b/src/main/kotlin/ch/ergon/anytask/ui/SettingsWindow.kt @@ -364,7 +364,6 @@ private fun PropertyTable( Text("Name", fontWeight = FontWeight.Bold, modifier = Modifier.weight(2f)) Text("Type", fontWeight = FontWeight.Bold, modifier = Modifier.weight(1.5f)) Text("Ind.", fontWeight = FontWeight.Bold, modifier = Modifier.weight(0.7f)) - Text("Values", fontWeight = FontWeight.Bold, modifier = Modifier.weight(2f)) Text("Obj Type", fontWeight = FontWeight.Bold, modifier = Modifier.weight(1.5f)) Spacer(modifier = Modifier.width(40.dp)) } @@ -383,11 +382,6 @@ private fun PropertyTable( Text(prop.name, modifier = Modifier.weight(2f), maxLines = 1) Text(prop.format, modifier = Modifier.weight(1.5f), maxLines = 1) Text(prop.indicator, modifier = Modifier.weight(0.7f), maxLines = 1) - Text( - prop.possibleValues.joinToString(", "), - modifier = Modifier.weight(2f), - maxLines = 1, - ) Text(prop.objectTypeKey, modifier = Modifier.weight(1.5f), maxLines = 1) IconButton(onClick = { onDelete(index) }) { Icon(Icons.Default.Delete, contentDescription = "Delete", tint = Color.Gray) @@ -409,7 +403,6 @@ private fun PropertyEditPanel( ) { var selectedPropertyKey by remember(existing) { mutableStateOf(existing?.key ?: "") } var indicator by remember(existing) { mutableStateOf(existing?.indicator ?: "") } - var possibleValuesText by remember(existing) { mutableStateOf(existing?.possibleValues?.joinToString("\n") ?: "") } var objectTypeKey by remember(existing) { mutableStateOf(existing?.objectTypeKey ?: "") } val selectedProperty = availableProperties.find { it.key == selectedPropertyKey } @@ -446,15 +439,6 @@ private fun PropertyEditPanel( // Format-specific fields when (format) { - "select", "multi_select" -> { - OutlinedTextField( - value = possibleValuesText, - onValueChange = { possibleValuesText = it }, - label = { Text("Possible Values (one per line)") }, - modifier = Modifier.fillMaxWidth().height(120.dp), - maxLines = 10, - ) - } "object", "objects" -> { DropdownSelector( label = "Object Type", @@ -470,14 +454,13 @@ private fun PropertyEditPanel( TextButton(onClick = onCancel) { Text("Cancel") } Button( onClick = { - val values = possibleValuesText.lines().map { it.trim() }.filter { it.isNotEmpty() } onConfirm( PropertyConfig( key = selectedPropertyKey, + id = selectedProperty?.id ?: existing?.id ?: "", name = selectedProperty?.name ?: existing?.name ?: "", format = format, indicator = indicator, - possibleValues = values, objectTypeKey = objectTypeKey, ) ) diff --git a/src/main/kotlin/ch/ergon/anytask/ui/TaskWindow.kt b/src/main/kotlin/ch/ergon/anytask/ui/TaskWindow.kt index ef969ca..94e1e94 100644 --- a/src/main/kotlin/ch/ergon/anytask/ui/TaskWindow.kt +++ b/src/main/kotlin/ch/ergon/anytask/ui/TaskWindow.kt @@ -49,6 +49,7 @@ import androidx.compose.ui.input.key.type import androidx.compose.ui.unit.dp import ch.ergon.anytask.api.AnyTypeApi import ch.ergon.anytask.api.dto.SearchObject +import ch.ergon.anytask.api.dto.Tag import ch.ergon.anytask.config.Configuration import ch.ergon.anytask.api.dto.buildPropertyValue import ch.ergon.anytask.config.PropertyConfig @@ -62,6 +63,7 @@ fun TaskWindow(client: AnyTypeApi, config: Configuration, isVisible: Boolean, on var isLoading by remember { mutableStateOf(false) } var errorMessage by remember { mutableStateOf(null) } val propertyValues = remember { mutableStateMapOf() } + val propertyTags = remember { mutableStateMapOf>() } val focusRequester = remember { FocusRequester() } @@ -144,6 +146,7 @@ fun TaskWindow(client: AnyTypeApi, config: Configuration, isVisible: Boolean, on value = propertyValues[prop.key] ?: "", onValueChange = { propertyValues[prop.key] = it }, client = client, + tags = propertyTags[prop.key] ?: emptyList(), ) } } @@ -174,7 +177,19 @@ fun TaskWindow(client: AnyTypeApi, config: Configuration, isVisible: Boolean, on } } - LaunchedEffect(isVisible) { if (isVisible) focusRequester.requestFocus() } + LaunchedEffect(isVisible) { + if (isVisible) { + focusRequester.requestFocus() + config.properties + .filter { it.format in listOf("select", "multi_select") && it.id.isNotEmpty() } + .forEach { prop -> + launch { + client.getTags(prop.id) + .onSuccess { propertyTags[prop.key] = it } + } + } + } + } } @Composable @@ -183,13 +198,14 @@ private fun PropertyField( value: String, onValueChange: (String) -> Unit, client: AnyTypeApi, + tags: List = emptyList(), ) { when (prop.format) { "select", "multi_select" -> { SelectField( label = prop.name, value = value, - options = prop.possibleValues, + tags = tags, onValueChange = onValueChange, ) } @@ -231,16 +247,17 @@ private fun PropertyField( private fun SelectField( label: String, value: String, - options: List, + tags: List, onValueChange: (String) -> Unit, ) { var expanded by remember { mutableStateOf(false) } + val selectedName = tags.find { it.id == value }?.name ?: value Column { Text(label, style = MaterialTheme.typography.caption) Box { OutlinedButton(onClick = { expanded = true }, modifier = Modifier.fillMaxWidth()) { - Text(value.ifEmpty { "Select..." }) + Text(selectedName.ifEmpty { "Select..." }) } DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { DropdownMenuItem(onClick = { @@ -249,12 +266,12 @@ private fun SelectField( }) { Text("(none)", style = MaterialTheme.typography.caption) } - options.forEach { option -> + tags.forEach { tag -> DropdownMenuItem(onClick = { - onValueChange(option) + onValueChange(tag.id) expanded = false }) { - Text(option) + Text(tag.name) } } }