Added remote branch deletion
This commit is contained in:
parent
fc4d52b57a
commit
07703a66be
@ -9,6 +9,7 @@ import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.lib.ProgressMonitor
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
import org.eclipse.jgit.transport.*
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
@ -25,11 +26,7 @@ class RemoteOperationsManager @Inject constructor(
|
||||
git
|
||||
.pull()
|
||||
.setTransportConfigCallback {
|
||||
if (it is SshTransport) {
|
||||
it.sshSessionFactory = sessionManager.generateSshSessionFactory()
|
||||
} else if (it is HttpTransport) {
|
||||
it.credentialsProvider = HttpCredentialsProvider()
|
||||
}
|
||||
handleTransportCredentials(it)
|
||||
}
|
||||
.setRebase(rebase)
|
||||
.setCredentialsProvider(CredentialsProvider.getDefault())
|
||||
@ -44,11 +41,7 @@ class RemoteOperationsManager @Inject constructor(
|
||||
.setRemote(remote.name)
|
||||
.setRefSpecs(remote.fetchRefSpecs)
|
||||
.setTransportConfigCallback {
|
||||
if (it is SshTransport) {
|
||||
it.sshSessionFactory = sessionManager.generateSshSessionFactory()
|
||||
} else if (it is HttpTransport) {
|
||||
it.credentialsProvider = HttpCredentialsProvider()
|
||||
}
|
||||
handleTransportCredentials(it)
|
||||
}
|
||||
.setCredentialsProvider(CredentialsProvider.getDefault())
|
||||
.call()
|
||||
@ -64,11 +57,7 @@ class RemoteOperationsManager @Inject constructor(
|
||||
.setForce(force)
|
||||
.setPushTags()
|
||||
.setTransportConfigCallback {
|
||||
if (it is SshTransport) {
|
||||
it.sshSessionFactory = sessionManager.generateSshSessionFactory()
|
||||
} else if (it is HttpTransport) {
|
||||
it.credentialsProvider = HttpCredentialsProvider()
|
||||
}
|
||||
handleTransportCredentials(it)
|
||||
}
|
||||
.call()
|
||||
|
||||
@ -87,6 +76,40 @@ class RemoteOperationsManager @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleTransportCredentials(transport: Transport?) {
|
||||
if (transport is SshTransport) {
|
||||
transport.sshSessionFactory = sessionManager.generateSshSessionFactory()
|
||||
} else if (transport is HttpTransport) {
|
||||
transport.credentialsProvider = HttpCredentialsProvider()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun deleteBranch(git: Git, ref: Ref) = withContext(Dispatchers.IO) {
|
||||
git
|
||||
.branchDelete()
|
||||
.setBranchNames(ref.name)
|
||||
.call()
|
||||
|
||||
val branchSplit = ref.name.split("/").toMutableList()
|
||||
val remoteName = branchSplit[2] // Remote name
|
||||
repeat(3) {
|
||||
branchSplit.removeAt(0)
|
||||
}
|
||||
|
||||
val branchName = "refs/heads/${branchSplit.joinToString("/")}"
|
||||
|
||||
val refSpec = RefSpec()
|
||||
.setSource(null)
|
||||
.setDestination(branchName)
|
||||
git.push()
|
||||
.setTransportConfigCallback {
|
||||
handleTransportCredentials(it)
|
||||
}
|
||||
.setRefSpecs(refSpec)
|
||||
.setRemote(remoteName)
|
||||
.call()
|
||||
}
|
||||
|
||||
private val RemoteRefUpdate.Status.isRejected: Boolean
|
||||
get() {
|
||||
return this == RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD ||
|
||||
@ -140,11 +163,7 @@ class RemoteOperationsManager @Inject constructor(
|
||||
|
||||
})
|
||||
.setTransportConfigCallback {
|
||||
if (it is SshTransport) {
|
||||
it.sshSessionFactory = sessionManager.generateSshSessionFactory()
|
||||
} else if (it is HttpTransport) {
|
||||
it.credentialsProvider = HttpCredentialsProvider()
|
||||
}
|
||||
handleTransportCredentials(it)
|
||||
}
|
||||
.call()
|
||||
|
||||
@ -158,6 +177,7 @@ class RemoteOperationsManager @Inject constructor(
|
||||
_cloneStatus.value = CloneStatus.None
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
sealed class CloneStatus {
|
||||
|
@ -1,5 +1,7 @@
|
||||
package app.ui
|
||||
|
||||
import androidx.compose.foundation.ContextMenuArea
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@ -11,10 +13,16 @@ import app.extensions.simpleVisibleName
|
||||
import app.git.RemoteInfo
|
||||
import app.ui.components.SideMenuPanel
|
||||
import app.ui.components.SideMenuSubentry
|
||||
import app.ui.components.VerticalExpandable
|
||||
import app.ui.context_menu.remoteBranchesContextMenu
|
||||
import app.viewmodels.RemotesViewModel
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
|
||||
@Composable
|
||||
fun Remotes(remotesViewModel: RemotesViewModel) {
|
||||
fun Remotes(
|
||||
remotesViewModel: RemotesViewModel,
|
||||
onBranchClicked: (Ref) -> Unit,
|
||||
) {
|
||||
val remotes by remotesViewModel.remotes.collectAsState()
|
||||
|
||||
val itemsCount = remember(remotes) {
|
||||
@ -28,28 +36,48 @@ fun Remotes(remotesViewModel: RemotesViewModel) {
|
||||
items = remotes,
|
||||
itemsCountForMaxHeight = itemsCount,
|
||||
itemContent = { remoteInfo ->
|
||||
RemoteRow(remoteInfo)
|
||||
RemoteRow(
|
||||
remote = remoteInfo,
|
||||
onBranchClicked = { branch -> onBranchClicked(branch) },
|
||||
onDeleteBranch = { branch -> remotesViewModel.deleteBranch(branch) }
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun RemoteRow(
|
||||
remote: RemoteInfo,
|
||||
onBranchClicked: (Ref) -> Unit,
|
||||
onDeleteBranch: (Ref) -> Unit,
|
||||
) {
|
||||
SideMenuSubentry(
|
||||
text = remote.remoteConfig.name,
|
||||
iconResourcePath = "cloud.svg",
|
||||
)
|
||||
|
||||
val branches = remote.branchesList
|
||||
Column {
|
||||
branches.forEach { branch ->
|
||||
VerticalExpandable(
|
||||
header = {
|
||||
SideMenuSubentry(
|
||||
text = branch.simpleVisibleName,
|
||||
extraPadding = 8.dp,
|
||||
iconResourcePath = "branch.svg",
|
||||
text = remote.remoteConfig.name,
|
||||
iconResourcePath = "cloud.svg",
|
||||
)
|
||||
}
|
||||
) {
|
||||
val branches = remote.branchesList
|
||||
Column {
|
||||
branches.forEach { branch ->
|
||||
ContextMenuArea(
|
||||
items = {
|
||||
remoteBranchesContextMenu(
|
||||
onDeleteBranch = { onDeleteBranch(branch) }
|
||||
)
|
||||
}
|
||||
) {
|
||||
SideMenuSubentry(
|
||||
text = branch.simpleVisibleName,
|
||||
extraPadding = 8.dp,
|
||||
iconResourcePath = "branch.svg",
|
||||
onClick = { onBranchClicked(branch) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -65,7 +65,12 @@ fun RepositoryOpenPage(tabViewModel: TabViewModel) {
|
||||
tabViewModel.newSelectedRef(it.objectId)
|
||||
}
|
||||
)
|
||||
Remotes(remotesViewModel = tabViewModel.remotesViewModel)
|
||||
Remotes(
|
||||
remotesViewModel = tabViewModel.remotesViewModel,
|
||||
onBranchClicked = {
|
||||
tabViewModel.newSelectedRef(it.objectId)
|
||||
}
|
||||
)
|
||||
Tags(
|
||||
tagsViewModel = tabViewModel.tagsViewModel,
|
||||
onTagClicked = {
|
||||
|
@ -25,14 +25,19 @@ fun SideMenuSubentry(
|
||||
iconResourcePath: String,
|
||||
bold: Boolean = false,
|
||||
extraPadding: Dp = 0.dp,
|
||||
onClick: () -> Unit = {},
|
||||
onClick: (() -> Unit)? = null,
|
||||
additionalInfo: @Composable () -> Unit = {}
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(ENTRY_HEIGHT.dp)
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onClick)
|
||||
.run {
|
||||
if(onClick != null)
|
||||
clickable(onClick = onClick)
|
||||
else
|
||||
this
|
||||
}
|
||||
.padding(start = extraPadding),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
|
@ -0,0 +1,17 @@
|
||||
@file:OptIn(ExperimentalFoundationApi::class)
|
||||
|
||||
package app.ui.context_menu
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
|
||||
fun remoteBranchesContextMenu(
|
||||
onDeleteBranch: () -> Unit
|
||||
): List<ContextMenuItem> {
|
||||
return mutableListOf(
|
||||
ContextMenuItem(
|
||||
label = "Delete remote branch",
|
||||
onClick = onDeleteBranch
|
||||
),
|
||||
)
|
||||
}
|
@ -1,18 +1,19 @@
|
||||
package app.viewmodels
|
||||
|
||||
import app.git.BranchesManager
|
||||
import app.git.RemoteInfo
|
||||
import app.git.RemotesManager
|
||||
import app.git.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.lib.Ref
|
||||
import javax.inject.Inject
|
||||
|
||||
class RemotesViewModel @Inject constructor(
|
||||
private val remotesManager: RemotesManager,
|
||||
private val remoteOperationsManager: RemoteOperationsManager,
|
||||
private val branchesManager: BranchesManager,
|
||||
private val tabState: TabState,
|
||||
) {
|
||||
private val _remotes = MutableStateFlow<List<RemoteInfo>>(listOf())
|
||||
val remotes: StateFlow<List<RemoteInfo>>
|
||||
@ -34,6 +35,12 @@ class RemotesViewModel @Inject constructor(
|
||||
_remotes.value = remoteInfoList
|
||||
}
|
||||
|
||||
fun deleteBranch(ref: Ref) = tabState.safeProcessing { git ->
|
||||
remoteOperationsManager.deleteBranch(git, ref)
|
||||
|
||||
return@safeProcessing RefreshType.ALL_DATA
|
||||
}
|
||||
|
||||
suspend fun refresh(git: Git) = withContext(Dispatchers.IO) {
|
||||
loadRemotes(git)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user