* feat(#441): add profile cloning and description editing * feat(#441): add profile builder wizard and API enhancements Introduce 5-step Profile Builder wizard into ProfilesScreen and add support for create/clone endpoints. * fix(#441): restore imports and add ProfileInfo constructor defaults * style: run ktlint format on codebase to fix styling errors * fix(#441): address PR review comments including provider slug bug, validation, and strings * fix(#441): remove unused McpServerConfigInput import --------- Co-authored-by: Hermes Agent <hermes@agent.local>
This commit is contained in:
1 parent
846a9380e2
commit
d181851670
37 files changed
+2299
-448
No files matched your search
@@ -88,14 +88,13 @@ import com.m57.hermescontrol.ui.common.ToastEffect
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
private fun formatBytes(bytes: Long): String {
|
||||
return when {
|
||||
private fun formatBytes(bytes: Long): String =
|
||||
when {
|
||||
bytes < 1024 -> "$bytes B"
|
||||
bytes < 1024 * 1024 -> "${bytes / 1024} KB"
|
||||
bytes < 1024 * 1024 * 1024 -> "${bytes / (1024 * 1024)} MB"
|
||||
else -> "${"%.1f".format(bytes.toDouble() / (1024 * 1024 * 1024))} GB"
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatDuration(totalSeconds: Double): String {
|
||||
val days = (totalSeconds / 86400).toInt()
|
||||
@@ -341,8 +340,7 @@ private fun LazyListScope.hostSection(
|
||||
stats.os?.let { InfoRow(stringResource(R.string.system_label_os), it) }
|
||||
stats.arch?.let { InfoRow(stringResource(R.string.system_label_arch), it) }
|
||||
stats.hostname?.let { InfoRow(stringResource(R.string.system_label_hostname), it) }
|
||||
stats.python_version?.let {
|
||||
python ->
|
||||
stats.python_version?.let { python ->
|
||||
val impl = stats.python_impl?.let { " ($it)" } ?: ""
|
||||
InfoRow(stringResource(R.string.system_label_python), "$python$impl")
|
||||
}
|
||||
@@ -352,14 +350,21 @@ private fun LazyListScope.hostSection(
|
||||
val updateBadge =
|
||||
state.updateInfo?.let { info ->
|
||||
when {
|
||||
info.update_available == true && info.behind != null && info.behind > 0 ->
|
||||
info.update_available == true && info.behind != null && info.behind > 0 -> {
|
||||
" (${stringResource(
|
||||
R.string.system_version_update_available,
|
||||
)}: ${stringResource(R.string.system_version_behind, info.behind)})"
|
||||
info.update_available == true -> " (${stringResource(
|
||||
R.string.system_version_update_available,
|
||||
)})"
|
||||
else -> " (${stringResource(R.string.system_version_latest)})"
|
||||
}
|
||||
|
||||
info.update_available == true -> {
|
||||
" (${stringResource(
|
||||
R.string.system_version_update_available,
|
||||
)})"
|
||||
}
|
||||
|
||||
else -> {
|
||||
" (${stringResource(R.string.system_version_latest)})"
|
||||
}
|
||||
}
|
||||
} ?: ""
|
||||
InfoRow(stringResource(R.string.system_label_hermes_version), "$ver$updateBadge")
|
||||
@@ -620,10 +625,12 @@ private fun LazyListScope.curatorSection(
|
||||
statusText = stringResource(R.string.system_status_disabled)
|
||||
statusType = StatusBadgeType.ERROR
|
||||
}
|
||||
|
||||
curator.paused == true -> {
|
||||
statusText = stringResource(R.string.system_status_paused)
|
||||
statusType = StatusBadgeType.WARNING
|
||||
}
|
||||
|
||||
else -> {
|
||||
statusText = stringResource(R.string.system_status_active)
|
||||
statusType = StatusBadgeType.SUCCESS
|
||||
|
||||
@@ -77,7 +77,9 @@ data class SystemUiState(
|
||||
val updateConfirmOpen: Boolean = false,
|
||||
)
|
||||
|
||||
class SystemViewModel : ViewModel(), ToastHost {
|
||||
class SystemViewModel :
|
||||
ViewModel(),
|
||||
ToastHost {
|
||||
companion object {
|
||||
private const val TAG = "SystemViewModel"
|
||||
}
|
||||
@@ -186,6 +188,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
_uiState.update { it.copy(toastMessage = "Gateway ${name}ed successfully") }
|
||||
loadAll()
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update { it.copy(toastMessage = "Failed to $name gateway: ${result.error.message}") }
|
||||
}
|
||||
@@ -206,6 +209,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
is NetworkResult.Success -> {
|
||||
_uiState.update { it.copy(checkingUpdate = false, updateInfo = result.data) }
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
@@ -251,6 +255,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
}
|
||||
loadAll()
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update { it.copy(toastMessage = "Failed to toggle curator: ${result.error.message}") }
|
||||
}
|
||||
@@ -278,6 +283,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
_uiState.update { it.copy(toastMessage = "Memory ($target) reset successfully") }
|
||||
loadAll()
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update { it.copy(toastMessage = "Failed to reset memory: ${result.error.message}") }
|
||||
}
|
||||
@@ -329,6 +335,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
}
|
||||
loadAll()
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(addingCred = false, toastMessage = "Failed to add credential: ${result.error.message}")
|
||||
@@ -352,6 +359,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
_uiState.update { it.copy(toastMessage = "Credential removed") }
|
||||
loadAll()
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update { it.copy(toastMessage = "Failed to remove credential: ${result.error.message}") }
|
||||
}
|
||||
@@ -411,6 +419,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
}
|
||||
loadAll()
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update { it.copy(toastMessage = "Failed to trigger backup: ${result.error.message}") }
|
||||
}
|
||||
@@ -433,6 +442,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
is NetworkResult.Success -> {
|
||||
_uiState.update { it.copy(toastMessage = "Backup downloaded") }
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update { it.copy(toastMessage = "Failed to download backup: ${result.error.message}") }
|
||||
}
|
||||
@@ -475,6 +485,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
@@ -556,6 +567,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
}
|
||||
loadAll()
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
@@ -582,6 +594,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
_uiState.update { it.copy(toastMessage = "Hook deleted") }
|
||||
loadAll()
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update { it.copy(toastMessage = "Failed to delete hook: ${result.error.message}") }
|
||||
}
|
||||
@@ -631,6 +644,7 @@ class SystemViewModel : ViewModel(), ToastHost {
|
||||
result.data?.name?.let { pollActionStatus(it) }
|
||||
_uiState.update { it.copy(toastMessage = "$label started") }
|
||||
}
|
||||
|
||||
is NetworkResult.Failure -> {
|
||||
_uiState.update { it.copy(toastMessage = "$label failed: ${result.error.message}") }
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user