diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreen.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreen.kt index 2e8aecc0f4..51e3ca31ab 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreen.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreen.kt @@ -371,9 +371,7 @@ fun VaultAddEditScreen( } }, ) - .takeUnless { - state.isAddItemMode || state.isCipherInCollection - }, + .takeUnless { !state.shouldShowMoveToOrganization }, OverflowMenuItemData( text = stringResource(id = BitwardenString.collections), onClick = remember(viewModel) { diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt index ac8042231d..c767e8de00 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditViewModel.kt @@ -2312,6 +2312,17 @@ data class VaultAddEditState( ((viewState as? ViewState.Content)?.type is ViewState.Content.ItemType.Login) && isAddItemMode + val hasOrganizations: Boolean + get() = (viewState as? ViewState.Content) + ?.common + ?.hasOrganizations + ?: false + + val shouldShowMoveToOrganization: Boolean + get() = !isAddItemMode && + !isCipherInCollection && + hasOrganizations + /** * Enum representing the main type options for the vault, such as LOGIN, CARD, etc. * diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemScreen.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemScreen.kt index e278e36d46..47db4f9c87 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemScreen.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemScreen.kt @@ -194,7 +194,10 @@ fun VaultItemScreen( } }, ) - .takeUnless { state.isCipherInCollection }, + .takeUnless { + state.isCipherInCollection || + !state.hasOrganizations + }, OverflowMenuItemData( text = stringResource(id = BitwardenString.collections), onClick = remember(viewModel) { diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModel.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModel.kt index 088228e1ab..0b930ee373 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModel.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModel.kt @@ -188,6 +188,9 @@ class VaultItemViewModel @Inject constructor( folderName?.let { VaultItemLocation.Folder(it) }, ) + val hasOrganizations = + !userState?.activeAccount?.organizations.isNullOrEmpty() + VaultItemStateData( cipher = cipherView, totpCodeItemData = totpCodeData, @@ -196,6 +199,7 @@ class VaultItemViewModel @Inject constructor( canAssociateToCollections = canAssignToCollections, canEdit = canEdit, relatedLocations = relatedLocations, + hasOrganizations = hasOrganizations, ) }, ) @@ -1074,6 +1078,7 @@ class VaultItemViewModel @Inject constructor( baseIconUrl = environmentRepository.environment.environmentUrlData.baseIconUrl, isIconLoadingDisabled = settingsRepository.isIconLoadingDisabled, relatedLocations = this.data?.relatedLocations.orEmpty().toImmutableList(), + hasOrganizations = this.data?.hasOrganizations == true, ) ?: VaultItemState.ViewState.Error(message = errorText) @@ -1336,6 +1341,12 @@ data class VaultItemState( ?.canAssignToCollections ?: false + val hasOrganizations: Boolean + get() = viewState.asContentOrNull() + ?.common + ?.hasOrganizations + ?: false + /** * The text to display on the deletion confirmation dialog. */ @@ -1392,6 +1403,7 @@ data class VaultItemState( * collections. * @property favorite Indicates that the cipher is favorite. * @property passwordHistoryCount An integer indicating how many times the password. + * @property hasOrganizations Indicates if the user has organizations. */ @Parcelize data class Common( @@ -1412,6 +1424,7 @@ data class VaultItemState( val passwordHistoryCount: Int?, val iconData: IconData, val relatedLocations: ImmutableList, + val hasOrganizations: Boolean, ) : Parcelable { /** diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/model/VaultItemStateData.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/model/VaultItemStateData.kt index 1519cd57ad..1829ebdf9c 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/model/VaultItemStateData.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/model/VaultItemStateData.kt @@ -12,6 +12,7 @@ import kotlinx.collections.immutable.ImmutableList * @property canAssociateToCollections Whether the item can be associated to a collection. * @property canEdit Whether the item can be edited. * @property relatedLocations The locations the item is assigned to. + * @property hasOrganizations Whether the user has organizations. */ data class VaultItemStateData( val cipher: CipherView?, @@ -21,4 +22,5 @@ data class VaultItemStateData( val canAssociateToCollections: Boolean, val canEdit: Boolean, val relatedLocations: ImmutableList, + val hasOrganizations: Boolean, ) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensions.kt index 5d3e7a8da5..50c50f3400 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensions.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensions.kt @@ -47,6 +47,7 @@ fun CipherView.toViewState( baseIconUrl: String, isIconLoadingDisabled: Boolean, relatedLocations: ImmutableList, + hasOrganizations: Boolean, ): VaultItemState.ViewState = VaultItemState.ViewState.Content( common = VaultItemState.ViewState.Content.Common( @@ -113,6 +114,7 @@ fun CipherView.toViewState( isIconLoadingDisabled = isIconLoadingDisabled, ), relatedLocations = relatedLocations, + hasOrganizations = hasOrganizations, ), type = when (type) { CipherType.LOGIN -> { diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt index 55cc0dce48..c5bccb612a 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/addedit/VaultAddEditScreenTest.kt @@ -3601,6 +3601,7 @@ class VaultAddEditScreenTest : BitwardenComposeTest() { originalCipher = createMockCipherView(1).copy( collectionIds = emptyList(), ), + hasOrganizations = true, ), type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes, isIndividualVaultDisabled = false, @@ -4258,6 +4259,75 @@ class VaultAddEditScreenTest : BitwardenComposeTest() { } } + @Test + fun `Move to organization option menu should not be visible if user has no organizations`() { + mutableStateFlow.update { + it.copy( + vaultAddEditType = VaultAddEditType.EditItem(vaultItemId = "mockId-1"), + viewState = VaultAddEditState.ViewState.Content( + common = VaultAddEditState.ViewState.Content.Common( + originalCipher = createMockCipherView(1).copy( + collectionIds = emptyList(), + ), + hasOrganizations = false, + ), + type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes, + isIndividualVaultDisabled = false, + ), + ) + } + + // Confirm dropdown version of item is absent + composeTestRule + .onAllNodesWithText("Move to Organization") + .filter(hasAnyAncestor(isPopup())) + .assertCountEquals(0) + // Open the overflow menu + composeTestRule + .onNodeWithContentDescription("More") + .performClick() + + // Confirm it does not exist + composeTestRule + .onAllNodesWithText("Move to Organization") + .filterToOne(hasAnyAncestor(isPopup())) + .assertIsNotDisplayed() + } + + @Test + fun `Move to organization option menu should be visible if user has organizations`() { + mutableStateFlow.update { + it.copy( + vaultAddEditType = VaultAddEditType.EditItem(vaultItemId = "mockId-1"), + viewState = VaultAddEditState.ViewState.Content( + common = VaultAddEditState.ViewState.Content.Common( + originalCipher = createMockCipherView(1).copy( + collectionIds = emptyList(), + ), + hasOrganizations = true, + ), + type = VaultAddEditState.ViewState.Content.ItemType.SecureNotes, + isIndividualVaultDisabled = false, + ), + ) + } + + // Confirm dropdown version of item is absent + composeTestRule + .onAllNodesWithText("Move to Organization") + .filter(hasAnyAncestor(isPopup())) + .assertCountEquals(0) + + composeTestRule + .onNodeWithContentDescription("More") + .performClick() + + composeTestRule + .onAllNodesWithText("Move to Organization") + .filterToOne(hasAnyAncestor(isPopup())) + .assertIsDisplayed() + } + //endregion Helper functions companion object { diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemScreenTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemScreenTest.kt index da77ac8203..5b1b1741a9 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemScreenTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemScreenTest.kt @@ -1352,6 +1352,12 @@ class VaultItemScreenTest : BitwardenComposeTest() { @Test fun `Move to organization option menu click should send MoveToOrganizationClick action`() { + mutableStateFlow.update { + DEFAULT_STATE.copy( + viewState = DEFAULT_LOGIN_VIEW_STATE, + ) + } + // Confirm dropdown version of item is absent composeTestRule .onAllNodesWithText("Move to Organization") @@ -1369,6 +1375,30 @@ class VaultItemScreenTest : BitwardenComposeTest() { } } + @Test + fun `Move to organization option menu should not be visible if user has no organizations`() { + mutableStateFlow.update { + DEFAULT_STATE.copy( + viewState = DEFAULT_LOGIN_VIEW_STATE.copy( + common = DEFAULT_COMMON.copy(hasOrganizations = false), + ), + ) + } + + // Confirm dropdown version of item is absent + composeTestRule + .onAllNodesWithText("Move to Organization") + .filter(hasAnyAncestor(isPopup())) + .assertCountEquals(0) + // Open the overflow menu + composeTestRule.onNodeWithContentDescription("More").performClick() + // Confirm it does not exist + composeTestRule + .onAllNodesWithText("Move to Organization") + .filterToOne(hasAnyAncestor(isPopup())) + .assertDoesNotExist() + } + @Test fun `menu Collection option should be displayed based on state`() { mutableStateFlow.update { @@ -3195,6 +3225,7 @@ private val DEFAULT_COMMON: VaultItemState.ViewState.Content.Common = passwordHistoryCount = null, iconData = IconData.Local(iconRes = BitwardenDrawable.ic_globe), relatedLocations = persistentListOf(), + hasOrganizations = true, ) private val DEFAULT_PASSKEY = BitwardenString.created_x.asText("Mar 13, 2024, 3:56 PM") @@ -3280,6 +3311,7 @@ private val EMPTY_COMMON: VaultItemState.ViewState.Content.Common = passwordHistoryCount = null, iconData = IconData.Local(iconRes = BitwardenDrawable.ic_globe), relatedLocations = persistentListOf(), + hasOrganizations = true, ) private val EMPTY_LOGIN_TYPE: VaultItemState.ViewState.Content.ItemType.Login = diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt index a29305dc57..76cadc87a7 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/VaultItemViewModelTest.kt @@ -236,6 +236,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns DEFAULT_VIEW_STATE @@ -278,6 +279,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns loginState @@ -313,6 +315,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns DEFAULT_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -361,6 +364,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns DEFAULT_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -414,6 +418,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns loginViewState mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -465,6 +470,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns viewState mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -508,6 +514,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns DEFAULT_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -556,6 +563,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns DEFAULT_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -601,6 +609,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns loginViewState mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -624,6 +633,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } assertEquals( @@ -664,6 +674,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns createViewState() every { clipboardManager.setText(text = field) } just runs @@ -688,6 +699,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) organizationEventManager.trackEvent( event = OrganizationEvent.CipherClientCopiedHiddenField( @@ -741,6 +753,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns loginViewState mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -778,6 +791,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) organizationEventManager.trackEvent( event = OrganizationEvent.CipherClientToggledHiddenFieldVisible( @@ -802,6 +816,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns DEFAULT_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -840,6 +855,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns loginViewState mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -873,6 +889,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } } @@ -892,6 +909,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns DEFAULT_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -929,6 +947,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns DEFAULT_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -976,6 +995,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns loginViewState mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1046,6 +1066,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns loginViewState mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1218,6 +1239,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns DEFAULT_VIEW_STATE @@ -1264,6 +1286,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns DEFAULT_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1313,6 +1336,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } coVerify(exactly = 1) { @@ -1334,6 +1358,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns createViewState() mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1360,6 +1385,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } } @@ -1416,6 +1442,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns createViewState() mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1442,6 +1469,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } } @@ -1484,6 +1512,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns createViewState() mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1511,6 +1540,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } } @@ -1531,6 +1561,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns loginViewState mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1567,6 +1598,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) organizationEventManager.trackEvent( event = OrganizationEvent.CipherClientToggledPasswordVisible( @@ -1604,6 +1636,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns createViewState(type = DEFAULT_CARD_TYPE) mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1629,6 +1662,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } } @@ -1649,6 +1683,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns createViewState(type = DEFAULT_CARD_TYPE) mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1677,6 +1712,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } } @@ -1695,6 +1731,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns createViewState(type = DEFAULT_CARD_TYPE) mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1720,6 +1757,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } } @@ -1739,6 +1777,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns createViewState(type = DEFAULT_CARD_TYPE) mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1767,6 +1806,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } } @@ -1799,6 +1839,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns SSH_KEY_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1832,6 +1873,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns sshKeyViewState mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1865,6 +1907,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } } @@ -1883,6 +1926,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns createViewState(type = DEFAULT_SSH_KEY_TYPE) mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1914,6 +1958,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns SSH_KEY_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -1955,6 +2000,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns IDENTITY_VIEW_STATE mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView) @@ -2114,6 +2160,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { VaultItemLocation.Collection("mockName-1"), VaultItemLocation.Folder("mockName-1"), ), + hasOrganizations = true, ) } returns viewState mutableUserStateFlow.value = DEFAULT_USER_STATE.copy( @@ -2176,6 +2223,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { VaultItemLocation.Collection("mockName-1"), VaultItemLocation.Folder("mockName-1"), ), + hasOrganizations = true, ) } returns viewState mutableUserStateFlow.value = DEFAULT_USER_STATE.copy( @@ -2237,6 +2285,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { VaultItemLocation.Collection("mockName-1"), VaultItemLocation.Folder("mockName-1"), ), + hasOrganizations = true, ) } returns viewState mutableUserStateFlow.value = DEFAULT_USER_STATE.copy( @@ -2306,6 +2355,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns viewState val viewModel = createViewModel(state = null) @@ -2351,6 +2401,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns viewState val viewModel = createViewModel(state = null) @@ -2391,6 +2442,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { baseIconUrl = Environment.Us.environmentUrlData.baseIconUrl, isIconLoadingDisabled = false, relatedLocations = persistentListOf(), + hasOrganizations = true, ) } returns viewState val viewModel = createViewModel(state = null) @@ -2511,7 +2563,17 @@ class VaultItemViewModelTest : BaseViewModelTest() { isVaultUnlocked = true, needsPasswordReset = false, isBiometricsEnabled = false, - organizations = emptyList(), + organizations = listOf( + Organization( + id = "organiationId", + name = "Test Organization", + shouldManageResetPassword = false, + shouldUseKeyConnector = false, + role = OrganizationType.USER, + keyConnectorUrl = null, + userIsClaimedByOrganization = false, + ), + ), needsMasterPassword = false, trustedDevice = null, hasMasterPassword = true, @@ -2649,6 +2711,7 @@ class VaultItemViewModelTest : BaseViewModelTest() { passwordHistoryCount = 1, iconData = IconData.Local(BitwardenDrawable.ic_globe), relatedLocations = persistentListOf(), + hasOrganizations = true, ) private val DEFAULT_VIEW_STATE: VaultItemState.ViewState.Content = diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensionsTest.kt index 7c535c9395..361038945c 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/CipherViewExtensionsTest.kt @@ -57,6 +57,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( @@ -90,6 +91,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( @@ -129,6 +131,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( @@ -159,6 +162,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( @@ -187,6 +191,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( @@ -218,6 +223,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( @@ -259,6 +265,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( @@ -305,6 +312,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( @@ -353,6 +361,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( @@ -385,6 +394,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) val expectedState = VaultItemState.ViewState.Content( @@ -415,6 +425,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( VaultItemState.ViewState.Content( @@ -462,6 +473,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( it.value, @@ -489,6 +501,7 @@ class CipherViewExtensionsTest { baseIconUrl = "https://example.com/", isIconLoadingDisabled = true, relatedLocations = persistentListOf(), + hasOrganizations = true, ) assertEquals( IconData.Local(it.value), diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/VaultItemTestUtil.kt b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/VaultItemTestUtil.kt index 58bcf18eef..f8b4369979 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/VaultItemTestUtil.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/ui/vault/feature/item/util/VaultItemTestUtil.kt @@ -185,6 +185,7 @@ fun createCommonContent( passwordHistoryCount = null, relatedLocations = persistentListOf(), iconData = IconData.Local(iconResId), + hasOrganizations = true, ) } else { VaultItemState.ViewState.Content.Common( @@ -248,6 +249,7 @@ fun createCommonContent( passwordHistoryCount = 1, relatedLocations = persistentListOf(), iconData = IconData.Local(iconResId), + hasOrganizations = true, ) }