[PM-15116] Add common vault item content to SSH keys (#4365)

This commit is contained in:
Patrick Honkonen
2024-12-02 14:51:59 -05:00
committed by GitHub
parent 02c44f514a
commit 7e82b6e400
3 changed files with 136 additions and 23 deletions

View File

@@ -404,6 +404,7 @@ private fun VaultItemContent(
VaultItemSshKeyContent(
commonState = viewState.common,
sshKeyItemState = viewState.type,
vaultCommonItemTypeHandlers = vaultCommonItemTypeHandlers,
vaultSshKeyItemTypeHandlers = vaultSshKeyItemTypeHandlers,
modifier = modifier,
)

View File

@@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
@@ -18,6 +19,7 @@ import com.x8bit.bitwarden.ui.platform.components.field.BitwardenPasswordField
import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextField
import com.x8bit.bitwarden.ui.platform.components.field.BitwardenTextFieldWithActions
import com.x8bit.bitwarden.ui.platform.components.header.BitwardenListHeaderText
import com.x8bit.bitwarden.ui.vault.feature.item.handlers.VaultCommonItemTypeHandlers
import com.x8bit.bitwarden.ui.vault.feature.item.handlers.VaultSshKeyItemTypeHandlers
/**
@@ -29,6 +31,7 @@ fun VaultItemSshKeyContent(
commonState: VaultItemState.ViewState.Content.Common,
sshKeyItemState: VaultItemState.ViewState.Content.ItemType.SshKey,
vaultSshKeyItemTypeHandlers: VaultSshKeyItemTypeHandlers,
vaultCommonItemTypeHandlers: VaultCommonItemTypeHandlers,
modifier: Modifier = Modifier,
) {
LazyColumn(modifier = modifier) {
@@ -120,6 +123,85 @@ fun VaultItemSshKeyContent(
)
}
commonState.notes?.let { notes ->
item {
Spacer(modifier = Modifier.height(4.dp))
BitwardenListHeaderText(
label = stringResource(id = R.string.notes),
modifier = Modifier
.fillMaxWidth()
.standardHorizontalMargin(),
)
Spacer(modifier = Modifier.height(8.dp))
BitwardenTextFieldWithActions(
label = stringResource(id = R.string.notes),
value = notes,
onValueChange = { },
readOnly = true,
singleLine = false,
actions = {
BitwardenTonalIconButton(
vectorIconRes = R.drawable.ic_copy,
contentDescription = stringResource(id = R.string.copy_notes),
onClick = vaultCommonItemTypeHandlers.onCopyNotesClick,
modifier = Modifier.testTag(tag = "CipherNotesCopyButton"),
)
},
textFieldTestTag = "CipherNotesLabel",
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
)
}
}
commonState.customFields.takeUnless { it.isEmpty() }?.let { customFields ->
item {
Spacer(modifier = Modifier.height(4.dp))
BitwardenListHeaderText(
label = stringResource(id = R.string.custom_fields),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
)
}
items(customFields) { customField ->
Spacer(modifier = Modifier.height(8.dp))
CustomField(
customField = customField,
onCopyCustomHiddenField = vaultCommonItemTypeHandlers.onCopyCustomHiddenField,
onCopyCustomTextField = vaultCommonItemTypeHandlers.onCopyCustomTextField,
onShowHiddenFieldClick = vaultCommonItemTypeHandlers.onShowHiddenFieldClick,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
)
}
}
commonState.attachments.takeUnless { it?.isEmpty() == true }?.let { attachments ->
item {
Spacer(modifier = Modifier.height(4.dp))
BitwardenListHeaderText(
label = stringResource(id = R.string.attachments),
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
)
}
items(attachments) { attachmentItem ->
AttachmentItemContent(
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp),
attachmentItem = attachmentItem,
onAttachmentDownloadClick =
vaultCommonItemTypeHandlers.onAttachmentDownloadClick,
)
}
item { Spacer(modifier = Modifier.height(8.dp)) }
}
item {
Spacer(modifier = Modifier.height(24.dp))
VaultItemUpdateText(

View File

@@ -1366,6 +1366,42 @@ class VaultItemScreenTest : BaseComposeTest() {
viewModel.trySendAction(VaultItemAction.Common.CopyNotesClick)
}
}
@Test
fun `on ssh key copy notes field click should send CopyNotesClick`() {
// Adding a custom field so that we can scroll to it
// So we can see the Copy notes button but not have it covered by the FAB
val textField = VaultItemState.ViewState.Content.Common.Custom.TextField(
name = "text",
value = "value",
isCopyable = true,
)
EMPTY_VIEW_STATES
.forEach { typeState ->
mutableStateFlow.update { currentState ->
currentState.copy(
viewState = typeState.copy(
type = DEFAULT_SSH_KEY,
common = EMPTY_COMMON.copy(
notes = "this is a note",
customFields = listOf(textField),
),
),
)
}
}
composeTestRule.onNodeWithTextAfterScroll(textField.name)
composeTestRule
.onNodeWithTag("CipherNotesCopyButton")
.performClick()
verify {
viewModel.trySendAction(VaultItemAction.Common.CopyNotesClick)
}
}
//endregion common
//region login
@@ -2602,29 +2638,6 @@ private fun updateCardType(
return currentState.copy(viewState = updatedType)
}
private fun updateSshKeyType(
currentState: VaultItemState,
transform: VaultItemState.ViewState.Content.ItemType.SshKey.() ->
VaultItemState.ViewState.Content.ItemType.SshKey,
): VaultItemState {
val updatedType = when (val viewState = currentState.viewState) {
is VaultItemState.ViewState.Content -> {
when (val type = viewState.type) {
is VaultItemState.ViewState.Content.ItemType.SshKey -> {
viewState.copy(
type = type.transform(),
)
}
else -> viewState
}
}
else -> viewState
}
return currentState.copy(viewState = updatedType)
}
private fun updateCommonContent(
currentState: VaultItemState,
transform: VaultItemState.ViewState.Content.Common.()
@@ -2811,6 +2824,15 @@ private val EMPTY_CARD_TYPE: VaultItemState.ViewState.Content.ItemType.Card =
),
)
private val EMPTY_SSH_KEY_TYPE: VaultItemState.ViewState.Content.ItemType.SshKey =
VaultItemState.ViewState.Content.ItemType.SshKey(
name = "",
publicKey = "",
privateKey = "",
fingerprint = "",
showPrivateKey = false,
)
private val EMPTY_LOGIN_VIEW_STATE: VaultItemState.ViewState.Content =
VaultItemState.ViewState.Content(
common = EMPTY_COMMON,
@@ -2835,6 +2857,12 @@ private val EMPTY_SECURE_NOTE_VIEW_STATE =
type = VaultItemState.ViewState.Content.ItemType.SecureNote,
)
private val EMPTY_SSH_KEY_VIEW_STATE =
VaultItemState.ViewState.Content(
common = EMPTY_COMMON,
type = EMPTY_SSH_KEY_TYPE,
)
private val DEFAULT_LOGIN_VIEW_STATE: VaultItemState.ViewState.Content =
VaultItemState.ViewState.Content(
type = DEFAULT_LOGIN,
@@ -2869,10 +2897,12 @@ private val EMPTY_VIEW_STATES = listOf(
EMPTY_LOGIN_VIEW_STATE,
EMPTY_IDENTITY_VIEW_STATE,
EMPTY_SECURE_NOTE_VIEW_STATE,
EMPTY_SSH_KEY_VIEW_STATE,
)
private val DEFAULT_VIEW_STATES = listOf(
DEFAULT_LOGIN_VIEW_STATE,
DEFAULT_IDENTITY_VIEW_STATE,
DEFAULT_SECURE_NOTE_VIEW_STATE,
DEFAULT_SSH_KEY_VIEW_STATE,
)