[PM-11304] Ownership Not Defaulting To Org and Collection (#4254)

This commit is contained in:
André Bispo 2024-11-14 08:15:01 +00:00 committed by GitHub
parent 5938e38070
commit 40f33dff89
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 68 additions and 27 deletions

View file

@ -75,10 +75,11 @@ fun NavGraphBuilder.vaultUnlockedGraph(
vaultItemListingDestinationAsRoot( vaultItemListingDestinationAsRoot(
onNavigateBack = { navController.popBackStack() }, onNavigateBack = { navController.popBackStack() },
onNavigateToVaultItemScreen = { navController.navigateToVaultItem(vaultItemId = it) }, onNavigateToVaultItemScreen = { navController.navigateToVaultItem(vaultItemId = it) },
onNavigateToVaultAddItemScreen = { cipherType, selectedFolderId -> onNavigateToVaultAddItemScreen = { cipherType, selectedFolderId, collectionId ->
navController.navigateToVaultAddEdit( navController.navigateToVaultAddEdit(
VaultAddEditType.AddItem(cipherType), VaultAddEditType.AddItem(cipherType),
selectedFolderId, selectedFolderId,
collectionId,
) )
}, },
onNavigateToSearchVault = { navController.navigateToSearch(searchType = it) }, onNavigateToSearchVault = { navController.navigateToSearch(searchType = it) },
@ -89,10 +90,11 @@ fun NavGraphBuilder.vaultUnlockedGraph(
vaultUnlockedNavBarDestination( vaultUnlockedNavBarDestination(
onNavigateToExportVault = { navController.navigateToExportVault() }, onNavigateToExportVault = { navController.navigateToExportVault() },
onNavigateToFolders = { navController.navigateToFolders() }, onNavigateToFolders = { navController.navigateToFolders() },
onNavigateToVaultAddItem = { cipherType, selectedFolderId -> onNavigateToVaultAddItem = { cipherType, selectedFolderId, collectionId ->
navController.navigateToVaultAddEdit( navController.navigateToVaultAddEdit(
VaultAddEditType.AddItem(cipherType), VaultAddEditType.AddItem(cipherType),
selectedFolderId, selectedFolderId,
collectionId,
) )
}, },
onNavigateToVaultItem = { navController.navigateToVaultItem(it) }, onNavigateToVaultItem = { navController.navigateToVaultItem(it) },

View file

@ -25,7 +25,7 @@ fun NavController.navigateToVaultUnlockedNavBar(navOptions: NavOptions? = null)
*/ */
@Suppress("LongParameterList") @Suppress("LongParameterList")
fun NavGraphBuilder.vaultUnlockedNavBarDestination( fun NavGraphBuilder.vaultUnlockedNavBarDestination(
onNavigateToVaultAddItem: (VaultItemCipherType, String?) -> Unit, onNavigateToVaultAddItem: (VaultItemCipherType, String?, String?) -> Unit,
onNavigateToVaultItem: (vaultItemId: String) -> Unit, onNavigateToVaultItem: (vaultItemId: String) -> Unit,
onNavigateToVaultEditItem: (vaultItemId: String) -> Unit, onNavigateToVaultEditItem: (vaultItemId: String) -> Unit,
onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit, onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit,

View file

@ -62,7 +62,7 @@ import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType
fun VaultUnlockedNavBarScreen( fun VaultUnlockedNavBarScreen(
viewModel: VaultUnlockedNavBarViewModel = hiltViewModel(), viewModel: VaultUnlockedNavBarViewModel = hiltViewModel(),
navController: NavHostController = rememberNavController(), navController: NavHostController = rememberNavController(),
onNavigateToVaultAddItem: (VaultItemCipherType, String?) -> Unit, onNavigateToVaultAddItem: (VaultItemCipherType, String?, String?) -> Unit,
onNavigateToVaultItem: (vaultItemId: String) -> Unit, onNavigateToVaultItem: (vaultItemId: String) -> Unit,
onNavigateToVaultEditItem: (vaultItemId: String) -> Unit, onNavigateToVaultEditItem: (vaultItemId: String) -> Unit,
onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit, onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit,
@ -156,7 +156,7 @@ private fun VaultUnlockedNavBarScaffold(
sendTabClickedAction: () -> Unit, sendTabClickedAction: () -> Unit,
generatorTabClickedAction: () -> Unit, generatorTabClickedAction: () -> Unit,
settingsTabClickedAction: () -> Unit, settingsTabClickedAction: () -> Unit,
navigateToVaultAddItem: (VaultItemCipherType, String?) -> Unit, navigateToVaultAddItem: (VaultItemCipherType, String?, String?) -> Unit,
onNavigateToVaultItem: (vaultItemId: String) -> Unit, onNavigateToVaultItem: (vaultItemId: String) -> Unit,
onNavigateToVaultEditItem: (vaultItemId: String) -> Unit, onNavigateToVaultEditItem: (vaultItemId: String) -> Unit,
onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit, onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit,

View file

@ -27,13 +27,15 @@ private const val ADD_ITEM_TYPE: String = "vault_add_item_type"
private const val ADD_EDIT_ITEM_PREFIX: String = "vault_add_edit_item" private const val ADD_EDIT_ITEM_PREFIX: String = "vault_add_edit_item"
private const val ADD_EDIT_ITEM_TYPE: String = "vault_add_edit_type" private const val ADD_EDIT_ITEM_TYPE: String = "vault_add_edit_type"
private const val ADD_SELECTED_FOLDER_ID: String = "vault_add_selected_folder_id" private const val ADD_SELECTED_FOLDER_ID: String = "vault_add_selected_folder_id"
private const val ADD_SELECTED_COLLECTION_ID: String = "vault_add_selected_collection_id"
private const val ADD_EDIT_ITEM_ROUTE: String = private const val ADD_EDIT_ITEM_ROUTE: String =
ADD_EDIT_ITEM_PREFIX + ADD_EDIT_ITEM_PREFIX +
"/{$ADD_EDIT_ITEM_TYPE}" + "/{$ADD_EDIT_ITEM_TYPE}" +
"?$EDIT_ITEM_ID={$EDIT_ITEM_ID}" + "?$EDIT_ITEM_ID={$EDIT_ITEM_ID}" +
"?$ADD_ITEM_TYPE={$ADD_ITEM_TYPE}" + "?$ADD_ITEM_TYPE={$ADD_ITEM_TYPE}" +
"?$ADD_SELECTED_FOLDER_ID={$ADD_SELECTED_FOLDER_ID}" "?$ADD_SELECTED_FOLDER_ID={$ADD_SELECTED_FOLDER_ID}" +
"?$ADD_SELECTED_COLLECTION_ID={$ADD_SELECTED_COLLECTION_ID}"
/** /**
* Class to retrieve vault add & edit arguments from the [SavedStateHandle]. * Class to retrieve vault add & edit arguments from the [SavedStateHandle].
@ -42,6 +44,7 @@ private const val ADD_EDIT_ITEM_ROUTE: String =
data class VaultAddEditArgs( data class VaultAddEditArgs(
val vaultAddEditType: VaultAddEditType, val vaultAddEditType: VaultAddEditType,
val selectedFolderId: String? = null, val selectedFolderId: String? = null,
val selectedCollectionId: String? = null,
) { ) {
constructor(savedStateHandle: SavedStateHandle) : this( constructor(savedStateHandle: SavedStateHandle) : this(
vaultAddEditType = when (requireNotNull(savedStateHandle[ADD_EDIT_ITEM_TYPE])) { vaultAddEditType = when (requireNotNull(savedStateHandle[ADD_EDIT_ITEM_TYPE])) {
@ -57,6 +60,7 @@ data class VaultAddEditArgs(
else -> throw IllegalStateException("Unknown VaultAddEditType.") else -> throw IllegalStateException("Unknown VaultAddEditType.")
}, },
selectedFolderId = savedStateHandle[ADD_SELECTED_FOLDER_ID], selectedFolderId = savedStateHandle[ADD_SELECTED_FOLDER_ID],
selectedCollectionId = savedStateHandle[ADD_SELECTED_COLLECTION_ID],
) )
} }
@ -80,6 +84,10 @@ fun NavGraphBuilder.vaultAddEditDestination(
type = NavType.StringType type = NavType.StringType
nullable = true nullable = true
}, },
navArgument(ADD_SELECTED_COLLECTION_ID) {
type = NavType.StringType
nullable = true
},
), ),
) { ) {
VaultAddEditScreen( VaultAddEditScreen(
@ -99,13 +107,15 @@ fun NavGraphBuilder.vaultAddEditDestination(
fun NavController.navigateToVaultAddEdit( fun NavController.navigateToVaultAddEdit(
vaultAddEditType: VaultAddEditType, vaultAddEditType: VaultAddEditType,
selectedFolderId: String? = null, selectedFolderId: String? = null,
selectedCollectionId: String? = null,
navOptions: NavOptions? = null, navOptions: NavOptions? = null,
) { ) {
navigate( navigate(
route = "$ADD_EDIT_ITEM_PREFIX/${vaultAddEditType.toTypeString()}" + route = "$ADD_EDIT_ITEM_PREFIX/${vaultAddEditType.toTypeString()}" +
"?$EDIT_ITEM_ID=${vaultAddEditType.toIdOrNull()}" + "?$EDIT_ITEM_ID=${vaultAddEditType.toIdOrNull()}" +
"?$ADD_ITEM_TYPE=${vaultAddEditType.toVaultItemCipherTypeOrNull()}" + "?$ADD_ITEM_TYPE=${vaultAddEditType.toVaultItemCipherTypeOrNull()}" +
"?$ADD_SELECTED_FOLDER_ID=$selectedFolderId", "?$ADD_SELECTED_FOLDER_ID=$selectedFolderId" +
"?$ADD_SELECTED_COLLECTION_ID=$selectedCollectionId",
navOptions = navOptions, navOptions = navOptions,
) )
} }

View file

@ -107,6 +107,7 @@ class VaultAddEditViewModel @Inject constructor(
?: run { ?: run {
val vaultAddEditType = VaultAddEditArgs(savedStateHandle).vaultAddEditType val vaultAddEditType = VaultAddEditArgs(savedStateHandle).vaultAddEditType
val selectedFolderId = VaultAddEditArgs(savedStateHandle).selectedFolderId val selectedFolderId = VaultAddEditArgs(savedStateHandle).selectedFolderId
val selectedCollectionId = VaultAddEditArgs(savedStateHandle).selectedCollectionId
val isIndividualVaultDisabled = policyManager val isIndividualVaultDisabled = policyManager
.getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP) .getActivePolicies(type = PolicyTypeJson.PERSONAL_OWNERSHIP)
.any() .any()
@ -147,12 +148,11 @@ class VaultAddEditViewModel @Inject constructor(
attestationOptions = fido2AttestationOptions, attestationOptions = fido2AttestationOptions,
isIndividualVaultDisabled = isIndividualVaultDisabled, isIndividualVaultDisabled = isIndividualVaultDisabled,
) )
?: totpData?.toDefaultAddTypeContent( ?: totpData?.toDefaultAddTypeContent(isIndividualVaultDisabled)
isIndividualVaultDisabled = isIndividualVaultDisabled,
)
?: VaultAddEditState.ViewState.Content( ?: VaultAddEditState.ViewState.Content(
common = VaultAddEditState.ViewState.Content.Common( common = VaultAddEditState.ViewState.Content.Common(
selectedFolderId = selectedFolderId, selectedFolderId = selectedFolderId,
selectedCollectionId = selectedCollectionId,
), ),
isIndividualVaultDisabled = isIndividualVaultDisabled, isIndividualVaultDisabled = isIndividualVaultDisabled,
type = vaultAddEditType.vaultItemCipherType.toItemType(), type = vaultAddEditType.vaultItemCipherType.toItemType(),
@ -2113,6 +2113,7 @@ data class VaultAddEditState(
val favorite: Boolean = false, val favorite: Boolean = false,
val customFieldData: List<Custom> = emptyList(), val customFieldData: List<Custom> = emptyList(),
val notes: String = "", val notes: String = "",
val selectedCollectionId: String? = null,
val selectedFolderId: String? = null, val selectedFolderId: String? = null,
val availableFolders: List<Folder> = emptyList(), val availableFolders: List<Folder> = emptyList(),
val selectedOwnerId: String? = null, val selectedOwnerId: String? = null,

View file

@ -132,17 +132,20 @@ fun VaultAddEditState.ViewState.appendFolderAndOwnerData(
selectedFolderId = folderViewList.toSelectedFolderId( selectedFolderId = folderViewList.toSelectedFolderId(
cipherView = currentContentState.common.originalCipher, cipherView = currentContentState.common.originalCipher,
) )
?: currentContentState.common.selectedFolderId, ?: currentContentState.common.selectedFolderId,
availableFolders = folderViewList.toAvailableFolders( availableFolders = folderViewList.toAvailableFolders(
resourceManager = resourceManager, resourceManager = resourceManager,
), ),
selectedOwnerId = activeAccount.toSelectedOwnerId( selectedOwnerId = activeAccount
cipherView = currentContentState.common.originalCipher, .toSelectedOwnerId(cipherView = currentContentState.common.originalCipher)
), ?: collectionViewList
.firstOrNull { it.id == currentContentState.common.selectedCollectionId }
?.organizationId,
availableOwners = activeAccount.toAvailableOwners( availableOwners = activeAccount.toAvailableOwners(
collectionViewList = collectionViewList, collectionViewList = collectionViewList,
cipherView = currentContentState.common.originalCipher, cipherView = currentContentState.common.originalCipher,
isIndividualVaultDisabled = isIndividualVaultDisabled, isIndividualVaultDisabled = isIndividualVaultDisabled,
selectedCollectionId = currentContentState.common.selectedCollectionId,
), ),
isUnlockWithPasswordEnabled = activeAccount.hasMasterPassword, isUnlockWithPasswordEnabled = activeAccount.hasMasterPassword,
hasOrganizations = activeAccount.organizations.isNotEmpty(), hasOrganizations = activeAccount.organizations.isNotEmpty(),
@ -197,13 +200,15 @@ private fun UserState.Account.toAvailableOwners(
collectionViewList: List<CollectionView>, collectionViewList: List<CollectionView>,
cipherView: CipherView?, cipherView: CipherView?,
isIndividualVaultDisabled: Boolean, isIndividualVaultDisabled: Boolean,
selectedCollectionId: String? = null,
): List<VaultAddEditState.Owner> = ): List<VaultAddEditState.Owner> =
listOfNotNull( listOfNotNull(
VaultAddEditState.Owner( VaultAddEditState
name = email, .Owner(
id = null, name = email,
collections = emptyList(), id = null,
) collections = emptyList(),
)
.takeUnless { isIndividualVaultDisabled }, .takeUnless { isIndividualVaultDisabled },
*organizations *organizations
.map { .map {
@ -219,9 +224,11 @@ private fun UserState.Account.toAvailableOwners(
VaultCollection( VaultCollection(
id = collection.id.orEmpty(), id = collection.id.orEmpty(),
name = collection.name, name = collection.name,
isSelected = cipherView isSelected = (cipherView
?.collectionIds ?.collectionIds
?.contains(collection.id) == true, ?.contains(collection.id))
?: (selectedCollectionId != null &&
collection.id == selectedCollectionId),
) )
}, },
) )

View file

@ -67,6 +67,7 @@ fun NavGraphBuilder.vaultItemListingDestination(
onNavigateToVaultAddItemScreen: ( onNavigateToVaultAddItemScreen: (
cipherType: VaultItemCipherType, cipherType: VaultItemCipherType,
selectedFolderId: String?, selectedFolderId: String?,
selectedCollectionId: String?,
) -> Unit, ) -> Unit,
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
) { ) {
@ -93,6 +94,7 @@ fun NavGraphBuilder.vaultItemListingDestinationAsRoot(
onNavigateToVaultAddItemScreen: ( onNavigateToVaultAddItemScreen: (
cipherType: VaultItemCipherType, cipherType: VaultItemCipherType,
selectedFolderId: String?, selectedFolderId: String?,
selectedCollectionId: String?,
) -> Unit, ) -> Unit,
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit, onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
) { ) {
@ -134,7 +136,7 @@ fun NavGraphBuilder.sendItemListingDestination(
onNavigateBack = onNavigateBack, onNavigateBack = onNavigateBack,
onNavigateToAddSendItem = onNavigateToAddSendItem, onNavigateToAddSendItem = onNavigateToAddSendItem,
onNavigateToEditSendItem = onNavigateToEditSendItem, onNavigateToEditSendItem = onNavigateToEditSendItem,
onNavigateToVaultAddItemScreen = { _, _ -> }, onNavigateToVaultAddItemScreen = { _, _, _ -> },
onNavigateToVaultItemScreen = { }, onNavigateToVaultItemScreen = { },
onNavigateToVaultEditItemScreen = { }, onNavigateToVaultEditItemScreen = { },
onNavigateToVaultItemListing = { }, onNavigateToVaultItemListing = { },
@ -155,6 +157,7 @@ private fun NavGraphBuilder.internalVaultItemListingDestination(
onNavigateToVaultAddItemScreen: ( onNavigateToVaultAddItemScreen: (
cipherType: VaultItemCipherType, cipherType: VaultItemCipherType,
selectedFolderId: String?, selectedFolderId: String?,
selectedCollectionId: String?,
) -> Unit, ) -> Unit,
onNavigateToAddSendItem: () -> Unit, onNavigateToAddSendItem: () -> Unit,
onNavigateToEditSendItem: (sendId: String) -> Unit, onNavigateToEditSendItem: (sendId: String) -> Unit,

View file

@ -74,6 +74,7 @@ fun VaultItemListingScreen(
onNavigateToVaultAddItemScreen: ( onNavigateToVaultAddItemScreen: (
vaultItemCipherType: VaultItemCipherType, vaultItemCipherType: VaultItemCipherType,
selectedFolderId: String?, selectedFolderId: String?,
selectedCollectionId: String?,
) -> Unit, ) -> Unit,
onNavigateToAddSendItem: () -> Unit, onNavigateToAddSendItem: () -> Unit,
onNavigateToEditSendItem: (sendId: String) -> Unit, onNavigateToEditSendItem: (sendId: String) -> Unit,
@ -118,6 +119,7 @@ fun VaultItemListingScreen(
onNavigateToVaultAddItemScreen( onNavigateToVaultAddItemScreen(
event.vaultItemCipherType, event.vaultItemCipherType,
event.selectedFolderId, event.selectedFolderId,
event.selectedCollectionId,
) )
} }
@ -446,7 +448,7 @@ private fun VaultItemListingScaffold(
) )
}, },
floatingActionButton = { floatingActionButton = {
if (state.itemListingType.hasFab) { if (state.hasAddItemFabButton) {
BitwardenFloatingActionButton( BitwardenFloatingActionButton(
onClick = vaultItemListingHandlers.addVaultItemClick, onClick = vaultItemListingHandlers.addVaultItemClick,
painter = rememberVectorPainter(id = R.drawable.ic_plus_large), painter = rememberVectorPainter(id = R.drawable.ic_plus_large),

View file

@ -541,6 +541,13 @@ class VaultItemListingViewModel @Inject constructor(
) )
} }
is VaultItemListingState.ItemListingType.Vault.Collection -> {
VaultItemListingEvent.NavigateToAddVaultItem(
vaultItemCipherType = itemListingType.toVaultItemCipherType(),
selectedCollectionId = itemListingType.collectionId,
)
}
is VaultItemListingState.ItemListingType.Vault -> { is VaultItemListingState.ItemListingType.Vault -> {
VaultItemListingEvent.NavigateToAddVaultItem( VaultItemListingEvent.NavigateToAddVaultItem(
vaultItemCipherType = itemListingType.toVaultItemCipherType(), vaultItemCipherType = itemListingType.toVaultItemCipherType(),
@ -1739,6 +1746,13 @@ data class VaultItemListingState(
val isPremium: Boolean, val isPremium: Boolean,
val isRefreshing: Boolean, val isRefreshing: Boolean,
) { ) {
/**
* Whether or not the add FAB should be shown.
*/
val hasAddItemFabButton: Boolean
get() = itemListingType.hasFab &&
!(viewState is ViewState.NoItems && viewState.shouldShowAddButton)
/** /**
* Whether or not this represents a listing screen for autofill. * Whether or not this represents a listing screen for autofill.
*/ */
@ -2111,7 +2125,7 @@ data class VaultItemListingState(
val collectionName: String = "", val collectionName: String = "",
) : Vault() { ) : Vault() {
override val titleText: Text get() = collectionName.asText() override val titleText: Text get() = collectionName.asText()
override val hasFab: Boolean get() = false override val hasFab: Boolean get() = true
} }
} }
@ -2158,6 +2172,7 @@ sealed class VaultItemListingEvent {
data class NavigateToAddVaultItem( data class NavigateToAddVaultItem(
val vaultItemCipherType: VaultItemCipherType, val vaultItemCipherType: VaultItemCipherType,
val selectedFolderId: String? = null, val selectedFolderId: String? = null,
val selectedCollectionId: String? = null,
) : VaultItemListingEvent() ) : VaultItemListingEvent()
/** /**

View file

@ -23,6 +23,7 @@ fun NavGraphBuilder.vaultGraph(
onNavigateToVaultAddItemScreen: ( onNavigateToVaultAddItemScreen: (
vaultItemCipherType: VaultItemCipherType, vaultItemCipherType: VaultItemCipherType,
selectedFolderId: String?, selectedFolderId: String?,
selectedCollectionId: String?,
) -> Unit, ) -> Unit,
onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit, onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit,
onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit, onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit,
@ -36,7 +37,7 @@ fun NavGraphBuilder.vaultGraph(
) { ) {
vaultDestination( vaultDestination(
onNavigateToVaultAddItemScreen = { onNavigateToVaultAddItemScreen = {
onNavigateToVaultAddItemScreen(VaultItemCipherType.LOGIN, null) onNavigateToVaultAddItemScreen(VaultItemCipherType.LOGIN, null, null)
}, },
onNavigateToVaultItemScreen = onNavigateToVaultItemScreen, onNavigateToVaultItemScreen = onNavigateToVaultItemScreen,
onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen, onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen,

View file

@ -41,7 +41,7 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() {
VaultUnlockedNavBarScreen( VaultUnlockedNavBarScreen(
viewModel = viewModel, viewModel = viewModel,
navController = fakeNavHostController, navController = fakeNavHostController,
onNavigateToVaultAddItem = { _, _ -> }, onNavigateToVaultAddItem = { _, _, _ -> },
onNavigateToVaultItem = {}, onNavigateToVaultItem = {},
onNavigateToVaultEditItem = {}, onNavigateToVaultEditItem = {},
onNavigateToAddSend = {}, onNavigateToAddSend = {},

View file

@ -117,7 +117,7 @@ class VaultItemListingScreenTest : BaseComposeTest() {
biometricsManager = biometricsManager, biometricsManager = biometricsManager,
onNavigateBack = { onNavigateBackCalled = true }, onNavigateBack = { onNavigateBackCalled = true },
onNavigateToVaultItem = { onNavigateToVaultItemId = it }, onNavigateToVaultItem = { onNavigateToVaultItemId = it },
onNavigateToVaultAddItemScreen = { _, _ -> onNavigateToVaultAddItemScreen = { _, _, _ ->
onNavigateToVaultAddItemScreenCalled = true onNavigateToVaultAddItemScreenCalled = true
}, },
onNavigateToAddSendItem = { onNavigateToAddSendScreenCalled = true }, onNavigateToAddSendItem = { onNavigateToAddSendScreenCalled = true },