-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[SAML Configuration] Verify Domain flow #73016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
mountiny
merged 46 commits into
Expensify:main
from
software-mansion-labs:feat/domain-validation
Nov 6, 2025
Merged
Changes from all commits
Commits
Show all changes
46 commits
Select commit
Hold shift + click to select a range
7f2cc8a
Create domain validation pages
mhawryluk 92832de
Merge branch 'feat/saml-display-domain-list' into feat/domain-validation
mhawryluk 6f14e73
Merge branch 'main' into feat/domain-validation
mhawryluk 4ce735b
Extend navigation, actions and loading states
mhawryluk 47c3a3c
Add link and error message to Verify Domain RHP
mhawryluk 7188e71
Display error from BE in Verify Domain page
mhawryluk 3ece949
Fix RHP refresh behavior
mhawryluk 3c1cc9c
Display verification badge only to admins
mhawryluk b9ed09a
Support offline status in Verify Domain RHP
mhawryluk 3f8cf0e
Normalize workspaces path in getMatchingFullScreenRoute
mhawryluk d99e562
Fix spell check
mhawryluk 45f4a4d
Use FormAlertWithSubmitButton in VerifyDomainPage
mhawryluk d98f0de
Fixes and refactors to the verify domain flow
mhawryluk a2aa3d0
Rename the new modal stack navigator
mhawryluk ae0b941
Change validation code loading UI + add error state
mhawryluk a932956
Adjust domain validate code loading and error state UI
mhawryluk ee45ed8
Remove unnecessary (for now) translation key
mhawryluk ae41ec6
Fix backend integration in the verify domain flow
mhawryluk e1fa943
Review fixes and translations
mhawryluk 9bd80f6
Improve spanish translations
mhawryluk fe3b4b6
Update jsdoc
mhawryluk 3623d08
Disable retry button when user is offline
mhawryluk e1648fd
Move status string literals to constant
mhawryluk 14801f8
Change Domain error status handling
mhawryluk fc1b7f7
Show dot indicator conditionally
mhawryluk 23e7e50
FIx word overflow bug in VerifyDomain page on mobile
mhawryluk fc7aa0a
Add bottom padding to DomainVerifiedPage
mhawryluk e5e76d1
Merge branch 'main' into feat/domain-validation
mhawryluk d4a2fd0
Merge branch 'main' into feat/domain-validation
mhawryluk 8e3ad31
Improve DomainsListRow styling
mhawryluk eaa6c9b
Tiny fix
mhawryluk aed85ad
Remove unnecessary optional chaining
mhawryluk 9b72d87
Review fixes
mhawryluk a6c396c
Show validateCode error directly from onyx
mhawryluk ec90ad0
Merge branch 'main' into feat/domain-validation
mhawryluk d3677b4
Align workspaces and domain row icons
mhawryluk 92a7c6a
Implement AI review suggestions
mhawryluk 88eaae0
Show NotFoundPage for not found domains + fix verified page padding
mhawryluk 2de1e2d
Fix verified page description on mobile and safe area bottom padding
mhawryluk 6465449
Reset domainValidationError when entering the verify page
mhawryluk 679c07a
Fix resetting error for non-existing domains
mhawryluk 3835b07
More review fixes
mhawryluk 857953e
Show full screen spinner instead of not-found when onyx domain data i…
mhawryluk 1165888
Merge branch 'main' into feat/domain-validation
mhawryluk b5b1440
Change onLinkPress for not found page
mhawryluk 03f935e
Remove unnecessary whitespace
mhawryluk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import React from 'react'; | ||
| import {View} from 'react-native'; | ||
| import ActivityIndicator from '@components/ActivityIndicator'; | ||
| import CopyTextToClipboard from '@components/CopyTextToClipboard'; | ||
| import Text from '@components/Text'; | ||
| import useTheme from '@hooks/useTheme'; | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
|
|
||
| type CopyableTextFieldProps = { | ||
| /** Text to display and to copy */ | ||
| value?: string; | ||
|
|
||
| /** Should an activity indicator be shown instead of the text and button */ | ||
| isLoading?: boolean; | ||
| }; | ||
|
|
||
| function CopyableTextField({value, isLoading = false}: CopyableTextFieldProps) { | ||
| const styles = useThemeStyles(); | ||
| const theme = useTheme(); | ||
| return ( | ||
| <View style={[styles.qbdSetupLinkBox, styles.border, styles.flexRow, styles.gap2, styles.justifyContentCenter, styles.alignItemsCenter]}> | ||
| {isLoading ? ( | ||
| <ActivityIndicator color={theme.text} /> | ||
| ) : ( | ||
| <> | ||
| <Text style={styles.copyableTextField}>{value ?? ''}</Text> | ||
| <View style={[styles.reportActionContextMenuMiniButton, styles.overflowHidden, styles.buttonHoveredBG]}> | ||
| <CopyTextToClipboard urlToCopy={value ?? ''} /> | ||
| </View> | ||
| </> | ||
| )} | ||
| </View> | ||
| ); | ||
| } | ||
mountiny marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| CopyableTextField.displayName = 'CopyableTextField'; | ||
| export default CopyableTextField; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| import React from 'react'; | ||
| import * as Expensicons from '@components/Icon/Expensicons'; | ||
| import type {OfflineWithFeedbackProps} from '@components/OfflineWithFeedback'; | ||
| import OfflineWithFeedback from '@components/OfflineWithFeedback'; | ||
| import type {PopoverMenuItem} from '@components/PopoverMenu'; | ||
| import {PressableWithoutFeedback} from '@components/Pressable'; | ||
| import useLocalize from '@hooks/useLocalize'; | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
| import Navigation from '@libs/Navigation/Navigation'; | ||
| import CONST from '@src/CONST'; | ||
| import ROUTES from '@src/ROUTES'; | ||
| import DomainsListRow from './DomainsListRow'; | ||
|
|
||
| type DomainMenuItemProps = { | ||
| /** Domain menu item data */ | ||
| item: DomainItem; | ||
|
|
||
| /** Row index in the menu */ | ||
| index: number; | ||
| }; | ||
|
|
||
| type DomainItem = { | ||
| /** Type of menu item row in the list of workspaces and domains */ | ||
| listItemType: 'domain'; | ||
mountiny marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /** Main text to show in the row */ | ||
| title: string; | ||
|
|
||
| /** Function to run after clicking on the row */ | ||
| action: () => void; | ||
|
|
||
| /** ID of the row's domain */ | ||
| accountID: number; | ||
|
|
||
| /** Whether the user is an admin of the row's domain */ | ||
| isAdmin: boolean; | ||
|
|
||
| /** Whether the row's domain is validated (aka verified) */ | ||
| isValidated: boolean; | ||
| } & Pick<OfflineWithFeedbackProps, 'pendingAction'>; | ||
|
|
||
mountiny marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| function DomainMenuItem({item, index}: DomainMenuItemProps) { | ||
| const styles = useThemeStyles(); | ||
| const {translate} = useLocalize(); | ||
| const {isAdmin, isValidated} = item; | ||
|
|
||
| const threeDotsMenuItems: PopoverMenuItem[] | undefined = | ||
| !isValidated && isAdmin | ||
| ? [ | ||
| { | ||
| icon: Expensicons.Globe, | ||
| text: translate('domain.verifyDomain.title'), | ||
| onSelected: () => Navigation.navigate(ROUTES.WORKSPACES_VERIFY_DOMAIN.getRoute(item.accountID)), | ||
| }, | ||
| ] | ||
| : undefined; | ||
|
|
||
| return ( | ||
| <OfflineWithFeedback | ||
| key={`domain_${item.title}_${index}`} | ||
| pendingAction={item.pendingAction} | ||
| style={styles.mb2} | ||
| > | ||
| <PressableWithoutFeedback | ||
| role={CONST.ROLE.BUTTON} | ||
| accessibilityLabel="row" | ||
| style={styles.mh5} | ||
| onPress={item.action} | ||
| disabled={!isAdmin} | ||
| > | ||
| {({hovered}) => ( | ||
| <DomainsListRow | ||
| title={item.title} | ||
| badgeText={isAdmin && !isValidated ? translate('domain.notVerified') : undefined} | ||
| isHovered={hovered} | ||
| menuItems={threeDotsMenuItems} | ||
| /> | ||
| )} | ||
| </PressableWithoutFeedback> | ||
| </OfflineWithFeedback> | ||
| ); | ||
| } | ||
|
|
||
| DomainMenuItem.displayName = 'DomainMenuItem'; | ||
|
|
||
| export type {DomainItem}; | ||
| export default DomainMenuItem; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import React from 'react'; | ||
| import useLocalize from '@hooks/useLocalize'; | ||
| import usePreferredPolicy from '@hooks/usePreferredPolicy'; | ||
| import useStyleUtils from '@hooks/useStyleUtils'; | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
| import interceptAnonymousUser from '@libs/interceptAnonymousUser'; | ||
| import Navigation from '@libs/Navigation/Navigation'; | ||
| import colors from '@styles/theme/colors'; | ||
| import variables from '@styles/variables'; | ||
| import CONST from '@src/CONST'; | ||
| import ROUTES from '@src/ROUTES'; | ||
| import EmptyStateComponent from './EmptyStateComponent'; | ||
| import LottieAnimations from './LottieAnimations'; | ||
| import WorkspaceRowSkeleton from './Skeletons/WorkspaceRowSkeleton'; | ||
|
|
||
| function WorkspacesEmptyStateComponent() { | ||
| const styles = useThemeStyles(); | ||
| const {translate} = useLocalize(); | ||
| const StyleUtils = useStyleUtils(); | ||
| const {isRestrictedPolicyCreation} = usePreferredPolicy(); | ||
|
|
||
| return ( | ||
| <EmptyStateComponent | ||
| SkeletonComponent={WorkspaceRowSkeleton} | ||
| headerMediaType={CONST.EMPTY_STATE_MEDIA.ANIMATION} | ||
| headerMedia={LottieAnimations.WorkspacePlanet} | ||
| title={translate('workspace.emptyWorkspace.title')} | ||
| subtitle={translate('workspace.emptyWorkspace.subtitle')} | ||
| titleStyles={styles.pt2} | ||
| headerStyles={[styles.overflowHidden, StyleUtils.getBackgroundColorStyle(colors.pink800), StyleUtils.getHeight(variables.sectionIllustrationHeight)]} | ||
| lottieWebViewStyles={styles.emptyWorkspaceListIllustrationStyle} | ||
| headerContentStyles={styles.emptyWorkspaceListIllustrationStyle} | ||
| buttons={ | ||
| isRestrictedPolicyCreation | ||
| ? [] | ||
| : [ | ||
| { | ||
| success: true, | ||
| buttonAction: () => interceptAnonymousUser(() => Navigation.navigate(ROUTES.WORKSPACE_CONFIRMATION.getRoute(ROUTES.WORKSPACES_LIST.route))), | ||
| buttonText: translate('workspace.new.newWorkspace'), | ||
| }, | ||
| ] | ||
| } | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| WorkspacesEmptyStateComponent.displayName = 'WorkspacesEmptyStateComponent'; | ||
| export default WorkspacesEmptyStateComponent; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mhawryluk marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.