From 49dfe7f2123dc4d8a054ad121afb2605b04ce1c3 Mon Sep 17 00:00:00 2001 From: shahid <105579118+Shahidullah-Muffakir@users.noreply.github.com> Date: Tue, 20 Aug 2024 17:40:32 +0000 Subject: [PATCH 01/77] Fix issue with splitting distance in quick actions by ensuring distance and amount are calculated before splitting. Signed-off-by: GitHub --- .../sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx index b221a5d5be9d..9d00b9330525 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx @@ -262,7 +262,7 @@ function FloatingActionButtonAndPopover( selectOption(() => IOU.startMoneyRequest(CONST.IOU.TYPE.SPLIT, quickActionReportID, CONST.IOU.REQUEST_TYPE.SCAN, true), true); return; case CONST.QUICK_ACTIONS.SPLIT_DISTANCE: - selectOption(() => IOU.startMoneyRequest(CONST.IOU.TYPE.SPLIT, quickActionReportID, CONST.IOU.REQUEST_TYPE.DISTANCE, true), true); + selectOption(() => IOU.startMoneyRequest(CONST.IOU.TYPE.SPLIT, quickActionReportID, CONST.IOU.REQUEST_TYPE.DISTANCE, false), true); return; case CONST.QUICK_ACTIONS.SEND_MONEY: selectOption(() => IOU.startMoneyRequest(CONST.IOU.TYPE.PAY, quickActionReportID, CONST.IOU.REQUEST_TYPE.MANUAL, true), false); From c4f7afb64783f9a9c22d3e67fda7d12d4c5374df Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Thu, 22 Aug 2024 07:22:24 -0700 Subject: [PATCH 02/77] WIP pass customUnitRateID for track distance --- src/libs/actions/IOU.ts | 1 + .../request/step/IOURequestStepConfirmation.tsx | 15 ++++++++++++++- .../iou/request/step/IOURequestStepDistance.tsx | 7 +++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index bbb6e3c48fcd..750d0b875e99 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3639,6 +3639,7 @@ function trackExpense( actionableWhisperReportActionID?: string, linkedTrackedExpenseReportAction?: OnyxTypes.ReportAction, linkedTrackedExpenseReportID?: string, + customUnitRateID = '', ) { const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); const currentChatReport = isMoneyRequestReport ? ReportUtils.getReportOrDraftReport(report.chatReportID) : report; diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index b33ce6f56600..601117ebdfc0 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -300,9 +300,22 @@ function IOURequestStepConfirmation({ transaction.actionableWhisperReportActionID, transaction.linkedTrackedExpenseReportAction, transaction.linkedTrackedExpenseReportID, + customUnitRateID, ); }, - [report, transaction, currentUserPersonalDetails.login, currentUserPersonalDetails.accountID, transactionTaxCode, transactionTaxAmount, policy, policyTags, policyCategories, action], + [ + report, + transaction, + currentUserPersonalDetails.login, + currentUserPersonalDetails.accountID, + transactionTaxCode, + transactionTaxAmount, + policy, + policyTags, + policyCategories, + action, + customUnitRateID, + ], ); const createDistanceRequest = useCallback( diff --git a/src/pages/iou/request/step/IOURequestStepDistance.tsx b/src/pages/iou/request/step/IOURequestStepDistance.tsx index 1798a95490a7..dbc2ca374e06 100644 --- a/src/pages/iou/request/step/IOURequestStepDistance.tsx +++ b/src/pages/iou/request/step/IOURequestStepDistance.tsx @@ -121,6 +121,7 @@ function IOURequestStepDistance({ const isCreatingNewRequest = !(backTo || isEditing); const [recentWaypoints, {status: recentWaypointsStatus}] = useOnyx(ONYXKEYS.NVP_RECENT_WAYPOINTS); const iouRequestType = TransactionUtils.getRequestType(transaction); + const customUnitRateID = TransactionUtils.getRateID(transaction); // For quick button actions, we'll skip the confirmation page unless the report is archived or this is a workspace // request and the workspace requires a category or a tag @@ -303,6 +304,11 @@ function IOURequestStepDistance({ undefined, undefined, TransactionUtils.getValidWaypoints(waypoints, true), + undefined, + undefined, + undefined, + undefined, + customUnitRateID, ); return; } @@ -356,6 +362,7 @@ function IOURequestStepDistance({ policy, iouRequestType, reportNameValuePairs, + customUnitRateID, ]); const getError = () => { From b8fc6853f8ade5608985116a7419928989112a7d Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Thu, 22 Aug 2024 07:30:37 -0700 Subject: [PATCH 03/77] Pass customUnitRateID straight to API --- src/libs/API/parameters/TrackExpenseParams.ts | 1 + src/libs/actions/IOU.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libs/API/parameters/TrackExpenseParams.ts b/src/libs/API/parameters/TrackExpenseParams.ts index d5e1de2e625b..3a7d0df6736c 100644 --- a/src/libs/API/parameters/TrackExpenseParams.ts +++ b/src/libs/API/parameters/TrackExpenseParams.ts @@ -27,6 +27,7 @@ type TrackExpenseParams = { createdReportActionIDForThread: string; waypoints?: string; actionableWhisperReportActionID?: string; + customUnitRateID?: string; }; export default TrackExpenseParams; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 750d0b875e99..4fdd8c4dc214 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3779,6 +3779,7 @@ function trackExpense( transactionThreadReportID: transactionThreadReportID ?? '-1', createdReportActionIDForThread: createdReportActionIDForThread ?? '-1', waypoints: validWaypoints ? JSON.stringify(validWaypoints) : undefined, + customUnitRateID, }; if (actionableWhisperReportActionIDParam) { parameters.actionableWhisperReportActionID = actionableWhisperReportActionIDParam; From 5201a6ce47424b9485d72b9d6afb1e8b87b66e91 Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Thu, 22 Aug 2024 07:35:09 -0700 Subject: [PATCH 04/77] Default to undefined to match other params --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 4fdd8c4dc214..d934b93938fb 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -3639,7 +3639,7 @@ function trackExpense( actionableWhisperReportActionID?: string, linkedTrackedExpenseReportAction?: OnyxTypes.ReportAction, linkedTrackedExpenseReportID?: string, - customUnitRateID = '', + customUnitRateID?: string, ) { const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); const currentChatReport = isMoneyRequestReport ? ReportUtils.getReportOrDraftReport(report.chatReportID) : report; From 5059985df6b6061b8317e761ae7cd2da7522e326 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Fri, 23 Aug 2024 23:45:05 +0300 Subject: [PATCH 05/77] fix room mention in edit message --- src/pages/home/report/ReportActionItem.tsx | 1 + src/pages/home/report/ReportActionItemMessageEdit.tsx | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index e4dab8518eb2..bc875ccda703 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -722,6 +722,7 @@ function ReportActionItem({ action={action} draftMessage={draftMessage} reportID={report.reportID} + policyID={report.policyID} index={index} ref={textInputRef} shouldDisableEmojiPicker={ diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 15b901689ddc..73bea7060b36 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -61,6 +61,9 @@ type ReportActionItemMessageEditProps = { /** ReportID that holds the comment we're editing */ reportID: string; + /** PolicyID of the policy the report belongs to */ + policyID?: string; + /** Position index of the report action in the overall report FlatList view */ index: number; @@ -68,7 +71,7 @@ type ReportActionItemMessageEditProps = { shouldDisableEmojiPicker?: boolean; /** Whether report is from group policy */ - isGroupPolicyReport?: boolean; + isGroupPolicyReport: boolean; }; // native ids @@ -81,7 +84,7 @@ const shouldUseForcedSelectionRange = shouldUseEmojiPickerSelection(); const draftMessageVideoAttributeCache = new Map(); function ReportActionItemMessageEdit( - {action, draftMessage, reportID, index, isGroupPolicyReport, shouldDisableEmojiPicker = false}: ReportActionItemMessageEditProps, + {action, draftMessage, reportID, policyID, index, isGroupPolicyReport, shouldDisableEmojiPicker = false}: ReportActionItemMessageEditProps, forwardedRef: ForwardedRef, ) { const [preferredSkinTone] = useOnyx(ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE, {initialValue: CONST.EMOJI_DEFAULT_SKIN_TONE}); @@ -532,7 +535,8 @@ function ReportActionItemMessageEdit( isComposerFocused={textInputRef.current?.isFocused()} updateComment={updateDraft} measureParentContainerAndReportCursor={measureParentContainerAndReportCursor} - isGroupPolicyReport={false} + isGroupPolicyReport={isGroupPolicyReport} + policyID={policyID} value={draft} selection={selection} setSelection={setSelection} From e9275e99d036eeca710ef10dc2f716bafd78ae7c Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Tue, 27 Aug 2024 11:59:59 +0200 Subject: [PATCH 06/77] add is filter page --- src/CONST.ts | 6 ++ src/ROUTES.ts | 1 + src/SCREENS.ts | 1 + src/languages/en.ts | 3 + src/languages/es.ts | 3 + .../ModalStackNavigators/index.tsx | 1 + src/libs/Navigation/linkingConfig/config.ts | 1 + src/libs/PolicyUtils.ts | 2 +- src/libs/SearchUtils.ts | 11 ++++ src/pages/Search/AdvancedSearchFilters.tsx | 15 +++++ .../SearchFiltersExpenseTypePage.tsx | 2 +- .../SearchFiltersIsPage.tsx | 66 +++++++++++++++++++ .../SearchFiltersTaxRatePage.tsx | 2 +- src/types/form/SearchAdvancedFiltersForm.ts | 4 ++ 14 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersIsPage.tsx diff --git a/src/CONST.ts b/src/CONST.ts index 7b5320e7c6ef..4a7465b99d10 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -5206,6 +5206,7 @@ const CONST = { EXPENSE: 'expense', INVOICE: 'invoice', TRIP: 'trip', + CHAT: 'chat', }, ACTION_TYPES: { VIEW: 'view', @@ -5213,6 +5214,10 @@ const CONST = { DONE: 'done', PAID: 'paid', }, + CHAT_STATUS: { + UNREAD: 'unread', + PINNED: 'pinned', + }, BULK_ACTION_TYPES: { EXPORT: 'export', HOLD: 'hold', @@ -5301,6 +5306,7 @@ const CONST = { CARD_ID: 'cardID', REPORT_ID: 'reportID', KEYWORD: 'keyword', + IS: 'is', }, }, diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 47a2ad76209e..38566794f29d 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -53,6 +53,7 @@ const ROUTES = { SEARCH_ADVANCED_FILTERS_TAG: 'search/filters/tag', SEARCH_ADVANCED_FILTERS_FROM: 'search/filters/from', SEARCH_ADVANCED_FILTERS_TO: 'search/filters/to', + SEARCH_ADVANCED_FILTERS_IS: 'search/filters/is', SEARCH_REPORT: { route: 'search/view/:reportID', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 686a752ad360..b197d79d9f8b 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -46,6 +46,7 @@ const SCREENS = { ADVANCED_FILTERS_TAG_RHP: 'Search_Advanced_Filters_Tag_RHP', ADVANCED_FILTERS_FROM_RHP: 'Search_Advanced_Filters_From_RHP', ADVANCED_FILTERS_TO_RHP: 'Search_Advanced_Filters_To_RHP', + ADVANCED_FILTERS_IS_RHP: 'Search_Advanced_Filters_Is_RHP', TRANSACTION_HOLD_REASON_RHP: 'Search_Transaction_Hold_Reason_RHP', BOTTOM_TAB: 'Search_Bottom_Tab', }, diff --git a/src/languages/en.ts b/src/languages/en.ts index 632da6f9c3ae..f2cd34833fd9 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3764,6 +3764,9 @@ export default { keyword: 'Keyword', hasKeywords: 'Has keywords', currency: 'Currency', + is: 'Is', + pinned: 'Pinned', + unread: 'Unread', amount: { lessThan: (amount?: string) => `Less than ${amount ?? ''}`, greaterThan: (amount?: string) => `Greater than ${amount ?? ''}`, diff --git a/src/languages/es.ts b/src/languages/es.ts index 77ba5e5abf45..138910db6009 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3814,6 +3814,9 @@ export default { keyword: 'Palabra clave', hasKeywords: 'Tiene palabras clave', currency: 'Divisa', + is: 'EstΓ‘', + pinned: 'Fijado', + unread: 'No leΓ­do', amount: { lessThan: (amount?: string) => `Menos de ${amount ?? ''}`, greaterThan: (amount?: string) => `MΓ‘s que ${amount ?? ''}`, diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 7722696245fd..b3db664bb487 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -528,6 +528,7 @@ const SearchAdvancedFiltersModalStackNavigator = createModalStackNavigator require('../../../../pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage').default, [SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP]: () => require('@pages/Search/SearchAdvancedFiltersPage/SearchFiltersFromPage').default, [SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP]: () => require('@pages/Search/SearchAdvancedFiltersPage/SearchFiltersToPage').default, + [SCREENS.SEARCH.ADVANCED_FILTERS_IS_RHP]: () => require('@pages/Search/SearchAdvancedFiltersPage/SearchFiltersIsPage').default, }); const RestrictedActionModalStackNavigator = createModalStackNavigator({ diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 4d3f19984b8f..2ac5940f46e4 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1038,6 +1038,7 @@ const config: LinkingOptions['config'] = { [SCREENS.SEARCH.ADVANCED_FILTERS_TAG_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_TAG, [SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_FROM, [SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_TO, + [SCREENS.SEARCH.ADVANCED_FILTERS_IS_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_IS, }, }, [SCREENS.RIGHT_MODAL.RESTRICTED_ACTION]: { diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 3f3a2a96a1e1..a03b01f512e3 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -300,7 +300,7 @@ function getTagNamesFromTagsLists(policyTagLists: PolicyTagLists): string[] { const uniqueTagNames = new Set(); for (const policyTagList of Object.values(policyTagLists ?? {})) { - for (const tag of Object.values(policyTagList.tags)) { + for (const tag of Object.values(policyTagList.tags ?? {})) { uniqueTagNames.add(getCleanedTagName(tag.name)); } } diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index ce2429c5653b..8c76866eed87 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -482,6 +482,16 @@ function getExpenseTypeTranslationKey(expenseType: ValueOf): TranslationPaths { + // eslint-disable-next-line default-case + switch (chatStatus) { + case CONST.SEARCH.CHAT_STATUS.PINNED: + return 'search.filters.pinned'; + case CONST.SEARCH.CHAT_STATUS.UNREAD: + return 'search.filters.unread'; + } +} + /** * Given object with chosen search filters builds correct query string from them */ @@ -613,4 +623,5 @@ export { normalizeQuery, shouldShowYear, getExpenseTypeTranslationKey, + getChatStatusTranslationKey, }; diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 4b859e37785e..b2cbf144b42f 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -125,6 +125,16 @@ function getExpenseTypeDisplayTitle(filters: Partial, : undefined; } +function getChatIsDisplayTitle(filters: Partial, translate: LocaleContextProps['translate']) { + const filterValue = filters[CONST.SEARCH.SYNTAX_FILTER_KEYS.IS]; + return filterValue + ? Object.values(CONST.SEARCH.CHAT_STATUS) + .filter((chatStatus) => filterValue.includes(chatStatus)) + .map((chatStatus) => translate(SearchUtils.getChatStatusTranslationKey(chatStatus))) + .join(', ') + : undefined; +} + function AdvancedSearchFilters() { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -209,6 +219,11 @@ function AdvancedSearchFilters() { description: 'common.to' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_TO, }, + { + title: getChatIsDisplayTitle(searchAdvancedFilters, translate), + description: 'search.filters.is' as const, + route: ROUTES.SEARCH_ADVANCED_FILTERS_IS, + }, ], [searchAdvancedFilters, translate, cardList, taxRates, personalDetails], ); diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersExpenseTypePage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersExpenseTypePage.tsx index 96984029142b..9cbb7b7743fe 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersExpenseTypePage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersExpenseTypePage.tsx @@ -61,6 +61,6 @@ function SearchFiltersExpenseTypePage() { ); } -SearchFiltersExpenseTypePage.displayName = 'SearchFiltersCategoryPage'; +SearchFiltersExpenseTypePage.displayName = 'SearchFiltersExpenseTypePage'; export default SearchFiltersExpenseTypePage; diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersIsPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersIsPage.tsx new file mode 100644 index 000000000000..d2431776eb44 --- /dev/null +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersIsPage.tsx @@ -0,0 +1,66 @@ +import React, {useCallback, useMemo} from 'react'; +import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import type {ValueOf} from 'type-fest'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SearchMultipleSelectionPicker from '@components/Search/SearchMultipleSelectionPicker'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import {getChatStatusTranslationKey} from '@libs/SearchUtils'; +import * as SearchActions from '@userActions/Search'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; + +function SearchFiltersIsPage() { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); + const selectedChatStatuses = searchAdvancedFiltersForm?.is?.map((chatStatus) => { + const chatStatusName = translate(getChatStatusTranslationKey(chatStatus as ValueOf)); + return {name: chatStatusName, value: chatStatus}; + }); + const allChatStatuses = Object.values(CONST.SEARCH.CHAT_STATUS); + + const chatStatusItems = useMemo(() => { + return allChatStatuses.map((chatStatus) => { + const chatStatusName = translate(getChatStatusTranslationKey(chatStatus)); + return {name: chatStatusName, value: chatStatus}; + }); + }, [allChatStatuses, translate]); + + const updateChatIsFilter = useCallback((values: string[]) => SearchActions.updateAdvancedFilters({is: values}), []); + + return ( + + { + Navigation.goBack(ROUTES.SEARCH_ADVANCED_FILTERS); + }} + /> + + + + + ); +} + +SearchFiltersIsPage.displayName = 'SearchFiltersIsPage'; + +export default SearchFiltersIsPage; diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTaxRatePage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTaxRatePage.tsx index 713e9f5110b2..a1ad32db6308 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTaxRatePage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTaxRatePage.tsx @@ -67,6 +67,6 @@ function SearchFiltersTaxRatePage() { ); } -SearchFiltersTaxRatePage.displayName = 'SearchFiltersCategoryPage'; +SearchFiltersTaxRatePage.displayName = 'SearchFiltersTaxRatePage'; export default SearchFiltersTaxRatePage; diff --git a/src/types/form/SearchAdvancedFiltersForm.ts b/src/types/form/SearchAdvancedFiltersForm.ts index 6541072cae81..7cd1cc00ff4d 100644 --- a/src/types/form/SearchAdvancedFiltersForm.ts +++ b/src/types/form/SearchAdvancedFiltersForm.ts @@ -2,6 +2,7 @@ import type {ValueOf} from 'type-fest'; import type Form from './Form'; const FILTER_KEYS = { + TYPE: 'type', DATE_AFTER: 'dateAfter', DATE_BEFORE: 'dateBefore', CURRENCY: 'currency', @@ -19,6 +20,7 @@ const FILTER_KEYS = { KEYWORD: 'keyword', FROM: 'from', TO: 'to', + IS: 'is', } as const; type InputID = ValueOf; @@ -26,6 +28,7 @@ type InputID = ValueOf; type SearchAdvancedFiltersForm = Form< InputID, { + [FILTER_KEYS.TYPE]: string; [FILTER_KEYS.DATE_AFTER]: string; [FILTER_KEYS.DATE_BEFORE]: string; [FILTER_KEYS.CURRENCY]: string[]; @@ -43,6 +46,7 @@ type SearchAdvancedFiltersForm = Form< [FILTER_KEYS.TAG]: string[]; [FILTER_KEYS.FROM]: string[]; [FILTER_KEYS.TO]: string[]; + [FILTER_KEYS.IS]: string[]; } >; From d0e97b1e709182f59ccc12619836e4cfa7e2cea0 Mon Sep 17 00:00:00 2001 From: dominictb Date: Wed, 28 Aug 2024 13:37:41 +0700 Subject: [PATCH 07/77] fix: clear anonymous user records after login --- src/CONST.ts | 1 + src/libs/actions/Session/index.ts | 36 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index 30b0b5364d83..75c688d604c6 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1339,6 +1339,7 @@ const CONST = { STUDENT_AMBASSADOR: 'studentambassadors@expensify.com', SVFG: 'svfg@expensify.com', EXPENSIFY_EMAIL_DOMAIN: '@expensify.com', + ANONYMOUS_USER_DOMAIN: '@expensify.anon', }, CONCIERGE_DISPLAY_NAME: 'Concierge', diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index b687abd61bb9..4a0e9feca469 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -50,6 +50,7 @@ import type {HybridAppRoute, Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import type Credentials from '@src/types/onyx/Credentials'; +import type {PersonalDetailsList} from '@src/types/onyx/PersonalDetails'; import type {AutoAuthState} from '@src/types/onyx/Session'; import type Session from '@src/types/onyx/Session'; import clearCache from './clearCache'; @@ -97,6 +98,15 @@ Onyx.connect({ callback: (val) => (preferredLocale = val ?? null), }); +let allPersonalDetails: OnyxEntry; + +Onyx.connect({ + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + callback: (value) => { + allPersonalDetails = value ?? {}; + }, +}); + function isSupportAuthToken(): boolean { return session.authTokenType === CONST.AUTH_TOKEN_TYPES.SUPPORT; } @@ -418,6 +428,24 @@ function beginSignIn(email: string) { API.read(READ_COMMANDS.BEGIN_SIGNIN, params, {optimisticData, successData, failureData}); } +/** + * Create Onyx update to clean up anonymous user data + */ +function buildOnyxDataToCleanUpAnonymousUser() { + const anonAccountIDs = Object.values(allPersonalDetails ?? {}) + .filter((detail) => detail?.login?.includes(CONST.EMAIL.ANONYMOUS_USER_DOMAIN) && detail?.accountID) + .map((detail) => detail?.accountID) as number[]; + const data = anonAccountIDs.reduce((res, accountID) => { + res[accountID] = null; + return res; + }, {} as Record); + return { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: data, + onyxMethod: Onyx.METHOD.MERGE, + }; +} + /** * Creates an account for the new user and signs them into the application with the newly created account. * @@ -434,6 +462,8 @@ function signUpUser() { }, ]; + const onyxOperationToCleanUpAnonymousUser = buildOnyxDataToCleanUpAnonymousUser(); + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -442,6 +472,7 @@ function signUpUser() { isLoading: false, }, }, + onyxOperationToCleanUpAnonymousUser, ]; const failureData: OnyxUpdate[] = [ @@ -517,6 +548,8 @@ function signIn(validateCode: string, twoFactorAuthCode?: string) { }, ]; + const onyxOperationToCleanUpAnonymousUser = buildOnyxDataToCleanUpAnonymousUser(); + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -533,6 +566,7 @@ function signIn(validateCode: string, twoFactorAuthCode?: string) { validateCode, }, }, + onyxOperationToCleanUpAnonymousUser, ]; const failureData: OnyxUpdate[] = [ @@ -567,6 +601,7 @@ function signInWithValidateCode(accountID: number, code: string, twoFactorAuthCo // If this is called from the 2fa step, get the validateCode directly from onyx // instead of the one passed from the component state because the state is changing when this method is called. const validateCode = twoFactorAuthCode ? credentials.validateCode : code; + const onyxOperationToCleanUpAnonymousUser = buildOnyxDataToCleanUpAnonymousUser(); const optimisticData: OnyxUpdate[] = [ { @@ -607,6 +642,7 @@ function signInWithValidateCode(accountID: number, code: string, twoFactorAuthCo key: ONYXKEYS.SESSION, value: {autoAuthState: CONST.AUTO_AUTH_STATE.JUST_SIGNED_IN}, }, + onyxOperationToCleanUpAnonymousUser, ]; const failureData: OnyxUpdate[] = [ From 24f4854e298b2a62542abd28b69609a6d1de1f7e Mon Sep 17 00:00:00 2001 From: dominictb Date: Fri, 30 Aug 2024 17:57:21 +0700 Subject: [PATCH 08/77] fix: only clear the current anonymous account --- src/libs/actions/Session/index.ts | 71 +++++++++++++------------------ 1 file changed, 29 insertions(+), 42 deletions(-) diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 4a0e9feca469..9eb982c32691 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -50,9 +50,8 @@ import type {HybridAppRoute, Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import type Credentials from '@src/types/onyx/Credentials'; -import type {PersonalDetailsList} from '@src/types/onyx/PersonalDetails'; -import type {AutoAuthState} from '@src/types/onyx/Session'; import type Session from '@src/types/onyx/Session'; +import type {AutoAuthState} from '@src/types/onyx/Session'; import clearCache from './clearCache'; import updateSessionAuthTokens from './updateSessionAuthTokens'; @@ -98,15 +97,6 @@ Onyx.connect({ callback: (val) => (preferredLocale = val ?? null), }); -let allPersonalDetails: OnyxEntry; - -Onyx.connect({ - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - callback: (value) => { - allPersonalDetails = value ?? {}; - }, -}); - function isSupportAuthToken(): boolean { return session.authTokenType === CONST.AUTH_TOKEN_TYPES.SUPPORT; } @@ -432,13 +422,10 @@ function beginSignIn(email: string) { * Create Onyx update to clean up anonymous user data */ function buildOnyxDataToCleanUpAnonymousUser() { - const anonAccountIDs = Object.values(allPersonalDetails ?? {}) - .filter((detail) => detail?.login?.includes(CONST.EMAIL.ANONYMOUS_USER_DOMAIN) && detail?.accountID) - .map((detail) => detail?.accountID) as number[]; - const data = anonAccountIDs.reduce((res, accountID) => { - res[accountID] = null; - return res; - }, {} as Record); + const data: Record = {}; + if (session.authTokenType === CONST.AUTH_TOKEN_TYPES.ANONYMOUS && session.accountID) { + data[session.accountID] = null; + } return { key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: data, @@ -1082,39 +1069,39 @@ const canAnonymousUserAccessRoute = (route: string) => { }; export { - beginSignIn, + authenticatePusher, beginAppleSignIn, beginGoogleSignIn, - setSupportAuthToken, + beginSignIn, + canAnonymousUserAccessRoute, checkIfActionIsAllowed, - signIn, - signInWithValidateCode, + cleanupSession, + clearAccountMessages, + clearSignInData, handleExitToNavigation, - signInWithValidateCodeAndNavigate, + hasAuthToken, + hasStashedSession, initAutoAuthState, + invalidateAuthToken, + invalidateCredentials, + isAnonymousUser, + isSupportAuthToken, + reauthenticatePusher, + requestUnlinkValidationLink, + resendValidateCode, + resendValidationLink, + setAccountError, + setSupportAuthToken, + signIn, signInWithShortLivedAuthToken, - cleanupSession, + signInWithSupportAuthToken, + signInWithValidateCode, + signInWithValidateCodeAndNavigate, signOut, signOutAndRedirectToSignIn, - resendValidationLink, - resendValidateCode, - requestUnlinkValidationLink, - unlinkLogin, - clearSignInData, - clearAccountMessages, - setAccountError, - authenticatePusher, - reauthenticatePusher, - invalidateCredentials, - invalidateAuthToken, - isAnonymousUser, + signUpUser, toggleTwoFactorAuth, + unlinkLogin, validateTwoFactorAuth, waitForUserSignIn, - hasAuthToken, - canAnonymousUserAccessRoute, - signInWithSupportAuthToken, - isSupportAuthToken, - hasStashedSession, - signUpUser, }; From 48a7997f914145532d5e8be4ed2550ab6eef1720 Mon Sep 17 00:00:00 2001 From: dominictb Date: Fri, 30 Aug 2024 18:03:15 +0700 Subject: [PATCH 09/77] fix: re-order exports in Session/index.ts --- src/libs/actions/Session/index.ts | 48 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 9eb982c32691..bbfcaaacd530 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -1069,39 +1069,39 @@ const canAnonymousUserAccessRoute = (route: string) => { }; export { - authenticatePusher, + beginSignIn, beginAppleSignIn, beginGoogleSignIn, - beginSignIn, - canAnonymousUserAccessRoute, - checkIfActionIsAllowed, - cleanupSession, - clearAccountMessages, - clearSignInData, - handleExitToNavigation, - hasAuthToken, - hasStashedSession, - initAutoAuthState, - invalidateAuthToken, - invalidateCredentials, - isAnonymousUser, - isSupportAuthToken, - reauthenticatePusher, - requestUnlinkValidationLink, - resendValidateCode, - resendValidationLink, - setAccountError, setSupportAuthToken, + checkIfActionIsAllowed, signIn, - signInWithShortLivedAuthToken, - signInWithSupportAuthToken, signInWithValidateCode, + handleExitToNavigation, signInWithValidateCodeAndNavigate, + initAutoAuthState, + signInWithShortLivedAuthToken, + cleanupSession, signOut, signOutAndRedirectToSignIn, - signUpUser, - toggleTwoFactorAuth, + resendValidationLink, + resendValidateCode, + requestUnlinkValidationLink, unlinkLogin, + clearSignInData, + clearAccountMessages, + setAccountError, + authenticatePusher, + reauthenticatePusher, + invalidateCredentials, + invalidateAuthToken, + isAnonymousUser, + toggleTwoFactorAuth, validateTwoFactorAuth, waitForUserSignIn, + hasAuthToken, + canAnonymousUserAccessRoute, + signInWithSupportAuthToken, + isSupportAuthToken, + hasStashedSession, + signUpUser, }; From 6d5ca9150f2a9e72f478330d0c8ab6f6b322a2e4 Mon Sep 17 00:00:00 2001 From: I Nyoman Jyotisa Date: Tue, 3 Sep 2024 01:01:29 +0800 Subject: [PATCH 10/77] Fix: Show warning modal on POLICY_ACCOUNTING after workspace upgrade --- src/ROUTES.ts | 7 +++++- .../accounting/AccountingContext.tsx | 10 +++++++- .../accounting/PolicyAccountingPage.tsx | 24 +++++++++++++++++++ src/pages/workspace/accounting/utils.tsx | 12 +++++++--- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 231997e398bc..ae7f9d5256d5 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -703,7 +703,12 @@ const ROUTES = { }, POLICY_ACCOUNTING: { route: 'settings/workspaces/:policyID/accounting', - getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting` as const, + getRoute: (policyID: string, newConnectionName?: ConnectionName, integrationToDisconnect?: ConnectionName, shouldDisconnectIntegrationBeforeConnecting?: boolean) => + `settings/workspaces/${policyID}/accounting${ + newConnectionName + ? `?newConnectionName=${newConnectionName}&integrationToDisconnect=${integrationToDisconnect}&shouldDisconnectIntegrationBeforeConnecting=${shouldDisconnectIntegrationBeforeConnecting}` + : '' + }` as const, }, WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ADVANCED: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/advanced', diff --git a/src/pages/workspace/accounting/AccountingContext.tsx b/src/pages/workspace/accounting/AccountingContext.tsx index ce5ac90fd2f1..a73287a10e33 100644 --- a/src/pages/workspace/accounting/AccountingContext.tsx +++ b/src/pages/workspace/accounting/AccountingContext.tsx @@ -58,7 +58,15 @@ function AccountingContextProvider({children, policy}: AccountingContextProvider const startIntegrationFlow = React.useCallback( (newActiveIntegration: ActiveIntegration) => { - const accountingIntegrationData = getAccountingIntegrationData(newActiveIntegration.name, policyID, translate); + const accountingIntegrationData = getAccountingIntegrationData( + newActiveIntegration.name, + policyID, + translate, + undefined, + undefined, + newActiveIntegration.integrationToDisconnect, + newActiveIntegration.shouldDisconnectIntegrationBeforeConnecting, + ); const workspaceUpgradeNavigationDetails = accountingIntegrationData?.workspaceUpgradeNavigationDetails; if (workspaceUpgradeNavigationDetails && !isControlPolicy(policy)) { Navigation.navigate( diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index 107f64dd2dee..5a5d5925133f 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -1,3 +1,4 @@ +import {useRoute} from '@react-navigation/native'; import {differenceInMinutes, isValid, parseISO} from 'date-fns'; import React, {useEffect, useMemo, useRef, useState} from 'react'; import {ActivityIndicator, View} from 'react-native'; @@ -41,11 +42,18 @@ import type {AnchorPosition} from '@styles/index'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import {ConnectionName} from '@src/types/onyx/Policy'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {AccountingContextProvider, useAccountingContext} from './AccountingContext'; import type {MenuItemData, PolicyAccountingPageProps} from './types'; import {getAccountingIntegrationData} from './utils'; +type RouteParams = { + newConnectionName?: ConnectionName; + integrationToDisconnect?: ConnectionName; + shouldDisconnectIntegrationBeforeConnecting?: boolean; +}; + function PolicyAccountingPage({policy}: PolicyAccountingPageProps) { const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy.id}`); const theme = useTheme(); @@ -61,6 +69,12 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) { const {canUseWorkspaceFeeds} = usePermissions(); const {startIntegrationFlow, popoverAnchorRefs} = useAccountingContext(); + const route = useRoute(); + const params = route.params as RouteParams | undefined; + const newConnectionName = params?.newConnectionName; + const integrationToDisconnect = params?.integrationToDisconnect; + const shouldDisconnectIntegrationBeforeConnecting = params?.shouldDisconnectIntegrationBeforeConnecting; + const lastSyncProgressDate = parseISO(connectionSyncProgress?.timestamp ?? ''); const isSyncInProgress = !!connectionSyncProgress?.stageInProgress && @@ -122,6 +136,16 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) { [shouldShowEnterCredentials, translate, isOffline, policyID, connectedIntegration, startIntegrationFlow], ); + useEffect(() => { + if (!!newConnectionName) { + startIntegrationFlow({ + name: newConnectionName, + integrationToDisconnect: integrationToDisconnect, + shouldDisconnectIntegrationBeforeConnecting: shouldDisconnectIntegrationBeforeConnecting, + }); + } + }, [newConnectionName, integrationToDisconnect, shouldDisconnectIntegrationBeforeConnecting, window.location.pathname]); + useEffect(() => { if (successfulDate) { setDateTimeToRelative(getDatetimeToRelative(successfulDate)); diff --git a/src/pages/workspace/accounting/utils.tsx b/src/pages/workspace/accounting/utils.tsx index 05ee41b85b9b..bd13d5fe2075 100644 --- a/src/pages/workspace/accounting/utils.tsx +++ b/src/pages/workspace/accounting/utils.tsx @@ -10,7 +10,7 @@ import {getTrackingCategories} from '@userActions/connections/Xero'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Policy} from '@src/types/onyx'; -import type {PolicyConnectionName} from '@src/types/onyx/Policy'; +import type {ConnectionName, PolicyConnectionName} from '@src/types/onyx/Policy'; import type {AccountingIntegration} from './types'; function getAccountingIntegrationData( @@ -19,6 +19,8 @@ function getAccountingIntegrationData( translate: LocaleContextProps['translate'], policy?: Policy, key?: number, + integrationToDisconnect?: ConnectionName, + shouldDisconnectIntegrationBeforeConnecting?: boolean, ): AccountingIntegration | undefined { switch (connectionName) { case CONST.POLICY.CONNECTIONS.NAME.QBO: @@ -83,7 +85,9 @@ function getAccountingIntegrationData( onAdvancedPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_ADVANCED.getRoute(policyID)), workspaceUpgradeNavigationDetails: { integrationAlias: CONST.UPGRADE_FEATURE_INTRO_MAPPING.netsuite.alias, - backToAfterWorkspaceUpgradeRoute: ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID), + backToAfterWorkspaceUpgradeRoute: !!integrationToDisconnect + ? ROUTES.POLICY_ACCOUNTING.getRoute(policyID, connectionName, integrationToDisconnect, shouldDisconnectIntegrationBeforeConnecting) + : ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID), }, }; case CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT: @@ -126,7 +130,9 @@ function getAccountingIntegrationData( ], workspaceUpgradeNavigationDetails: { integrationAlias: CONST.UPGRADE_FEATURE_INTRO_MAPPING.intacct.alias, - backToAfterWorkspaceUpgradeRoute: ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_PREREQUISITES.getRoute(policyID), + backToAfterWorkspaceUpgradeRoute: !!integrationToDisconnect + ? ROUTES.POLICY_ACCOUNTING.getRoute(policyID, connectionName, integrationToDisconnect, shouldDisconnectIntegrationBeforeConnecting) + : ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID), }, pendingFields: policy?.connections?.intacct?.config?.pendingFields, errorFields: policy?.connections?.intacct?.config?.errorFields, From f6891bda694cb9ba5fd8c1edce24245fe85287c1 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Tue, 3 Sep 2024 00:42:54 +0200 Subject: [PATCH 11/77] Change address state to use value instead of default value --- src/components/AddressForm.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/AddressForm.tsx b/src/components/AddressForm.tsx index 7ca4cc3273ca..393cdd5559f8 100644 --- a/src/components/AddressForm.tsx +++ b/src/components/AddressForm.tsx @@ -1,5 +1,6 @@ import React, {useCallback} from 'react'; import {View} from 'react-native'; +import type {State} from '@components/StateSelector'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; @@ -192,7 +193,7 @@ function AddressForm({ From 8fe414c1ac4b7afaa34e3d6bdea97927c9e15b09 Mon Sep 17 00:00:00 2001 From: Abdelrahman Khattab Date: Tue, 3 Sep 2024 01:00:47 +0200 Subject: [PATCH 12/77] Minor edit --- src/components/AddressForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/AddressForm.tsx b/src/components/AddressForm.tsx index 393cdd5559f8..bd032df9a244 100644 --- a/src/components/AddressForm.tsx +++ b/src/components/AddressForm.tsx @@ -1,12 +1,11 @@ import React, {useCallback} from 'react'; import {View} from 'react-native'; -import type {State} from '@components/StateSelector'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as ValidationUtils from '@libs/ValidationUtils'; -import CONST from '@src/CONST'; import type {Country} from '@src/CONST'; +import CONST from '@src/CONST'; import type ONYXKEYS from '@src/ONYXKEYS'; import INPUT_IDS from '@src/types/form/HomeAddressForm'; import type {Errors} from '@src/types/onyx/OnyxCommon'; @@ -15,6 +14,7 @@ import CountrySelector from './CountrySelector'; import FormProvider from './Form/FormProvider'; import InputWrapper from './Form/InputWrapper'; import type {FormOnyxValues} from './Form/types'; +import type {State} from './StateSelector'; import StateSelector from './StateSelector'; import TextInput from './TextInput'; From e9fcb34c8d764389dab927f97cb4bb5fd21ce029 Mon Sep 17 00:00:00 2001 From: I Nyoman Jyotisa Date: Tue, 3 Sep 2024 11:25:41 +0800 Subject: [PATCH 13/77] lint fix and change useEffect to useFocusEffect --- .../accounting/PolicyAccountingPage.tsx | 27 ++++++++++--------- src/pages/workspace/accounting/utils.tsx | 4 +-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index 5a5d5925133f..dfe09d0d3dfd 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -1,6 +1,6 @@ -import {useRoute} from '@react-navigation/native'; +import {useFocusEffect, useRoute} from '@react-navigation/native'; import {differenceInMinutes, isValid, parseISO} from 'date-fns'; -import React, {useEffect, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {ActivityIndicator, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; @@ -33,6 +33,7 @@ import { getCurrentXeroOrganizationName, getIntegrationLastSuccessfulDate, getXeroTenants, + isControlPolicy, settingsPendingAction, } from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; @@ -42,7 +43,7 @@ import type {AnchorPosition} from '@styles/index'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {ConnectionName} from '@src/types/onyx/Policy'; +import type {ConnectionName} from '@src/types/onyx/Policy'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {AccountingContextProvider, useAccountingContext} from './AccountingContext'; import type {MenuItemData, PolicyAccountingPageProps} from './types'; @@ -136,15 +137,17 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) { [shouldShowEnterCredentials, translate, isOffline, policyID, connectedIntegration, startIntegrationFlow], ); - useEffect(() => { - if (!!newConnectionName) { - startIntegrationFlow({ - name: newConnectionName, - integrationToDisconnect: integrationToDisconnect, - shouldDisconnectIntegrationBeforeConnecting: shouldDisconnectIntegrationBeforeConnecting, - }); - } - }, [newConnectionName, integrationToDisconnect, shouldDisconnectIntegrationBeforeConnecting, window.location.pathname]); + useFocusEffect( + useCallback(() => { + if (newConnectionName && isControlPolicy(policy)) { + startIntegrationFlow({ + name: newConnectionName, + integrationToDisconnect, + shouldDisconnectIntegrationBeforeConnecting, + }); + } + }, [newConnectionName, integrationToDisconnect, shouldDisconnectIntegrationBeforeConnecting, isControlPolicy(policy), startIntegrationFlow]), + ); useEffect(() => { if (successfulDate) { diff --git a/src/pages/workspace/accounting/utils.tsx b/src/pages/workspace/accounting/utils.tsx index bd13d5fe2075..d7e67ab1e963 100644 --- a/src/pages/workspace/accounting/utils.tsx +++ b/src/pages/workspace/accounting/utils.tsx @@ -85,7 +85,7 @@ function getAccountingIntegrationData( onAdvancedPagePress: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_ADVANCED.getRoute(policyID)), workspaceUpgradeNavigationDetails: { integrationAlias: CONST.UPGRADE_FEATURE_INTRO_MAPPING.netsuite.alias, - backToAfterWorkspaceUpgradeRoute: !!integrationToDisconnect + backToAfterWorkspaceUpgradeRoute: integrationToDisconnect ? ROUTES.POLICY_ACCOUNTING.getRoute(policyID, connectionName, integrationToDisconnect, shouldDisconnectIntegrationBeforeConnecting) : ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID), }, @@ -130,7 +130,7 @@ function getAccountingIntegrationData( ], workspaceUpgradeNavigationDetails: { integrationAlias: CONST.UPGRADE_FEATURE_INTRO_MAPPING.intacct.alias, - backToAfterWorkspaceUpgradeRoute: !!integrationToDisconnect + backToAfterWorkspaceUpgradeRoute: integrationToDisconnect ? ROUTES.POLICY_ACCOUNTING.getRoute(policyID, connectionName, integrationToDisconnect, shouldDisconnectIntegrationBeforeConnecting) : ROUTES.POLICY_ACCOUNTING_NETSUITE_TOKEN_INPUT.getRoute(policyID), }, From 1fe95cce36440b01c54df3ccce0317e153fa29b0 Mon Sep 17 00:00:00 2001 From: I Nyoman Jyotisa Date: Tue, 3 Sep 2024 11:51:51 +0800 Subject: [PATCH 14/77] lint fix --- .../accounting/PolicyAccountingPage.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index 33beab4f437a..5a1abf431cfd 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -133,14 +133,16 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) { useFocusEffect( useCallback(() => { - if (newConnectionName && isControlPolicy(policy)) { - startIntegrationFlow({ - name: newConnectionName, - integrationToDisconnect, - shouldDisconnectIntegrationBeforeConnecting, - }); + if (!newConnectionName || !isControlPolicy(policy)) { + return; } - }, [newConnectionName, integrationToDisconnect, shouldDisconnectIntegrationBeforeConnecting, isControlPolicy(policy), startIntegrationFlow]), + + startIntegrationFlow({ + name: newConnectionName, + integrationToDisconnect, + shouldDisconnectIntegrationBeforeConnecting, + }); + }, [newConnectionName, integrationToDisconnect, shouldDisconnectIntegrationBeforeConnecting, policy, startIntegrationFlow]), ); useEffect(() => { From 33b671ab1e2b55798622a5223864fecc1b481f99 Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Tue, 3 Sep 2024 16:01:08 +0200 Subject: [PATCH 15/77] add is phrase to parser --- src/libs/SearchParser/searchParser.js | 66 ++++++++++++++-------- src/libs/SearchParser/searchParser.peggy | 1 + src/libs/SearchUtils.ts | 3 +- src/pages/Search/AdvancedSearchFilters.tsx | 15 ++--- 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js index a93e3fae8551..4c6c382d6224 100644 --- a/src/libs/SearchParser/searchParser.js +++ b/src/libs/SearchParser/searchParser.js @@ -201,7 +201,8 @@ function peg$parse(input, options) { var peg$c23 = "sortOrder"; var peg$c24 = "policyID"; var peg$c25 = "has"; - var peg$c26 = "\""; + var peg$c26 = "is"; + var peg$c27 = "\""; var peg$r0 = /^[:=]/; var peg$r1 = /^[^"\r\n]/; @@ -235,11 +236,12 @@ function peg$parse(input, options) { var peg$e24 = peg$literalExpectation("sortOrder", false); var peg$e25 = peg$literalExpectation("policyID", false); var peg$e26 = peg$literalExpectation("has", false); - var peg$e27 = peg$literalExpectation("\"", false); - var peg$e28 = peg$classExpectation(["\"", "\r", "\n"], true, false); - var peg$e29 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_", "@", ".", "/", "#", "&", "+", "-", "\\", "'", ",", ";"], false, false); - var peg$e30 = peg$otherExpectation("whitespace"); - var peg$e31 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); + var peg$e27 = peg$literalExpectation("is", false); + var peg$e28 = peg$literalExpectation("\"", false); + var peg$e29 = peg$classExpectation(["\"", "\r", "\n"], true, false); + var peg$e30 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_", "@", ".", "/", "#", "&", "+", "-", "\\", "'", ",", ";"], false, false); + var peg$e31 = peg$otherExpectation("whitespace"); + var peg$e32 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); var peg$f0 = function(filters) { const withDefaults = applyDefaults(filters); @@ -314,10 +316,11 @@ function peg$parse(input, options) { var peg$f27 = function() { return "sortOrder"; }; var peg$f28 = function() { return "policyID"; }; var peg$f29 = function() { return "has"; }; - var peg$f30 = function(parts) { return parts.join(''); }; - var peg$f31 = function(chars) { return chars.join(''); }; + var peg$f30 = function() { return "is"; }; + var peg$f31 = function(parts) { return parts.join(''); }; var peg$f32 = function(chars) { return chars.join(''); }; - var peg$f33 = function() { return "and"; }; + var peg$f33 = function(chars) { return chars.join(''); }; + var peg$f34 = function() { return "and"; }; var peg$currPos = options.peg$currPos | 0; var peg$savedPos = peg$currPos; var peg$posDetailsCache = [{ line: 1, column: 1 }]; @@ -954,6 +957,21 @@ function peg$parse(input, options) { s1 = peg$f29(); } s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c26) { + s1 = peg$c26; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e27); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f30(); + } + s0 = s1; + } } } } @@ -1000,7 +1018,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f30(s1); + s1 = peg$f31(s1); } s0 = s1; @@ -1012,11 +1030,11 @@ function peg$parse(input, options) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c26; + s1 = peg$c27; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e27); } + if (peg$silentFails === 0) { peg$fail(peg$e28); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1025,7 +1043,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e28); } + if (peg$silentFails === 0) { peg$fail(peg$e29); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -1034,19 +1052,19 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e28); } + if (peg$silentFails === 0) { peg$fail(peg$e29); } } } if (input.charCodeAt(peg$currPos) === 34) { - s3 = peg$c26; + s3 = peg$c27; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e27); } + if (peg$silentFails === 0) { peg$fail(peg$e28); } } if (s3 !== peg$FAILED) { peg$savedPos = s0; - s0 = peg$f31(s2); + s0 = peg$f32(s2); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1069,7 +1087,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e29); } + if (peg$silentFails === 0) { peg$fail(peg$e30); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { @@ -1079,7 +1097,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e29); } + if (peg$silentFails === 0) { peg$fail(peg$e30); } } } } else { @@ -1087,7 +1105,7 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f32(s1); + s1 = peg$f33(s1); } s0 = s1; @@ -1100,7 +1118,7 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = peg$parse_(); peg$savedPos = s0; - s1 = peg$f33(); + s1 = peg$f34(); s0 = s1; return s0; @@ -1116,7 +1134,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e31); } + if (peg$silentFails === 0) { peg$fail(peg$e32); } } while (s1 !== peg$FAILED) { s0.push(s1); @@ -1125,12 +1143,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e31); } + if (peg$silentFails === 0) { peg$fail(peg$e32); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e30); } + if (peg$silentFails === 0) { peg$fail(peg$e31); } return s0; } diff --git a/src/libs/SearchParser/searchParser.peggy b/src/libs/SearchParser/searchParser.peggy index 105a8a62bc39..805ee3e668de 100644 --- a/src/libs/SearchParser/searchParser.peggy +++ b/src/libs/SearchParser/searchParser.peggy @@ -135,6 +135,7 @@ key / "sortOrder" { return "sortOrder"; } / "policyID" { return "policyID"; } / "has" { return "has"; } + / "is" { return "is"; } identifier = parts:(quotedString / alphanumeric)+ { return parts.join(''); } diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 1d621a38d22e..4d5393c23fa1 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -475,7 +475,8 @@ function buildQueryStringFromFilters(filterValues: Partial 0 ) { diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 74d4dae562c9..2576e1e483d2 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -109,7 +109,7 @@ const baseFilterConfig = { route: ROUTES.SEARCH_ADVANCED_FILTERS_IN, }, is: { - getTitle: getChatIsDisplayTitle, + getTitle: getFilterIsDisplayTitle, description: 'search.filters.is' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_IS, }, @@ -119,7 +119,7 @@ const typeFiltersKeys: Record, cards: CardList) { @@ -237,7 +237,7 @@ function getFilterHasDisplayTitle(filters: Partial, t : undefined; } -function getChatIsDisplayTitle(filters: Partial, translate: LocaleContextProps['translate']) { +function getFilterIsDisplayTitle(filters: Partial, translate: LocaleContextProps['translate']) { const filterValue = filters[CONST.SEARCH.SYNTAX_FILTER_KEYS.IS]; return filterValue ? Object.values(CONST.SEARCH.CHAT_STATUS) @@ -337,15 +337,10 @@ function AdvancedSearchFilters() { // description: 'common.in' as const, // route: ROUTES.SEARCH_ADVANCED_FILTERS_IN, // }, - // { - // title: getChatIsDisplayTitle(searchAdvancedFilters, translate), - // description: 'search.filters.is' as const, - // route: ROUTES.SEARCH_ADVANCED_FILTERS_IS, - // }, // ], // [searchAdvancedFilters, translate, cardList, taxRates, personalDetails, reports], // ); - const currentType = searchAdvancedFilters?.type ?? CONST.SEARCH.DATA_TYPES.EXPENSE; + const currentType = 'chat'; const onFormSubmit = () => { const query = SearchUtils.buildQueryStringFromFilters(searchAdvancedFilters); @@ -381,7 +376,7 @@ function AdvancedSearchFilters() { filterTitle = baseFilterConfig[key].getTitle(searchAdvancedFilters, cardList); } else if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE) { filterTitle = baseFilterConfig[key].getTitle(searchAdvancedFilters, taxRates); - } else if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPENSE_TYPE || key === CONST.SEARCH.SYNTAX_FILTER_KEYS.HAS) { + } else if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPENSE_TYPE || key === CONST.SEARCH.SYNTAX_FILTER_KEYS.HAS || key === CONST.SEARCH.SYNTAX_FILTER_KEYS.IS) { filterTitle = baseFilterConfig[key].getTitle(searchAdvancedFilters, translate); } else if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || key === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO) { filterTitle = baseFilterConfig[key].getTitle(searchAdvancedFilters[key] ?? [], personalDetails); From a263e109c5ca164b3feb7a0f696ac5ce0861cd23 Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Tue, 3 Sep 2024 16:52:16 +0200 Subject: [PATCH 16/77] revert test code --- src/pages/Search/AdvancedSearchFilters.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 2576e1e483d2..a7b803e4ae52 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -340,7 +340,7 @@ function AdvancedSearchFilters() { // ], // [searchAdvancedFilters, translate, cardList, taxRates, personalDetails, reports], // ); - const currentType = 'chat'; + const currentType = searchAdvancedFilters?.type ?? CONST.SEARCH.DATA_TYPES.EXPENSE; const onFormSubmit = () => { const query = SearchUtils.buildQueryStringFromFilters(searchAdvancedFilters); From 973d557b587985fb882c22c7cfb0fdbe23c24348 Mon Sep 17 00:00:00 2001 From: Srikar Parsi <48188732+srikarparsi@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:38:03 -0400 Subject: [PATCH 17/77] Revert "Revert "Revert "Consolidate options on settlement "Pay" button""" --- .../ButtonWithDropdownMenu/index.tsx | 2 +- .../ButtonWithDropdownMenu/types.ts | 3 +- src/components/KYCWall/BaseKYCWall.tsx | 129 +++++++++++++++--- .../MoneyRequestConfirmationList.tsx | 1 + src/components/SettlementButton.tsx | 45 +++--- src/languages/en.ts | 3 - src/languages/es.ts | 5 - src/languages/types.ts | 1 - src/pages/iou/MoneyRequestAmountForm.tsx | 1 + src/types/onyx/OriginalMessage.ts | 2 +- 10 files changed, 137 insertions(+), 55 deletions(-) diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index c58bb3a09f29..bc297b0b39a6 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -66,7 +66,7 @@ function ButtonWithDropdownMenu({ if ('measureInWindow' in dropdownAnchor.current) { dropdownAnchor.current.measureInWindow((x, y, w, h) => { setPopoverAnchorPosition({ - horizontal: x + w + h, + horizontal: x + w, vertical: anchorAlignment.vertical === CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP ? y + h + CONST.MODAL.POPOVER_MENU_PADDING // if vertical anchorAlignment is TOP, menu will open below the button and we need to add the height of button and padding diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts index 82b26a39e1db..58ad58ce4e68 100644 --- a/src/components/ButtonWithDropdownMenu/types.ts +++ b/src/components/ButtonWithDropdownMenu/types.ts @@ -1,13 +1,12 @@ import type {RefObject} from 'react'; import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'; import type {ValueOf} from 'type-fest'; -import type {PaymentMethodType} from '@components/KYCWall/types'; import type CONST from '@src/CONST'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type IconAsset from '@src/types/utils/IconAsset'; -type PaymentType = DeepValueOf; +type PaymentType = DeepValueOf; type WorkspaceMemberBulkActionType = DeepValueOf; diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index 625973bbbe59..fd681546c470 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -1,12 +1,16 @@ -import React, {useCallback, useRef} from 'react'; -import type {GestureResponderEvent, View} from 'react-native'; +import React, {useCallback, useEffect, useRef, useState} from 'react'; +import {Dimensions} from 'react-native'; +import type {EmitterSubscription, GestureResponderEvent, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; +import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu'; import * as BankAccounts from '@libs/actions/BankAccounts'; +import getClickedTargetLocation from '@libs/getClickedTargetLocation'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import * as PaymentUtils from '@libs/PaymentUtils'; import * as ReportUtils from '@libs/ReportUtils'; +import * as PaymentMethods from '@userActions/PaymentMethods'; import * as Policy from '@userActions/Policy/Policy'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; @@ -15,7 +19,10 @@ import ROUTES from '@src/ROUTES'; import type {BankAccountList, FundList, ReimbursementAccount, UserWallet, WalletTerms} from '@src/types/onyx'; import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import viewRef from '@src/types/utils/viewRef'; -import type {KYCWallProps, PaymentMethod} from './types'; +import type {AnchorPosition, DomRect, KYCWallProps, PaymentMethod} from './types'; + +// This sets the Horizontal anchor position offset for POPOVER MENU. +const POPOVER_MENU_ANCHOR_POSITION_HORIZONTAL_OFFSET = 20; type BaseKYCWallOnyxProps = { /** The user's wallet */ @@ -42,6 +49,10 @@ type BaseKYCWallProps = KYCWallProps & BaseKYCWallOnyxProps; function KYCWall({ addBankAccountRoute, addDebitCardRoute, + anchorAlignment = { + horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, + vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, + }, bankAccountList = {}, chatReportID = '', children, @@ -52,13 +63,60 @@ function KYCWall({ onSuccessfulKYC, reimbursementAccount, shouldIncludeDebitCard = true, + shouldListenForResize = false, source, userWallet, walletTerms, + shouldShowPersonalBankAccountOption = false, }: BaseKYCWallProps) { const anchorRef = useRef(null); const transferBalanceButtonRef = useRef(null); + const [shouldShowAddPaymentMenu, setShouldShowAddPaymentMenu] = useState(false); + + const [anchorPosition, setAnchorPosition] = useState({ + anchorPositionVertical: 0, + anchorPositionHorizontal: 0, + }); + + const getAnchorPosition = useCallback( + (domRect: DomRect): AnchorPosition => { + if (anchorAlignment.vertical === CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP) { + return { + anchorPositionVertical: domRect.top + domRect.height + CONST.MODAL.POPOVER_MENU_PADDING, + anchorPositionHorizontal: domRect.left + POPOVER_MENU_ANCHOR_POSITION_HORIZONTAL_OFFSET, + }; + } + + return { + anchorPositionVertical: domRect.top - CONST.MODAL.POPOVER_MENU_PADDING, + anchorPositionHorizontal: domRect.left, + }; + }, + [anchorAlignment.vertical], + ); + + /** + * Set position of the transfer payment menu + */ + const setPositionAddPaymentMenu = ({anchorPositionVertical, anchorPositionHorizontal}: AnchorPosition) => { + setAnchorPosition({ + anchorPositionVertical, + anchorPositionHorizontal, + }); + }; + + const setMenuPosition = useCallback(() => { + if (!transferBalanceButtonRef.current) { + return; + } + + const buttonPosition = getClickedTargetLocation(transferBalanceButtonRef.current as HTMLDivElement); + const position = getAnchorPosition(buttonPosition); + + setPositionAddPaymentMenu(position); + }, [getAnchorPosition]); + const selectPaymentMethod = useCallback( (paymentMethod: PaymentMethod) => { onSelectPaymentMethod(paymentMethod); @@ -101,6 +159,11 @@ function KYCWall({ */ Wallet.setKYCWallSource(source, chatReportID); + if (shouldShowAddPaymentMenu) { + setShouldShowAddPaymentMenu(false); + return; + } + // Use event target as fallback if anchorRef is null for safety const targetElement = anchorRef.current ?? (event?.currentTarget as HTMLDivElement); @@ -121,19 +184,11 @@ function KYCWall({ return; } - switch (iouPaymentType) { - case CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT: - selectPaymentMethod(CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT); - break; - case CONST.PAYMENT_METHODS.DEBIT_CARD: - selectPaymentMethod(CONST.PAYMENT_METHODS.DEBIT_CARD); - break; - case CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT: - selectPaymentMethod(CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT); - break; - default: - break; - } + const clickedElementLocation = getClickedTargetLocation(targetElement as HTMLDivElement); + const position = getAnchorPosition(clickedElementLocation); + + setPositionAddPaymentMenu(position); + setShouldShowAddPaymentMenu(true); return; } @@ -159,18 +214,58 @@ function KYCWall({ chatReportID, enablePaymentsRoute, fundList, + getAnchorPosition, iouReport, onSuccessfulKYC, reimbursementAccount?.achData?.state, selectPaymentMethod, shouldIncludeDebitCard, + shouldShowAddPaymentMenu, source, userWallet?.tierName, walletTerms?.source, ], ); - return <>{children(continueAction, viewRef(anchorRef))}; + useEffect(() => { + let dimensionsSubscription: EmitterSubscription | null = null; + + PaymentMethods.kycWallRef.current = {continueAction}; + + if (shouldListenForResize) { + dimensionsSubscription = Dimensions.addEventListener('change', setMenuPosition); + } + + return () => { + if (shouldListenForResize && dimensionsSubscription) { + dimensionsSubscription.remove(); + } + + PaymentMethods.kycWallRef.current = null; + }; + }, [chatReportID, setMenuPosition, shouldListenForResize, continueAction]); + + return ( + <> + setShouldShowAddPaymentMenu(false)} + anchorRef={anchorRef} + anchorPosition={{ + vertical: anchorPosition.anchorPositionVertical, + horizontal: anchorPosition.anchorPositionHorizontal, + }} + anchorAlignment={anchorAlignment} + onItemSelected={(item: PaymentMethod) => { + setShouldShowAddPaymentMenu(false); + selectPaymentMethod(item); + }} + shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} + /> + {children(continueAction, viewRef(anchorRef))} + + ); } KYCWall.displayName = 'BaseKYCWall'; diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index cee1450baeb2..f3089505d15a 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -837,6 +837,7 @@ function MoneyRequestConfirmationList({ onPress={confirm} enablePaymentsRoute={ROUTES.IOU_SEND_ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} + shouldShowPersonalBankAccountOption currency={iouCurrencyCode} policyID={policyID} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.LARGE} diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index fc72f2fe7418..e68d09375d49 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -105,6 +105,9 @@ type SettlementButtonProps = SettlementButtonOnyxProps & { /** The anchor alignment of the popover menu for KYC wall popover */ kycWallAnchorAlignment?: AnchorAlignment; + /** Whether the personal bank account option should be shown */ + shouldShowPersonalBankAccountOption?: boolean; + /** The priority to assign the enter key event listener to buttons. 0 is the highest priority. */ enterKeyEventListenerPriority?: number; @@ -144,6 +147,7 @@ function SettlementButton({ shouldShowApproveButton = false, shouldDisableApproveButton = false, style, + shouldShowPersonalBankAccountOption = false, enterKeyEventListenerPriority = 0, confirmApproval, policy, @@ -166,35 +170,25 @@ function SettlementButton({ (!shouldHidePaymentOptions && ReportUtils.isPayer(session, iouReport) && policy?.reimbursementChoice !== CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_MANUAL); const shouldShowPayElsewhereOption = (!isPaidGroupPolicy || policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_MANUAL) && !isInvoiceReport; const paymentButtonOptions = useMemo(() => { + const buttonOptions = []; const isExpenseReport = ReportUtils.isExpenseReport(iouReport); const paymentMethods = { + [CONST.IOU.PAYMENT_TYPE.EXPENSIFY]: { + text: translate('iou.settleExpensify', {formattedAmount}), + icon: Expensicons.Wallet, + value: CONST.IOU.PAYMENT_TYPE.EXPENSIFY, + }, [CONST.IOU.PAYMENT_TYPE.VBBA]: { text: translate('iou.settleExpensify', {formattedAmount}), icon: Expensicons.Wallet, value: CONST.IOU.PAYMENT_TYPE.VBBA, }, - [CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT]: { - text: translate('iou.settlePersonalBank', {formattedAmount}), - icon: Expensicons.Bank, - value: CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT, - }, - [CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT]: { - text: translate('iou.settleBusinessBank', {formattedAmount}), - icon: Expensicons.Bank, - value: CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT, - }, - [CONST.PAYMENT_METHODS.DEBIT_CARD]: { - text: translate('iou.settleDebitCard', {formattedAmount}), - icon: Expensicons.CreditCard, - value: CONST.PAYMENT_METHODS.DEBIT_CARD, - }, [CONST.IOU.PAYMENT_TYPE.ELSEWHERE]: { text: translate('iou.payElsewhere', {formattedAmount}), icon: Expensicons.Cash, value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, }, }; - const buttonOptions = []; const approveButtonOption = { text: translate('iou.approve'), icon: Expensicons.ThumbsUp, @@ -212,10 +206,12 @@ function SettlementButton({ // If the user has previously chosen a specific payment option or paid for some expense, // let's use the last payment method or use default. const paymentMethod = nvpLastPaymentMethod?.[policyID] ?? '-1'; - if (canUseWallet || (isExpenseReport && shouldShowPaywithExpensifyOption)) { - buttonOptions.push(paymentMethods[CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT]); + if (canUseWallet) { + buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.EXPENSIFY]); + } + if (isExpenseReport && shouldShowPaywithExpensifyOption) { + buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.VBBA]); } - if (shouldShowPayElsewhereOption) { buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.ELSEWHERE]); } @@ -275,12 +271,7 @@ function SettlementButton({ return; } - if ( - iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA || - iouPaymentType === CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT || - iouPaymentType === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT || - iouPaymentType === CONST.PAYMENT_METHODS.DEBIT_CARD - ) { + if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { triggerKYCFlow(event, iouPaymentType); BankAccounts.setPersonalBankAccountContinueKYCOnSuccess(ROUTES.ENABLE_PAYMENTS); return; @@ -314,6 +305,7 @@ function SettlementButton({ chatReportID={chatReportID} iouReport={iouReport} anchorAlignment={kycWallAnchorAlignment} + shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption} > {(triggerKYCFlow, buttonRef) => ( @@ -321,7 +313,10 @@ function SettlementButton({ onOptionsMenuShow={onPaymentOptionsShow} onOptionsMenuHide={onPaymentOptionsHide} buttonRef={buttonRef} + shouldAlwaysShowDropdownMenu={isInvoiceReport} + customText={isInvoiceReport ? translate('iou.settlePayment', {formattedAmount}) : undefined} menuHeaderText={isInvoiceReport ? translate('workspace.invoices.paymentMethods.chooseInvoiceMethod') : undefined} + isSplitButton={!isInvoiceReport} isDisabled={isDisabled} isLoading={isLoading} onPress={(event, iouPaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} diff --git a/src/languages/en.ts b/src/languages/en.ts index cbabc8c56ee8..ef17dae3069d 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -801,9 +801,6 @@ export default { settlePayment: ({formattedAmount}: SettleExpensifyCardParams) => `Pay ${formattedAmount}`, settleBusiness: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as a business` : `Pay as a business`), payElsewhere: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} elsewhere` : `Pay elsewhere`), - settlePersonalBank: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} with personal bank account` : `Pay with personal bank account`), - settleBusinessBank: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} with business bank account` : `Pay with business bank account`), - settleDebitCard: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} with debit card` : `Pay with debit card`), nextStep: 'Next steps', finished: 'Finished', sendInvoice: ({amount}: RequestAmountParams) => `Send ${amount} invoice`, diff --git a/src/languages/es.ts b/src/languages/es.ts index efd91987f331..3257bff1dc6a 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -794,11 +794,6 @@ export default { settlePayment: ({formattedAmount}: SettleExpensifyCardParams) => `Pagar ${formattedAmount}`, settleBusiness: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} como negocio` : `Pagar como empresa`), payElsewhere: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} de otra forma` : `Pagar de otra forma`), - settlePersonalBank: ({formattedAmount}: SettleExpensifyCardParams) => - formattedAmount ? `Pagar ${formattedAmount} con cuenta bancaria personal` : `Pagar con cuenta bancaria personal`, - settleBusinessBank: ({formattedAmount}: SettleExpensifyCardParams) => - formattedAmount ? `Pagar ${formattedAmount} con cuenta bancaria comercial` : `Pagar con cuenta bancaria comercial`, - settleDebitCard: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} con tarjeta de dΓ©bito` : `Pagar con tarjeta de dΓ©bito`), nextStep: 'Pasos siguientes', finished: 'Finalizado', sendInvoice: ({amount}: RequestAmountParams) => `Enviar factura de ${amount}`, diff --git a/src/languages/types.ts b/src/languages/types.ts index fb396a3f64ea..c4c6b25b06d0 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -103,7 +103,6 @@ type RequestCountParams = { type SettleExpensifyCardParams = { formattedAmount: string; - available?: boolean; }; type RequestAmountParams = {amount: string}; diff --git a/src/pages/iou/MoneyRequestAmountForm.tsx b/src/pages/iou/MoneyRequestAmountForm.tsx index 81de69919ed3..ba406c3ddef6 100644 --- a/src/pages/iou/MoneyRequestAmountForm.tsx +++ b/src/pages/iou/MoneyRequestAmountForm.tsx @@ -323,6 +323,7 @@ function MoneyRequestAmountForm( horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, }} + shouldShowPersonalBankAccountOption enterKeyEventListenerPriority={1} /> ) : ( diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index fcab54b470bf..763f221f56fe 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -8,7 +8,7 @@ import type ReportActionName from './ReportActionName'; type JoinWorkspaceResolution = ValueOf; /** Types of payments methods */ -type PaymentMethodType = DeepValueOf; +type PaymentMethodType = DeepValueOf; /** Types of sources of original message */ type OriginalMessageSource = 'Chronos' | 'email' | 'ios' | 'android' | 'web' | ''; From a8e9394ec5bd8d76e59d2bb7bf37bb9f18639bde Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Wed, 4 Sep 2024 10:56:10 +0200 Subject: [PATCH 18/77] add 'Draft' option --- src/CONST.ts | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/libs/SearchUtils.ts | 2 ++ 4 files changed, 5 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index be3e7111a616..806ed964cfdf 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -5247,6 +5247,7 @@ const CONST = { CHAT_STATUS: { UNREAD: 'unread', PINNED: 'pinned', + DRAFT: 'draft', }, BULK_ACTION_TYPES: { EXPORT: 'export', diff --git a/src/languages/en.ts b/src/languages/en.ts index 51a71963a832..3a5963ee0eb2 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3825,6 +3825,7 @@ export default { is: 'Is', pinned: 'Pinned', unread: 'Unread', + draft: 'Draft', amount: { lessThan: (amount?: string) => `Less than ${amount ?? ''}`, greaterThan: (amount?: string) => `Greater than ${amount ?? ''}`, diff --git a/src/languages/es.ts b/src/languages/es.ts index 6c69b4fedd92..fc45a318a146 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3876,6 +3876,7 @@ export default { is: 'EstΓ‘', pinned: 'Fijado', unread: 'No leΓ­do', + draft: 'Borrador', amount: { lessThan: (amount?: string) => `Menos de ${amount ?? ''}`, greaterThan: (amount?: string) => `MΓ‘s que ${amount ?? ''}`, diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 4d5393c23fa1..5f6f4033ea91 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -444,6 +444,8 @@ function getChatStatusTranslationKey(chatStatus: ValueOf Date: Wed, 4 Sep 2024 17:17:08 +0800 Subject: [PATCH 19/77] minor fix --- src/ROUTES.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 601cd5917c86..b49baac2e7c1 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -704,12 +704,19 @@ const ROUTES = { }, POLICY_ACCOUNTING: { route: 'settings/workspaces/:policyID/accounting', - getRoute: (policyID: string, newConnectionName?: ConnectionName, integrationToDisconnect?: ConnectionName, shouldDisconnectIntegrationBeforeConnecting?: boolean) => - `settings/workspaces/${policyID}/accounting${ - newConnectionName - ? `?newConnectionName=${newConnectionName}&integrationToDisconnect=${integrationToDisconnect}&shouldDisconnectIntegrationBeforeConnecting=${shouldDisconnectIntegrationBeforeConnecting}` - : '' - }` as const, + getRoute: (policyID: string, newConnectionName?: ConnectionName, integrationToDisconnect?: ConnectionName, shouldDisconnectIntegrationBeforeConnecting?: boolean) => { + let queryParams = ''; + if (newConnectionName) { + queryParams += `?newConnectionName=${newConnectionName}`; + if (integrationToDisconnect) { + queryParams += `&integrationToDisconnect=${integrationToDisconnect}`; + } + if (shouldDisconnectIntegrationBeforeConnecting !== undefined) { + queryParams += `&shouldDisconnectIntegrationBeforeConnecting=${shouldDisconnectIntegrationBeforeConnecting}`; + } + } + return `settings/workspaces/${policyID}/accounting${queryParams}` as const; + }, }, WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ADVANCED: { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/advanced', From aee068c15d11c92a0e9c8d004998ee89a2154234 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 4 Sep 2024 17:34:27 +0700 Subject: [PATCH 20/77] fix undefined is displayed for GL code --- src/pages/workspace/categories/ImportedCategoriesPage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/categories/ImportedCategoriesPage.tsx b/src/pages/workspace/categories/ImportedCategoriesPage.tsx index 585e5e2833ed..e0c59a6f4cd1 100644 --- a/src/pages/workspace/categories/ImportedCategoriesPage.tsx +++ b/src/pages/workspace/categories/ImportedCategoriesPage.tsx @@ -92,9 +92,11 @@ function ImportedCategoriesPage({route}: ImportedCategoriesPageProps) { name, enabled: categoriesEnabledColumn !== -1 ? categoriesEnabled?.[containsHeader ? index + 1 : index] === 'true' : true, // eslint-disable-next-line @typescript-eslint/naming-convention - 'GL Code': categoriesGLCodeColumn !== -1 ? categoriesGLCode?.[containsHeader ? index + 1 : index] : '', + 'GL Code': categoriesGLCodeColumn !== -1 ? categoriesGLCode?.[containsHeader ? index + 1 : index] ?? '' : '', })); + console.log(categories, typeof categoriesGLCode[3]); + if (categories) { setIsImportingCategories(true); importPolicyCategories(policyID, categories); From 8962c7f190d7f1e7e6e2477d35e594c64513341c Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 4 Sep 2024 17:55:15 +0700 Subject: [PATCH 21/77] remove log --- src/CONFIG.ts | 2 +- src/pages/workspace/categories/ImportedCategoriesPage.tsx | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/CONFIG.ts b/src/CONFIG.ts index a1a72b86fadd..047d4dc823fd 100644 --- a/src/CONFIG.ts +++ b/src/CONFIG.ts @@ -97,5 +97,5 @@ export default { }, GCP_GEOLOCATION_API_KEY: googleGeolocationAPIKey, // to read more about StrictMode see: contributingGuides/STRICT_MODE.md - USE_REACT_STRICT_MODE_IN_DEV: true, + USE_REACT_STRICT_MODE_IN_DEV: false, } as const; diff --git a/src/pages/workspace/categories/ImportedCategoriesPage.tsx b/src/pages/workspace/categories/ImportedCategoriesPage.tsx index e0c59a6f4cd1..6e5528afcad6 100644 --- a/src/pages/workspace/categories/ImportedCategoriesPage.tsx +++ b/src/pages/workspace/categories/ImportedCategoriesPage.tsx @@ -95,8 +95,6 @@ function ImportedCategoriesPage({route}: ImportedCategoriesPageProps) { 'GL Code': categoriesGLCodeColumn !== -1 ? categoriesGLCode?.[containsHeader ? index + 1 : index] ?? '' : '', })); - console.log(categories, typeof categoriesGLCode[3]); - if (categories) { setIsImportingCategories(true); importPolicyCategories(policyID, categories); From 6430995a82291283471ac954c61c85b5d7cb9b4f Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 4 Sep 2024 17:57:18 +0700 Subject: [PATCH 22/77] remove hard code --- src/CONFIG.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONFIG.ts b/src/CONFIG.ts index 047d4dc823fd..a1a72b86fadd 100644 --- a/src/CONFIG.ts +++ b/src/CONFIG.ts @@ -97,5 +97,5 @@ export default { }, GCP_GEOLOCATION_API_KEY: googleGeolocationAPIKey, // to read more about StrictMode see: contributingGuides/STRICT_MODE.md - USE_REACT_STRICT_MODE_IN_DEV: false, + USE_REACT_STRICT_MODE_IN_DEV: true, } as const; From b8f546cea8c7c823cd1ba2e3f06d9ef30fcb0a32 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Wed, 4 Sep 2024 19:12:31 +0530 Subject: [PATCH 23/77] fix: Dupe detection - 'Keep this one' button appears when there is a paid expense. Signed-off-by: krishna2323 --- .../MoneyRequestPreview/MoneyRequestPreviewContent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index 6ab1c0937278..f422269bfc69 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -136,7 +136,7 @@ function MoneyRequestPreviewContent({ const duplicates = useMemo(() => TransactionUtils.removeSettledAndApprovedTransactions(allDuplicates), [allDuplicates]); // When there are no settled transactions in duplicates, show the "Keep this one" button - const shouldShowKeepButton = allDuplicates.length === duplicates.length; + const shouldShowKeepButton = !!(allDuplicates.length && duplicates.length && allDuplicates.length === duplicates.length); const hasDuplicates = duplicates.length > 0; From b6e080760804939ede6d574262aa8a0a13ba9f16 Mon Sep 17 00:00:00 2001 From: kirillzyusko Date: Wed, 4 Sep 2024 15:46:33 +0200 Subject: [PATCH 24/77] e2e: migrate to specific host, don't use nvm --- tests/e2e/TestSpec.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/e2e/TestSpec.yml b/tests/e2e/TestSpec.yml index 277a4d1ef43b..563a7eb4ce0e 100644 --- a/tests/e2e/TestSpec.yml +++ b/tests/e2e/TestSpec.yml @@ -1,16 +1,15 @@ version: 0.1 +android_test_host: amazon_linux_2 + phases: install: commands: - # Install correct version of node - - export NVM_DIR=$HOME/.nvm - export FLASHLIGHT_BINARY_PATH=$DEVICEFARM_TEST_PACKAGE_PATH/zip/bin - - . $NVM_DIR/nvm.sh # Note: Node v16 is the latest supported version of node for AWS Device Farm # using v20 will not work! - - nvm install 16 - - nvm use --delete-prefix 16 + - devicefarm-cli use node 16 + - node -v # Reverse ports using AWS magic - PORT=4723 From f9fe23973c2c8203ac82d7419552fcca9cf2f786 Mon Sep 17 00:00:00 2001 From: Roji Philip Date: Wed, 4 Sep 2024 19:36:59 +0530 Subject: [PATCH 25/77] use card name from transaction --- src/components/EReceipt.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/EReceipt.tsx b/src/components/EReceipt.tsx index bfb59dc748ab..026713027f96 100644 --- a/src/components/EReceipt.tsx +++ b/src/components/EReceipt.tsx @@ -8,6 +8,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as CardUtils from '@libs/CardUtils'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as ReportUtils from '@libs/ReportUtils'; +import * as TransactionUtils from '@libs/TransactionUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -44,7 +45,7 @@ function EReceipt({transaction, transactionID}: EReceiptProps) { const formattedAmount = CurrencyUtils.convertToDisplayString(transactionAmount, transactionCurrency); const currency = CurrencyUtils.getCurrencySymbol(transactionCurrency ?? ''); const amount = currency ? formattedAmount.replace(currency, '') : formattedAmount; - const cardDescription = transactionCardID ? CardUtils.getCardDescription(transactionCardID) : ''; + const cardDescription = TransactionUtils.getCardName(transaction) ?? (transactionCardID ? CardUtils.getCardDescription(transactionCardID) : ''); const secondaryTextColorStyle = secondaryColor ? StyleUtils.getColorStyle(secondaryColor) : undefined; From 531033a30d1cf3adee9ec0055c2ab195a19eaefd Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Wed, 4 Sep 2024 21:21:33 +0700 Subject: [PATCH 26/77] add delegate avatar component --- .../home/sidebar/AvatarWithDelegateAvatar.tsx | 41 +++++++++++++++++++ src/pages/home/sidebar/BottomTabAvatar.tsx | 14 +++++++ 2 files changed, 55 insertions(+) create mode 100644 src/pages/home/sidebar/AvatarWithDelegateAvatar.tsx diff --git a/src/pages/home/sidebar/AvatarWithDelegateAvatar.tsx b/src/pages/home/sidebar/AvatarWithDelegateAvatar.tsx new file mode 100644 index 000000000000..a94af164d8fe --- /dev/null +++ b/src/pages/home/sidebar/AvatarWithDelegateAvatar.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import {View} from 'react-native'; +import Avatar from '@components/Avatar'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; +import * as UserUtils from '@libs/UserUtils'; +import CONST from '@src/CONST'; +import ProfileAvatarWithIndicator from './ProfileAvatarWithIndicator'; + +type AvatarWithDelegateAvatarProps = { + /** Emoji status */ + delegateEmail: string; + + /** Whether the avatar is selected */ + isSelected?: boolean; +}; + +function AvatarWithDelegateAvatar({delegateEmail, isSelected = false}: AvatarWithDelegateAvatarProps) { + const styles = useThemeStyles(); + const personalDetail = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + + return ( + + + + + + + + + ); +} + +AvatarWithDelegateAvatar.displayName = 'AvatarWithDelegateAvatar'; + +export default AvatarWithDelegateAvatar; diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index c928fdbc7dd8..d015480fbf08 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -1,4 +1,5 @@ import React, {useCallback} from 'react'; +import {useOnyx} from 'react-native-onyx'; import {PressableWithFeedback} from '@components/Pressable'; import Tooltip from '@components/Tooltip'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; @@ -7,7 +8,9 @@ import useThemeStyles from '@hooks/useThemeStyles'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import AvatarWithDelegateAvatar from './AvatarWithDelegateAvatar'; import AvatarWithOptionalStatus from './AvatarWithOptionalStatus'; import ProfileAvatarWithIndicator from './ProfileAvatarWithIndicator'; @@ -22,6 +25,8 @@ type BottomTabAvatarProps = { function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomTabAvatarProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const delegateEmail = account?.delegatedAccess?.delegate ?? ''; const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const emojiStatus = currentUserPersonalDetails?.status?.emojiCode ?? ''; @@ -36,6 +41,15 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT let children; + if (delegateEmail) { + children = ( + + ); + } + if (emojiStatus) { children = ( Date: Wed, 4 Sep 2024 21:24:19 +0700 Subject: [PATCH 27/77] update logic --- src/pages/home/sidebar/BottomTabAvatar.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index d015480fbf08..0a798389517b 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -48,9 +48,7 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT isSelected={isSelected} /> ); - } - - if (emojiStatus) { + } else if (emojiStatus) { children = ( Date: Wed, 4 Sep 2024 23:39:57 +0800 Subject: [PATCH 28/77] fix icon is cut-off --- .../approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx | 1 + .../approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index 9daf6a6a41eb..d34b9d59891f 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -240,6 +240,7 @@ function WorkspaceWorkflowsApprovalsApproverPageBeta({policy, personalDetails, i subtitle={translate('workflowsPage.emptyContent.approverSubtitle')} subtitleStyle={styles.textSupporting} containerStyle={styles.pb10} + contentFitImage='contain' /> ), [translate, styles.textSupporting, styles.pb10], diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx index 003c7eb00e36..5a35ec7c710a 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx @@ -188,6 +188,7 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat subtitle={translate('workflowsPage.emptyContent.expensesFromSubtitle')} subtitleStyle={styles.textSupporting} containerStyle={styles.pb10} + contentFitImage='contain' /> ), [translate, styles.textSupporting, styles.pb10], From 9c83581ee8190f894c657fa853c53ac34f551fa5 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 5 Sep 2024 00:01:30 +0800 Subject: [PATCH 29/77] bold list item title by default --- src/libs/OptionsListUtils.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index acc9d4bdefc5..a32a8f0be5ff 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -177,6 +177,7 @@ type GetOptionsConfig = { includeInvoiceRooms?: boolean; includeDomainEmail?: boolean; action?: IOUAction; + shouldBoldTitleByDefault?: boolean; }; type GetUserToInviteConfig = { @@ -1743,6 +1744,7 @@ function getOptions( includeInvoiceRooms = false, includeDomainEmail = false, action, + shouldBoldTitleByDefault = true, }: GetOptionsConfig, ): Options { if (includeCategories) { @@ -1967,7 +1969,7 @@ function getOptions( } reportOption.isSelected = isReportSelected(reportOption, selectedOptions); - reportOption.isBold = shouldUseBoldText(reportOption); + reportOption.isBold = shouldBoldTitleByDefault || shouldUseBoldText(reportOption); if (action === CONST.IOU.ACTION.CATEGORIZE) { const policyCategories = allPolicyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${reportOption.policyID}`] ?? {}; @@ -1991,7 +1993,7 @@ function getOptions( if (personalDetailsOptionsToExclude.some((optionToExclude) => optionToExclude.login === personalDetailOption.login)) { continue; } - personalDetailOption.isBold = shouldUseBoldText(personalDetailOption); + personalDetailOption.isBold = shouldBoldTitleByDefault; personalDetailsOptions.push(personalDetailOption); } @@ -2061,6 +2063,7 @@ function getSearchOptions(options: OptionList, searchValue = '', betas: Beta[] = includeMoneyRequests: true, includeTasks: true, includeSelfDM: true, + shouldBoldTitleByDefault: false, }); Timing.end(CONST.TIMING.LOAD_SEARCH_OPTIONS); Performance.markEnd(CONST.TIMING.LOAD_SEARCH_OPTIONS); From 6f0c0b3c7bb16bf685f99d13806b3d2daa585ec9 Mon Sep 17 00:00:00 2001 From: mkzie2 Date: Wed, 4 Sep 2024 23:04:49 +0700 Subject: [PATCH 30/77] fix: create object uri for import spreadsheets --- src/components/ImportSpreadsheet.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/ImportSpreadsheet.tsx b/src/components/ImportSpreadsheet.tsx index 76918982652d..044a28fc6e4b 100644 --- a/src/components/ImportSpreadsheet.tsx +++ b/src/components/ImportSpreadsheet.tsx @@ -75,6 +75,7 @@ function ImportSpreedsheet({backTo, goTo}: ImportSpreedsheetProps) { if (!validateFile(file)) { return; } + file.uri = URL.createObjectURL(file); if (!file.uri) { return; } @@ -98,6 +99,9 @@ function ImportSpreedsheet({backTo, goTo}: ImportSpreedsheetProps) { }) .finally(() => { setIsReadingFIle(false); + if (file.uri) { + URL.revokeObjectURL(file.uri); + } }); }; From 4f6c2fd4c727dbcaf8008498c81d6acabccfa51e Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Thu, 5 Sep 2024 00:14:31 +0800 Subject: [PATCH 31/77] lint --- .../approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx | 2 +- .../approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index d34b9d59891f..b46b7e1697ee 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -240,7 +240,7 @@ function WorkspaceWorkflowsApprovalsApproverPageBeta({policy, personalDetails, i subtitle={translate('workflowsPage.emptyContent.approverSubtitle')} subtitleStyle={styles.textSupporting} containerStyle={styles.pb10} - contentFitImage='contain' + contentFitImage="contain" /> ), [translate, styles.textSupporting, styles.pb10], diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx index 5a35ec7c710a..2c69f07ef83b 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx @@ -188,7 +188,7 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat subtitle={translate('workflowsPage.emptyContent.expensesFromSubtitle')} subtitleStyle={styles.textSupporting} containerStyle={styles.pb10} - contentFitImage='contain' + contentFitImage="contain" /> ), [translate, styles.textSupporting, styles.pb10], From e059c00695bcf44ef8eda4364b1ef2229b32ee6a Mon Sep 17 00:00:00 2001 From: mkzie2 Date: Wed, 4 Sep 2024 23:16:39 +0700 Subject: [PATCH 32/77] update text color --- src/components/ImportSpreadsheet.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ImportSpreadsheet.tsx b/src/components/ImportSpreadsheet.tsx index 044a28fc6e4b..b441ff9f867c 100644 --- a/src/components/ImportSpreadsheet.tsx +++ b/src/components/ImportSpreadsheet.tsx @@ -189,7 +189,7 @@ function ImportSpreedsheet({backTo, goTo}: ImportSpreedsheetProps) { height={CONST.IMPORT_SPREADSHEET.ICON_HEIGHT} /> {translate('common.dropTitle')} - {translate('common.dropMessage')} + {translate('common.dropMessage')} From 1c1b5da9bf65bdf1fea9fcea0c00ca88389409e7 Mon Sep 17 00:00:00 2001 From: mkzie2 Date: Wed, 4 Sep 2024 23:46:11 +0700 Subject: [PATCH 33/77] fix lint --- src/components/ImportSpreadsheet.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/ImportSpreadsheet.tsx b/src/components/ImportSpreadsheet.tsx index b441ff9f867c..0b636804d3ab 100644 --- a/src/components/ImportSpreadsheet.tsx +++ b/src/components/ImportSpreadsheet.tsx @@ -75,16 +75,15 @@ function ImportSpreedsheet({backTo, goTo}: ImportSpreedsheetProps) { if (!validateFile(file)) { return; } - file.uri = URL.createObjectURL(file); - if (!file.uri) { + let fileURI = file.uri || URL.createObjectURL(file); + if (!fileURI) { return; } - let filePath = file.uri; if (Platform.OS === 'ios') { - filePath = filePath.replace(/^.*\/Documents\//, `${RNFetchBlob.fs.dirs.DocumentDir}/`); + fileURI = fileURI.replace(/^.*\/Documents\//, `${RNFetchBlob.fs.dirs.DocumentDir}/`); } - fetch(filePath) + fetch(fileURI) .then((data) => { setIsReadingFIle(true); return data.arrayBuffer(); @@ -99,8 +98,8 @@ function ImportSpreedsheet({backTo, goTo}: ImportSpreedsheetProps) { }) .finally(() => { setIsReadingFIle(false); - if (file.uri) { - URL.revokeObjectURL(file.uri); + if (fileURI && !file.uri) { + URL.revokeObjectURL(fileURI); } }); }; From 37694a34cc91a87c463973ecaffe5f7000ea5da6 Mon Sep 17 00:00:00 2001 From: mkzie2 Date: Wed, 4 Sep 2024 23:57:29 +0700 Subject: [PATCH 34/77] use nullish coalescing --- src/components/ImportSpreadsheet.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ImportSpreadsheet.tsx b/src/components/ImportSpreadsheet.tsx index 0b636804d3ab..2ce31be701db 100644 --- a/src/components/ImportSpreadsheet.tsx +++ b/src/components/ImportSpreadsheet.tsx @@ -75,7 +75,7 @@ function ImportSpreedsheet({backTo, goTo}: ImportSpreedsheetProps) { if (!validateFile(file)) { return; } - let fileURI = file.uri || URL.createObjectURL(file); + let fileURI = file.uri ?? URL.createObjectURL(file); if (!fileURI) { return; } From a3782805eb8e8c9fcee3519b9cfd4041c1f5ad61 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 5 Sep 2024 01:30:20 +0700 Subject: [PATCH 35/77] fix app crash when clicking on got it button --- src/components/ImportColumn.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ImportColumn.tsx b/src/components/ImportColumn.tsx index f25082f94474..0693a6be65cb 100644 --- a/src/components/ImportColumn.tsx +++ b/src/components/ImportColumn.tsx @@ -156,7 +156,7 @@ function ImportColumn({column, columnName, columnRoles, columnIndex}: ImportColu text: item.text, value: item.value, description: item.description ?? (item.isRequired ? translate('common.required') : undefined), - isSelected: spreadsheet?.columns[columnIndex] === item.value, + isSelected: spreadsheet?.columns?.[columnIndex] === item.value, })); const columnValuesString = column.slice(containsHeader ? 1 : 0).join(', '); @@ -176,7 +176,7 @@ function ImportColumn({column, columnName, columnRoles, columnIndex}: ImportColu return ( - {columnHeader} + {columnHeader} Date: Wed, 4 Sep 2024 13:29:30 -0700 Subject: [PATCH 36/77] Create all onboarding tasks with Concierge --- src/libs/actions/Report.ts | 23 ++----------------- .../BaseOnboardingPersonalDetails.tsx | 6 +---- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index bd31d3832605..1f87c65fcf84 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2164,17 +2164,6 @@ function navigateToConciergeChat(shouldDismissModal = false, checkIfCurrentPageA } } -/** - * Navigates to the 1:1 system chat - */ -function navigateToSystemChat() { - const systemChatReport = ReportUtils.getSystemChat(); - - if (systemChatReport?.reportID) { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(systemChatReport.reportID)); - } -} - /** Add a policy report (workspace room) optimistically and navigate to it. */ function addPolicyReport(policyReport: ReportUtils.OptimisticChatReport) { const createdReportAction = ReportUtils.buildOptimisticCreatedReportAction(CONST.POLICY.OWNER_EMAIL_FAKE); @@ -3329,13 +3318,7 @@ function completeOnboarding( adminsChatReportID?: string, onboardingPolicyID?: string, ) { - const isAccountIDOdd = AccountUtils.isAccountIDOddNumber(currentUserAccountID ?? 0); - const targetEmail = isAccountIDOdd ? CONST.EMAIL.NOTIFICATIONS : CONST.EMAIL.CONCIERGE; - - // If the target report isn't opened, the permission field will not exist. So we should add the fallback permission for task report - const fallbackPermission = isAccountIDOdd ? [CONST.REPORT.PERMISSIONS.READ] : [CONST.REPORT.PERMISSIONS.READ, CONST.REPORT.PERMISSIONS.WRITE]; - - const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; + const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE])[0]; const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID, currentUserAccountID]); const {reportID: targetChatReportID = '', policyID: targetChatPolicyID = ''} = targetChatReport ?? {}; @@ -3386,7 +3369,7 @@ function completeOnboarding( targetChatPolicyID, CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, ); - const taskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(targetEmail); + const taskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(CONST.EMAIL.CONCIERGE); const taskReportAction = ReportUtils.buildOptimisticTaskCommentReportAction( currentTask.reportID, task.title, @@ -3450,7 +3433,6 @@ function completeOnboarding( }, isOptimisticReport: true, managerID: currentUserAccountID, - permissions: targetChatReport?.permissions ?? fallbackPermission, }, }, { @@ -4109,7 +4091,6 @@ export { saveReportActionDraft, deleteReportComment, navigateToConciergeChat, - navigateToSystemChat, addPolicyReport, deleteReport, navigateToConciergeChatAndDeleteReport, diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index d2dbd7eff953..c5dab0f8a247 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -76,11 +76,7 @@ function BaseOnboardingPersonalDetails({ // Only navigate to concierge chat when central pane is visible // Otherwise stay on the chats screen. if (!shouldUseNarrowLayout && !route.params?.backTo) { - if (AccountUtils.isAccountIDOddNumber(accountID ?? 0)) { - Report.navigateToSystemChat(); - } else { - Report.navigateToConciergeChat(); - } + Report.navigateToConciergeChat(); } }, [onboardingPurposeSelected, onboardingAdminsChatReportID, onboardingPolicyID, shouldUseNarrowLayout, route.params?.backTo, accountID], From 0e704458c5c42c4b32d6d4d9374e6a8f3c3ea1d5 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Wed, 4 Sep 2024 13:40:00 -0700 Subject: [PATCH 37/77] Remove unused dep, use Concierge ID directly --- src/libs/actions/Report.ts | 3 +-- .../BaseOnboardingPersonalDetails.tsx | 5 +---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 1f87c65fcf84..6958e4d84426 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -8,7 +8,6 @@ import Onyx from 'react-native-onyx'; import type {PartialDeep, ValueOf} from 'type-fest'; import type {Emoji} from '@assets/emojis/types'; import type {FileObject} from '@components/AttachmentModal'; -import AccountUtils from '@libs/AccountUtils'; import * as ActiveClientManager from '@libs/ActiveClientManager'; import * as API from '@libs/API'; import type { @@ -3318,7 +3317,7 @@ function completeOnboarding( adminsChatReportID?: string, onboardingPolicyID?: string, ) { - const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE])[0]; + const actorAccountID = CONST.ACCOUNT_ID.CONCIERGE; const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID, currentUserAccountID]); const {reportID: targetChatReportID = '', policyID: targetChatPolicyID = ''} = targetChatReport ?? {}; diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index c5dab0f8a247..4579059c23bc 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -6,7 +6,6 @@ import InputWrapper from '@components/Form/InputWrapper'; import type {FormOnyxValues} from '@components/Form/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import OfflineIndicator from '@components/OfflineIndicator'; -import {useSession} from '@components/OnyxProvider'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; @@ -15,7 +14,6 @@ import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import AccountUtils from '@libs/AccountUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ValidationUtils from '@libs/ValidationUtils'; @@ -40,7 +38,6 @@ function BaseOnboardingPersonalDetails({ const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout(); const {inputCallbackRef} = useAutoFocusInput(); const [shouldValidateOnChange, setShouldValidateOnChange] = useState(false); - const {accountID} = useSession(); useEffect(() => { Welcome.setOnboardingErrorMessage(''); @@ -79,7 +76,7 @@ function BaseOnboardingPersonalDetails({ Report.navigateToConciergeChat(); } }, - [onboardingPurposeSelected, onboardingAdminsChatReportID, onboardingPolicyID, shouldUseNarrowLayout, route.params?.backTo, accountID], + [onboardingPurposeSelected, onboardingAdminsChatReportID, onboardingPolicyID, shouldUseNarrowLayout, route.params?.backTo], ); const validate = (values: FormOnyxValues<'onboardingPersonalDetailsForm'>) => { From 891c6ec154ad727d5fe5d50970640f4a92747b98 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Wed, 4 Sep 2024 14:49:20 -0700 Subject: [PATCH 38/77] Don't show Expensify DM in background behind modal , update docs --- src/libs/ReportUtils.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7b226b2e5c8e..990b83ff2a38 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -55,7 +55,6 @@ import type {Message, ReportActions} from '@src/types/onyx/ReportAction'; import type {Comment, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; -import AccountUtils from './AccountUtils'; import * as IOU from './actions/IOU'; import * as PolicyActions from './actions/Policy/Policy'; import * as store from './actions/ReimbursementAccount/store'; @@ -5981,7 +5980,10 @@ function shouldReportBeInOptionList({ return false; } - if (report?.participants?.[CONST.ACCOUNT_ID.NOTIFICATIONS] && (!currentUserAccountID || !AccountUtils.isAccountIDOddNumber(currentUserAccountID))) { + // We used to use the system DM for A/B testing onboarding tasks, but now only create them in the Concierge chat. We + // still need to allow existing users who have tasks in the system DM to see them, but otherwise we don't need to + // show that chat + if (report?.participants?.[CONST.ACCOUNT_ID.NOTIFICATIONS] && isEmptyReport(report)) { return false; } @@ -7619,8 +7621,9 @@ function shouldShowMerchantColumn(transactions: Transaction[]) { } /** - * Whether the report is a system chat or concierge chat, depending on the onboarding report ID or fallbacking - * to the user's account ID (used for A/B testing purposes). + * Whether a given report is used for onboarding tasks. In the past, it could be either the Concierge chat or the system + * DM, and we saved the report ID in the user's `onboarding` NVP. As a fallback for users who don't have the NVP, we now + * only use the Concierge chat. */ function isChatUsedForOnboarding(optionOrReport: OnyxEntry | OptionData): boolean { // onboarding can be an array for old accounts and accounts created from olddot @@ -7628,13 +7631,12 @@ function isChatUsedForOnboarding(optionOrReport: OnyxEntry | OptionData) return onboarding.chatReportID === optionOrReport?.reportID; } - return AccountUtils.isAccountIDOddNumber(currentUserAccountID ?? -1) - ? isSystemChat(optionOrReport) - : (optionOrReport as OptionData)?.isConciergeChat ?? isConciergeChatReport(optionOrReport); + return (optionOrReport as OptionData)?.isConciergeChat ?? isConciergeChatReport(optionOrReport); } /** - * Get the report (system or concierge chat) used for the user's onboarding process. + * Get the report used for the user's onboarding process. For most users it is the Concierge chat, however in the past + * we also used the system DM for A/B tests. */ function getChatUsedForOnboarding(): OnyxEntry { return Object.values(ReportConnection.getAllReports() ?? {}).find(isChatUsedForOnboarding); From 6931e93fb6f9677e599227e0f733a24c6924bf02 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Wed, 4 Sep 2024 15:12:14 -0700 Subject: [PATCH 39/77] Fix unit tests --- tests/unit/ReportUtilsTest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 6161fa57f75c..bdff4323579f 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -884,7 +884,7 @@ describe('ReportUtils', () => { expect(ReportUtils.isChatUsedForOnboarding(LHNTestUtils.getFakeReport())).toBeFalsy(); }); - it('should return true if the user account ID is odd and report is the system chat', async () => { + it('should return false if the user account ID is odd and report is the system chat - only the Concierge chat chat should be the onboarding chat for users without the onboarding NVP', async () => { const accountID = 1; await Onyx.multiSet({ @@ -901,7 +901,7 @@ describe('ReportUtils', () => { chatType: CONST.REPORT.CHAT_TYPE.SYSTEM, }; - expect(ReportUtils.isChatUsedForOnboarding(report)).toBeTruthy(); + expect(ReportUtils.isChatUsedForOnboarding(report)).toBeFalsy(); }); it('should return true if the user account ID is even and report is the concierge chat', async () => { From d439bedb97391381c9ed2def9d48fe4e5a550cec Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 5 Sep 2024 07:23:41 +0700 Subject: [PATCH 40/77] merge main --- src/components/ImportColumn.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ImportColumn.tsx b/src/components/ImportColumn.tsx index 0693a6be65cb..6ede4ed490b0 100644 --- a/src/components/ImportColumn.tsx +++ b/src/components/ImportColumn.tsx @@ -176,7 +176,7 @@ function ImportColumn({column, columnName, columnRoles, columnIndex}: ImportColu return ( - {columnHeader} + {columnHeader} Date: Thu, 5 Sep 2024 12:15:04 +0800 Subject: [PATCH 41/77] minor fix on integrationData --- src/pages/workspace/accounting/PolicyAccountingPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index c6ee182d388f..a8ca3fc2054f 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -253,7 +253,7 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) { } const shouldShowSynchronizationError = !!synchronizationError; const shouldHideConfigurationOptions = isConnectionUnverified(policy, connectedIntegration); - const integrationData = getAccountingIntegrationData(connectedIntegration, policyID, translate, policy, undefined, canUseNetSuiteUSATax); + const integrationData = getAccountingIntegrationData(connectedIntegration, policyID, translate, policy, undefined, undefined, undefined, canUseNetSuiteUSATax); const iconProps = integrationData?.icon ? {icon: integrationData.icon, iconType: CONST.ICON_TYPE_AVATAR} : {}; const configurationOptions = [ From 7538aef71c77990902be08e12bdca68e60120644 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 5 Sep 2024 11:39:51 +0700 Subject: [PATCH 42/77] fix loading bug --- src/pages/home/sidebar/AvatarWithDelegateAvatar.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pages/home/sidebar/AvatarWithDelegateAvatar.tsx b/src/pages/home/sidebar/AvatarWithDelegateAvatar.tsx index a94af164d8fe..0192d3d8423a 100644 --- a/src/pages/home/sidebar/AvatarWithDelegateAvatar.tsx +++ b/src/pages/home/sidebar/AvatarWithDelegateAvatar.tsx @@ -1,10 +1,11 @@ import React from 'react'; import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import Avatar from '@components/Avatar'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as UserUtils from '@libs/UserUtils'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ProfileAvatarWithIndicator from './ProfileAvatarWithIndicator'; type AvatarWithDelegateAvatarProps = { @@ -17,7 +18,8 @@ type AvatarWithDelegateAvatarProps = { function AvatarWithDelegateAvatar({delegateEmail, isSelected = false}: AvatarWithDelegateAvatarProps) { const styles = useThemeStyles(); - const personalDetail = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail); + const personalDetails = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); + const delegatePersonalDetail = Object.values(personalDetails[0] ?? {}).find((personalDetail) => personalDetail?.login?.toLowerCase() === delegateEmail); return ( @@ -26,8 +28,8 @@ function AvatarWithDelegateAvatar({delegateEmail, isSelected = false}: AvatarWit From aa8e514133d0cd085fb114fec2e8bed34a6427ed Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 5 Sep 2024 11:36:57 +0530 Subject: [PATCH 43/77] fix: Tags - App closes RHP after upgrade and clicking back button in GL code page. Signed-off-by: krishna2323 --- src/pages/workspace/tags/TagGLCodePage.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/tags/TagGLCodePage.tsx b/src/pages/workspace/tags/TagGLCodePage.tsx index 54e5c034ca07..89c281e91f4d 100644 --- a/src/pages/workspace/tags/TagGLCodePage.tsx +++ b/src/pages/workspace/tags/TagGLCodePage.tsx @@ -40,15 +40,19 @@ function TagGLCodePage({route, policyTags}: EditTagGLCodePageProps) { const {tags} = PolicyUtils.getTagList(policyTags, orderWeight); const glCode = tags?.[route.params.tagName]?.['GL Code']; + const goBack = useCallback(() => { + Navigation.goBack(ROUTES.WORKSPACE_TAG_SETTINGS.getRoute(route.params.policyID, orderWeight, tagName)); + }, [orderWeight, route.params.policyID, tagName]); + const editGLCode = useCallback( (values: FormOnyxValues) => { const newGLCode = values.glCode.trim(); if (newGLCode !== glCode) { Tag.setPolicyTagGLCode(route.params.policyID, tagName, orderWeight, newGLCode); } - Navigation.goBack(ROUTES.WORKSPACE_TAG_SETTINGS.getRoute(route.params.policyID, orderWeight, tagName)); + goBack(); }, - [glCode, route.params.policyID, tagName, orderWeight], + [glCode, route.params.policyID, tagName, orderWeight, goBack], ); return ( @@ -65,7 +69,7 @@ function TagGLCodePage({route, policyTags}: EditTagGLCodePageProps) { > Navigation.goBack()} + onBackButtonPress={goBack} /> Date: Thu, 5 Sep 2024 07:39:18 +0000 Subject: [PATCH 44/77] Update version to 9.0.29-7 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 4b1fb7ae40cf..b73fab33e2dc 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009002906 - versionName "9.0.29-6" + versionCode 1009002907 + versionName "9.0.29-7" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index f676f248fb8c..0f50b67d53d0 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.29.6 + 9.0.29.7 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 5eb312548f35..792f51893136 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.29.6 + 9.0.29.7 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index c13e6f18dc1e..f6f256ca576c 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.29 CFBundleVersion - 9.0.29.6 + 9.0.29.7 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index e46eb0494ea7..3d85c024edf3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.29-6", + "version": "9.0.29-7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.29-6", + "version": "9.0.29-7", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index b36985b72631..87a07fc3ca15 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.29-6", + "version": "9.0.29-7", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 5050319c11899a7e29d43e31980f1bb1e090a7da Mon Sep 17 00:00:00 2001 From: Ishpaul Singh Date: Thu, 5 Sep 2024 15:31:34 +0530 Subject: [PATCH 45/77] fixes the issue --- .../categories/ImportedCategoriesPage.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/pages/workspace/categories/ImportedCategoriesPage.tsx b/src/pages/workspace/categories/ImportedCategoriesPage.tsx index 585e5e2833ed..b2485ecc083b 100644 --- a/src/pages/workspace/categories/ImportedCategoriesPage.tsx +++ b/src/pages/workspace/categories/ImportedCategoriesPage.tsx @@ -28,6 +28,7 @@ function ImportedCategoriesPage({route}: ImportedCategoriesPageProps) { const {containsHeader} = spreadsheet ?? {}; const [isValidationEnabled, setIsValidationEnabled] = useState(false); const policyID = route.params.policyID; + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); const policy = usePolicy(policyID); const columnNames = generateColumnNames(spreadsheet?.data?.length ?? 0); @@ -88,18 +89,22 @@ function ImportedCategoriesPage({route}: ImportedCategoriesPageProps) { const categoriesNames = spreadsheet?.data[categoriesNamesColumn].map((name) => name); const categoriesEnabled = categoriesEnabledColumn !== -1 ? spreadsheet?.data[categoriesEnabledColumn].map((enabled) => enabled) : []; const categoriesGLCode = categoriesGLCodeColumn !== -1 ? spreadsheet?.data[categoriesGLCodeColumn].map((glCode) => glCode) : []; - const categories = categoriesNames?.slice(containsHeader ? 1 : 0).map((name, index) => ({ - name, - enabled: categoriesEnabledColumn !== -1 ? categoriesEnabled?.[containsHeader ? index + 1 : index] === 'true' : true, - // eslint-disable-next-line @typescript-eslint/naming-convention - 'GL Code': categoriesGLCodeColumn !== -1 ? categoriesGLCode?.[containsHeader ? index + 1 : index] : '', - })); + const categories = categoriesNames?.slice(containsHeader ? 1 : 0).map((name, index) => { + const categoryAlreadyExists = policyCategories?.[name]; + const existingGLCodeOrDefault = categoryAlreadyExists?.['GL Code'] ?? ''; + return { + name, + enabled: categoriesEnabledColumn !== -1 ? categoriesEnabled?.[containsHeader ? index + 1 : index] === 'true' : true, + // eslint-disable-next-line @typescript-eslint/naming-convention + 'GL Code': categoriesGLCodeColumn !== -1 ? categoriesGLCode?.[containsHeader ? index + 1 : index] : existingGLCodeOrDefault, + }; + }); if (categories) { setIsImportingCategories(true); importPolicyCategories(policyID, categories); } - }, [validate, spreadsheet, containsHeader, policyID]); + }, [validate, spreadsheet, containsHeader, policyID, policyCategories]); const spreadsheetColumns = spreadsheet?.data; if (!spreadsheetColumns) { From 5a88297d21529e063bf11f76edbc6149a3983a7f Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 5 Sep 2024 10:34:25 +0000 Subject: [PATCH 46/77] Update version to 9.0.29-8 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index b73fab33e2dc..f829e726fbf9 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009002907 - versionName "9.0.29-7" + versionCode 1009002908 + versionName "9.0.29-8" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 0f50b67d53d0..8f33c608b9e9 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.29.7 + 9.0.29.8 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 792f51893136..5199100b8972 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.29.7 + 9.0.29.8 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index f6f256ca576c..27bbfd89c73f 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.29 CFBundleVersion - 9.0.29.7 + 9.0.29.8 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 3d85c024edf3..9eefe3dc7ecb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.29-7", + "version": "9.0.29-8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.29-7", + "version": "9.0.29-8", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 87a07fc3ca15..778008e678e6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.29-7", + "version": "9.0.29-8", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From a6e6ae67e04b80b8a245503fbef945e48ceb53c4 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 5 Sep 2024 10:58:13 +0000 Subject: [PATCH 47/77] Update version to 9.0.29-9 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index f829e726fbf9..c03948c3c42e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009002908 - versionName "9.0.29-8" + versionCode 1009002909 + versionName "9.0.29-9" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 8f33c608b9e9..dbcc744d94b0 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.29.8 + 9.0.29.9 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 5199100b8972..9f1147d9e0db 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.29.8 + 9.0.29.9 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 27bbfd89c73f..59eb7d9727eb 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.29 CFBundleVersion - 9.0.29.8 + 9.0.29.9 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 9eefe3dc7ecb..3935090b322a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.29-8", + "version": "9.0.29-9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.29-8", + "version": "9.0.29-9", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 778008e678e6..b9039a4f08f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.29-8", + "version": "9.0.29-9", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From d856478a5e8e1923bf3a8bd50b60fa85248c1284 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:13:20 +0100 Subject: [PATCH 48/77] copy jobs from platformDeploy.yml to deploy.yml --- .github/workflows/deploy.yml | 480 +++++++++++++++++++++++++++++++++++ 1 file changed, 480 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6b1b72f1f901..efa069782078 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -4,7 +4,487 @@ on: push: branches: [staging, production] +env: + SHOULD_DEPLOY_PRODUCTION: ${{ github.event.action == 'released' }} + +concurrency: + group: ${{ github.workflow }}-${{ github.event.action }} + cancel-in-progress: true + jobs: + validateActor: + runs-on: ubuntu-latest + outputs: + IS_DEPLOYER: ${{ fromJSON(steps.isUserDeployer.outputs.IS_DEPLOYER) || github.actor == 'OSBotify' || github.actor == 'os-botify[bot]' }} + steps: + - name: Check if user is deployer + id: isUserDeployer + run: | + if gh api /orgs/Expensify/teams/mobile-deployers/memberships/${{ github.actor }} --silent; then + echo "IS_DEPLOYER=true" >> "$GITHUB_OUTPUT" + else + echo "IS_DEPLOYER=false" >> "$GITHUB_OUTPUT" + fi + env: + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} + + # Note: we're updating the checklist before running the deploys and assuming that it will succeed on at least one platform + deployChecklist: + name: Create or update deploy checklist + uses: ./.github/workflows/createDeployChecklist.yml + if: ${{ github.event.action != 'released' }} + needs: validateActor + secrets: inherit + + android: + # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly + name: Build and deploy Android + needs: validateActor + if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} + runs-on: ubuntu-latest-xl + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Configure MapBox SDK + run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} + + - name: Setup Node + uses: ./.github/actions/composite/setupNode + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'oracle' + java-version: '17' + + - name: Setup Ruby + uses: ruby/setup-ruby@v1.190.0 + with: + bundler-cache: true + + - name: Decrypt keystore + run: cd android/app && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output my-upload-key.keystore my-upload-key.keystore.gpg + env: + LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} + + - name: Decrypt json key + run: cd android/app && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output android-fastlane-json-key.json android-fastlane-json-key.json.gpg + env: + LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} + + - name: Set version in ENV + run: echo "VERSION_CODE=$(grep -o 'versionCode\s\+[0-9]\+' android/app/build.gradle | awk '{ print $2 }')" >> "$GITHUB_ENV" + + - name: Run Fastlane + run: bundle exec fastlane android ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'beta' }} + env: + RUBYOPT: '-rostruct' + MYAPP_UPLOAD_STORE_PASSWORD: ${{ secrets.MYAPP_UPLOAD_STORE_PASSWORD }} + MYAPP_UPLOAD_KEY_PASSWORD: ${{ secrets.MYAPP_UPLOAD_KEY_PASSWORD }} + VERSION: ${{ env.VERSION_CODE }} + + - name: Upload Android build to Browser Stack + if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + run: curl -u "$BROWSERSTACK" -X POST "https://api-cloud.browserstack.com/app-live/upload" -F "file=@./android/app/build/outputs/bundle/productionRelease/app-production-release.aab" + env: + BROWSERSTACK: ${{ secrets.BROWSERSTACK }} + + - name: Upload Android sourcemaps to GitHub Release + if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + run: gh release upload ${{ github.event.release.tag_name }} android/app/build/generated/sourcemaps/react/productionRelease/index.android.bundle.map#android-sourcemap-${{ github.event.release.tag_name }} + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload Android build to GitHub Release + if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + run: gh release upload ${{ github.event.release.tag_name }} android/app/build/outputs/bundle/productionRelease/app-production-release.aab + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Warn deployers if Android production deploy failed + if: ${{ failure() && fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + uses: 8398a7/action-slack@v3 + with: + status: custom + custom_payload: | + { + channel: '#deployer', + attachments: [{ + color: "#DB4545", + pretext: ``, + text: `πŸ’₯ Android production deploy failed. Please manually submit ${{ github.event.release.tag_name }} in the . πŸ’₯`, + }] + } + env: + GITHUB_TOKEN: ${{ github.token }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + desktop: + # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly + name: Build and deploy Desktop + needs: validateActor + if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} + runs-on: macos-14-large + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: ./.github/actions/composite/setupNode + + - name: Decrypt Developer ID Certificate + run: cd desktop && gpg --quiet --batch --yes --decrypt --passphrase="$DEVELOPER_ID_SECRET_PASSPHRASE" --output developer_id.p12 developer_id.p12.gpg + env: + DEVELOPER_ID_SECRET_PASSPHRASE: ${{ secrets.DEVELOPER_ID_SECRET_PASSPHRASE }} + + - name: Build desktop app + run: | + if [[ ${{ env.SHOULD_DEPLOY_PRODUCTION }} == 'true' ]]; then + npm run desktop-build + else + npm run desktop-build-staging + fi + env: + CSC_LINK: ${{ secrets.CSC_LINK }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + GCP_GEOLOCATION_API_KEY: $${{ secrets.GCP_GEOLOCATION_API_KEY_PRODUCTION }} + + - name: Upload desktop sourcemaps to GitHub Release + run: gh release upload ${{ github.event.release.tag_name }} desktop/dist/www/merged-source-map.js.map#desktop-sourcemap-${{ github.event.release.tag_name }} --clobber + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload desktop build to GitHub Release + run: gh release upload ${{ github.event.release.tag_name }} desktop-build/NewExpensify.dmg --clobber + env: + GITHUB_TOKEN: ${{ github.token }} + + iOS: + # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly + name: Build and deploy iOS + needs: validateActor + if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} + env: + DEVELOPER_DIR: /Applications/Xcode_15.2.0.app/Contents/Developer + runs-on: macos-13-xlarge + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Configure MapBox SDK + run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} + + - name: Setup Node + id: setup-node + uses: ./.github/actions/composite/setupNode + + - name: Setup Ruby + uses: ruby/setup-ruby@v1.190.0 + with: + bundler-cache: true + + - name: Cache Pod dependencies + uses: actions/cache@v4 + id: pods-cache + with: + path: ios/Pods + key: ${{ runner.os }}-pods-cache-${{ hashFiles('ios/Podfile.lock', 'firebase.json') }} + + - name: Compare Podfile.lock and Manifest.lock + id: compare-podfile-and-manifest + run: echo "IS_PODFILE_SAME_AS_MANIFEST=${{ hashFiles('ios/Podfile.lock') == hashFiles('ios/Pods/Manifest.lock') }}" >> "$GITHUB_OUTPUT" + + - name: Install cocoapods + uses: nick-fields/retry@3f757583fb1b1f940bc8ef4bf4734c8dc02a5847 + if: steps.pods-cache.outputs.cache-hit != 'true' || steps.compare-podfile-and-manifest.outputs.IS_PODFILE_SAME_AS_MANIFEST != 'true' || steps.setup-node.outputs.cache-hit != 'true' + with: + timeout_minutes: 10 + max_attempts: 5 + command: scripts/pod-install.sh + + - name: Decrypt AppStore profile + run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output NewApp_AppStore.mobileprovision NewApp_AppStore.mobileprovision.gpg + env: + LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} + + - name: Decrypt AppStore Notification Service profile + run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output NewApp_AppStore_Notification_Service.mobileprovision NewApp_AppStore_Notification_Service.mobileprovision.gpg + env: + LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} + + - name: Decrypt certificate + run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output Certificates.p12 Certificates.p12.gpg + env: + LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} + + - name: Decrypt App Store Connect API key + run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output ios-fastlane-json-key.json ios-fastlane-json-key.json.gpg + env: + LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} + + - name: Set iOS version in ENV + run: echo "IOS_VERSION=$(echo '${{ github.event.release.tag_name }}' | tr '-' '.')" >> "$GITHUB_ENV" + + - name: Run Fastlane + run: bundle exec fastlane ios ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'beta' }} + env: + APPLE_CONTACT_EMAIL: ${{ secrets.APPLE_CONTACT_EMAIL }} + APPLE_CONTACT_PHONE: ${{ secrets.APPLE_CONTACT_PHONE }} + APPLE_DEMO_EMAIL: ${{ secrets.APPLE_DEMO_EMAIL }} + APPLE_DEMO_PASSWORD: ${{ secrets.APPLE_DEMO_PASSWORD }} + VERSION: ${{ env.IOS_VERSION }} + + - name: Upload iOS build to Browser Stack + if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + run: curl -u "$BROWSERSTACK" -X POST "https://api-cloud.browserstack.com/app-live/upload" -F "file=@/Users/runner/work/App/App/New Expensify.ipa" + env: + BROWSERSTACK: ${{ secrets.BROWSERSTACK }} + + - name: Upload iOS sourcemaps to GitHub Release + if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + run: gh release upload ${{ github.event.release.tag_name }} main.jsbundle.map#ios-sourcemap-${{ github.event.release.tag_name }} + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload iOS build to GitHub Release + if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + run: gh release upload ${{ github.event.release.tag_name }} /Users/runner/work/App/App/New\ Expensify.ipa + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Warn deployers if iOS production deploy failed + if: ${{ failure() && fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + uses: 8398a7/action-slack@v3 + with: + status: custom + custom_payload: | + { + channel: '#deployer', + attachments: [{ + color: "#DB4545", + pretext: ``, + text: `πŸ’₯ iOS production deploy failed. Please manually submit ${{ env.IOS_VERSION }} in the . πŸ’₯`, + }] + } + env: + GITHUB_TOKEN: ${{ github.token }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + web: + # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly + name: Build and deploy Web + needs: validateActor + if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} + runs-on: ubuntu-latest-xl + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: ./.github/actions/composite/setupNode + + - name: Setup Cloudflare CLI + run: pip3 install cloudflare==2.19.0 + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + + - name: Build web + run: | + if [[ ${{ env.SHOULD_DEPLOY_PRODUCTION }} == 'true' ]]; then + npm run build + else + npm run build-staging + fi + + - name: Build storybook docs + continue-on-error: true + run: | + if [[ ${{ env.SHOULD_DEPLOY_PRODUCTION }} == 'true' ]]; then + npm run storybook-build + else + npm run storybook-build-staging + fi + + - name: Deploy to S3 + run: | + aws s3 cp --recursive --acl public-read "$GITHUB_WORKSPACE"/dist ${{ env.S3_URL }}/ + aws s3 cp --acl public-read --content-type 'application/json' --metadata-directive REPLACE ${{ env.S3_URL }}/.well-known/apple-app-site-association ${{ env.S3_URL }}/.well-known/apple-app-site-association + aws s3 cp --acl public-read --content-type 'application/json' --metadata-directive REPLACE ${{ env.S3_URL }}/.well-known/apple-app-site-association ${{env.S3_URL }}/apple-app-site-association + env: + S3_URL: s3://${{ env.SHOULD_DEPLOY_PRODUCTION != 'true' && 'staging-' || '' }}expensify-cash + + - name: Purge Cloudflare cache + run: /home/runner/.local/bin/cli4 --verbose --delete hosts=["${{ env.SHOULD_DEPLOY_PRODUCTION != 'true' && 'staging.' || '' }}new.expensify.com"] /zones/:9ee042e6cfc7fd45e74aa7d2f78d617b/purge_cache + env: + CF_API_KEY: ${{ secrets.CLOUDFLARE_TOKEN }} + + - name: Verify staging deploy + if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + run: | + sleep 5 + DOWNLOADED_VERSION="$(wget -q -O /dev/stdout https://staging.new.expensify.com/version.json | jq -r '.version')" + if [[ '${{ github.event.release.tag_name }}' != "$DOWNLOADED_VERSION" ]]; then + echo "Error: deployed version $DOWNLOADED_VERSION does not match local version ${{ github.event.release.tag_name }}. Something went wrong..." + exit 1 + fi + + - name: Verify production deploy + if: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + run: | + sleep 5 + DOWNLOADED_VERSION="$(wget -q -O /dev/stdout https://new.expensify.com/version.json | jq -r '.version')" + if [[ '${{ github.event.release.tag_name }}' != "$DOWNLOADED_VERSION" ]]; then + echo "Error: deployed version $DOWNLOADED_VERSION does not match local version ${{ github.event.release.tag_name }}. Something went wrong..." + exit 1 + fi + + - name: Upload web sourcemaps to GitHub Release + run: gh release upload ${{ github.event.release.tag_name }} dist/merged-source-map.js.map#web-sourcemap-${{ github.event.release.tag_name }} --clobber + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload web build to GitHub Release + run: | + tar -czvf webBuild.tar.gz dist + zip -r webBuild.zip dist + gh release upload ${{ github.event.release.tag_name }} webBuild.tar.gz webBuild.zip --clobber + env: + GITHUB_TOKEN: ${{ github.token }} + + postSlackMessageOnFailure: + name: Post a Slack message when any platform fails to build or deploy + runs-on: ubuntu-latest + if: ${{ failure() }} + needs: [android, desktop, iOS, web] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Post Slack message on failure + uses: ./.github/actions/composite/announceFailedWorkflowInSlack + with: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + + # Build a version of iOS and Android HybridApp if we are deploying to staging + hybridApp: + runs-on: ubuntu-latest + needs: validateActor + if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) && github.event.action != 'released' }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: 'Deploy HybridApp' + run: gh workflow run --repo Expensify/Mobile-Deploy deploy.yml -f force_build=true -f build_version="$(npm run print-version --silent)" + env: + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} + + postSlackMessageOnSuccess: + name: Post a Slack message when all platforms deploy successfully + runs-on: ubuntu-latest + if: ${{ success() }} + needs: [android, desktop, iOS, web] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set version + run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" + + - name: 'Announces the deploy in the #announce Slack room' + uses: 8398a7/action-slack@v3 + with: + status: custom + custom_payload: | + { + channel: '#announce', + attachments: [{ + color: 'good', + text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'staging' }} πŸŽ‰οΈ`, + }] + } + env: + GITHUB_TOKEN: ${{ github.token }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + - name: 'Announces the deploy in the #deployer Slack room' + uses: 8398a7/action-slack@v3 + with: + status: custom + custom_payload: | + { + channel: '#deployer', + attachments: [{ + color: 'good', + text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'staging' }} πŸŽ‰οΈ`, + }] + } + env: + GITHUB_TOKEN: ${{ github.token }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + - name: 'Announces a production deploy in the #expensify-open-source Slack room' + uses: 8398a7/action-slack@v3 + if: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + with: + status: custom + custom_payload: | + { + channel: '#expensify-open-source', + attachments: [{ + color: 'good', + text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to production πŸŽ‰οΈ`, + }] + } + env: + GITHUB_TOKEN: ${{ github.token }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + postGithubComment: + name: Post a GitHub comment when platforms are done building and deploying + runs-on: ubuntu-latest + if: ${{ !cancelled() }} + needs: [android, desktop, iOS, web] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: ./.github/actions/composite/setupNode + + - name: Set version + run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" + + - name: Get Release Pull Request List + id: getReleasePRList + uses: ./.github/actions/javascript/getDeployPullRequestList + with: + TAG: ${{ env.VERSION }} + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} + IS_PRODUCTION_DEPLOY: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + + - name: Comment on issues + uses: ./.github/actions/javascript/markPullRequestsAsDeployed + with: + PR_LIST: ${{ steps.getReleasePRList.outputs.PR_LIST }} + IS_PRODUCTION_DEPLOY: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + DEPLOY_VERSION: ${{ env.VERSION }} + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} + ANDROID: ${{ needs.android.result }} + DESKTOP: ${{ needs.desktop.result }} + IOS: ${{ needs.iOS.result }} + WEB: ${{ needs.web.result }} + deployStaging: runs-on: ubuntu-latest if: github.ref == 'refs/heads/staging' From 4bf80e688e136ad80c7aaa914e63433647744a93 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:16:52 +0100 Subject: [PATCH 49/77] Make necessary changes to Combine deploy.yml and platformDeploy.yml --- .github/workflows/deploy.yml | 214 ++++++++++++++++++++++++++--------- 1 file changed, 160 insertions(+), 54 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index efa069782078..c49d56cedb0e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -5,10 +5,10 @@ on: branches: [staging, production] env: - SHOULD_DEPLOY_PRODUCTION: ${{ github.event.action == 'released' }} + SHOULD_DEPLOY_PRODUCTION: ${{ github.ref == 'refs/heads/production' }} concurrency: - group: ${{ github.workflow }}-${{ github.event.action }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: @@ -32,7 +32,7 @@ jobs: deployChecklist: name: Create or update deploy checklist uses: ./.github/workflows/createDeployChecklist.yml - if: ${{ github.event.action != 'released' }} + if: !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) needs: validateActor secrets: inherit @@ -45,7 +45,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - + - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} @@ -90,17 +90,22 @@ jobs: env: BROWSERSTACK: ${{ secrets.BROWSERSTACK }} - - name: Upload Android sourcemaps to GitHub Release + - name: Upload Android sourcemaps artifact if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: gh release upload ${{ github.event.release.tag_name }} android/app/build/generated/sourcemaps/react/productionRelease/index.android.bundle.map#android-sourcemap-${{ github.event.release.tag_name }} - env: - GITHUB_TOKEN: ${{ github.token }} + uses: actions/upload-artifact@v4 + with: + name: android-sourcemaps + path: ./android/app/build/generated/sourcemaps/react/productionRelease/index.android.bundle.map - - name: Upload Android build to GitHub Release + - name: Upload Android build artifact if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: gh release upload ${{ github.event.release.tag_name }} android/app/build/outputs/bundle/productionRelease/app-production-release.aab - env: - GITHUB_TOKEN: ${{ github.token }} + uses: actions/upload-artifact@v4 + with: + name: android-build + path: ./android/app/build/outputs/bundle/productionRelease/app-production-release.aab + + - name: Set current App version in Env + run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" - name: Warn deployers if Android production deploy failed if: ${{ failure() && fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} @@ -113,7 +118,7 @@ jobs: attachments: [{ color: "#DB4545", pretext: ``, - text: `πŸ’₯ Android production deploy failed. Please manually submit ${{ github.event.release.tag_name }} in the . πŸ’₯`, + text: `πŸ’₯ Android production deploy failed. Please manually submit ${{ env.VERSION }} in the . πŸ’₯`, }] } env: @@ -154,15 +159,17 @@ jobs: AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} GCP_GEOLOCATION_API_KEY: $${{ secrets.GCP_GEOLOCATION_API_KEY_PRODUCTION }} - - name: Upload desktop sourcemaps to GitHub Release - run: gh release upload ${{ github.event.release.tag_name }} desktop/dist/www/merged-source-map.js.map#desktop-sourcemap-${{ github.event.release.tag_name }} --clobber - env: - GITHUB_TOKEN: ${{ github.token }} + - name: Upload desktop sourcemaps artifact + uses: actions/upload-artifact@v4 + with: + name: desktop-sourcemaps + path: ./desktop/dist/www/merged-source-map.js.map - - name: Upload desktop build to GitHub Release - run: gh release upload ${{ github.event.release.tag_name }} desktop-build/NewExpensify.dmg --clobber - env: - GITHUB_TOKEN: ${{ github.token }} + - name: Upload desktop build artifact + uses: actions/upload-artifact@v4 + with: + name: desktop-build + path: ./desktop-build/NewExpensify.dmg iOS: # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly @@ -227,8 +234,11 @@ jobs: env: LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} + - name: Set current App version in Env + run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" + - name: Set iOS version in ENV - run: echo "IOS_VERSION=$(echo '${{ github.event.release.tag_name }}' | tr '-' '.')" >> "$GITHUB_ENV" + run: echo "IOS_VERSION=$(echo '${{ env.VERSION }}' | tr '-' '.')" >> "$GITHUB_ENV" - name: Run Fastlane run: bundle exec fastlane ios ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'beta' }} @@ -245,17 +255,19 @@ jobs: env: BROWSERSTACK: ${{ secrets.BROWSERSTACK }} - - name: Upload iOS sourcemaps to GitHub Release + - name: Upload iOS sourcemaps artifact if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: gh release upload ${{ github.event.release.tag_name }} main.jsbundle.map#ios-sourcemap-${{ github.event.release.tag_name }} - env: - GITHUB_TOKEN: ${{ github.token }} + uses: actions/upload-artifact@v4 + with: + name: ios-sourcemaps + path: ./main.jsbundle.map - - name: Upload iOS build to GitHub Release - if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: gh release upload ${{ github.event.release.tag_name }} /Users/runner/work/App/App/New\ Expensify.ipa - env: - GITHUB_TOKEN: ${{ github.token }} + - name: Upload iOS build artifact + if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + uses: actions/upload-artifact@v4 + with: + name: ios-build + path: ./Users/runner/work/App/App/New\ Expensify.ipa - name: Warn deployers if iOS production deploy failed if: ${{ failure() && fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} @@ -328,13 +340,16 @@ jobs: env: CF_API_KEY: ${{ secrets.CLOUDFLARE_TOKEN }} + - name: Set current App version in Env + run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" + - name: Verify staging deploy if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} run: | sleep 5 DOWNLOADED_VERSION="$(wget -q -O /dev/stdout https://staging.new.expensify.com/version.json | jq -r '.version')" - if [[ '${{ github.event.release.tag_name }}' != "$DOWNLOADED_VERSION" ]]; then - echo "Error: deployed version $DOWNLOADED_VERSION does not match local version ${{ github.event.release.tag_name }}. Something went wrong..." + if [[ '${{ env.VERSION }}' != "$DOWNLOADED_VERSION" ]]; then + echo "Error: deployed version $DOWNLOADED_VERSION does not match local version ${{ env.VERSION }}. Something went wrong..." exit 1 fi @@ -343,23 +358,33 @@ jobs: run: | sleep 5 DOWNLOADED_VERSION="$(wget -q -O /dev/stdout https://new.expensify.com/version.json | jq -r '.version')" - if [[ '${{ github.event.release.tag_name }}' != "$DOWNLOADED_VERSION" ]]; then - echo "Error: deployed version $DOWNLOADED_VERSION does not match local version ${{ github.event.release.tag_name }}. Something went wrong..." + if [[ '${{ env.VERSION }}' != "$DOWNLOADED_VERSION" ]]; then + echo "Error: deployed version $DOWNLOADED_VERSION does not match local version ${{ env.VERSION }}. Something went wrong..." exit 1 fi - - name: Upload web sourcemaps to GitHub Release - run: gh release upload ${{ github.event.release.tag_name }} dist/merged-source-map.js.map#web-sourcemap-${{ github.event.release.tag_name }} --clobber - env: - GITHUB_TOKEN: ${{ github.token }} + - name: Upload web sourcemaps artifact + uses: actions/upload-artifact@v4 + with: + name: web-sourcemaps + path: ./dist/merged-source-map.js.map - - name: Upload web build to GitHub Release + - name: Compress web build .tar.gz and .zip run: | tar -czvf webBuild.tar.gz dist zip -r webBuild.zip dist - gh release upload ${{ github.event.release.tag_name }} webBuild.tar.gz webBuild.zip --clobber - env: - GITHUB_TOKEN: ${{ github.token }} + + - name: Upload .tar.gz web build artifact + uses: actions/upload-artifact@v4 + with: + name: web-build-tar-gz + path: ./webBuild.tar.gz + + - name: Upload .zip web build artifact + uses: actions/upload-artifact@v4 + with: + name: web-build-zip + path: ./webBuild.zip postSlackMessageOnFailure: name: Post a Slack message when any platform fails to build or deploy @@ -379,7 +404,7 @@ jobs: hybridApp: runs-on: ubuntu-latest needs: validateActor - if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) && github.event.action != 'released' }} + if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) && github.ref == 'refs/heads/staging' }} steps: - name: Checkout uses: actions/checkout@v4 @@ -398,7 +423,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Set version + - name: Set current App version in Env run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" - name: 'Announces the deploy in the #announce Slack room' @@ -462,7 +487,7 @@ jobs: - name: Setup Node uses: ./.github/actions/composite/setupNode - - name: Set version + - name: Set current App version in Env run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" - name: Get Release Pull Request List @@ -485,9 +510,29 @@ jobs: IOS: ${{ needs.iOS.result }} WEB: ${{ needs.web.result }} - deployStaging: + check-deployment-success: + runs-on: ubuntu-latest + outputs: + IS_DEPLOYED: ${{ steps.check-success.outputs.IS_DEPLOYED }} + needs: [android, desktop, iOS, web] + steps: + - name: Check deployment success on at least one platform + id: check-success + run: | + success="false" + if [ "${{ needs.android.result }}" == 'success' ] || \ + [ "${{ needs.iOS.result }}" == 'success' ] || \ + [ "${{ needs.desktop.result }}" == 'success' ] || \ + [ "${{ needs.web.result }}" == 'success' ]; then + success="true" + fi + echo "IS_DEPLOYED=$success" >> $GITHUB_ENV + echo "::set-output name=IS_DEPLOYED::$success" + + createPrerelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/staging' + if: github.ref == 'refs/heads/staging' && ${{ needs.check-deployment-success.outputs.IS_DEPLOYED }} == 'true' + needs: [android, desktop, iOS, web, check-deployment-success] steps: - name: Checkout staging branch uses: actions/checkout@v4 @@ -506,11 +551,54 @@ jobs: - name: Get current app version run: echo "STAGING_VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" - - name: πŸš€ Create prerelease to trigger staging deploy πŸš€ + - name: Download all workflow run artifacts + uses: actions/download-artifact@v4 + + - name: πŸš€ Create prerelease πŸš€ run: gh release create ${{ env.STAGING_VERSION }} --title ${{ env.STAGING_VERSION }} --generate-notes --prerelease --target staging env: GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} + - name: Upload Android sourcemaps to GitHub Release + run: gh release upload ${{ env.STAGING_VERSION }} ./android-sourcemaps/index.android.bundle.map#android-sourcemap-${{ env.STAGING_VERSION }} + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload Android build to GitHub Release + run: gh release upload ${{ env.STAGING_VERSION }} ./android-build/app-production-release.aab + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload desktop sourcemaps to GitHub Release + run: gh release upload ${{ env.STAGING_VERSION }} ./desktop-sourcemaps/merged-source-map.js.map#desktop-sourcemap-${{ env.STAGING_VERSION }} + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload desktop build to GitHub Release + run: gh release upload ${{ env.STAGING_VERSION }} ./desktop-build/NewExpensify.dmg + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload iOS sourcemaps to GitHub Release + run: gh release upload ${{ env.STAGING_VERSION }} ./ios-sourcemaps/main.jsbundle.map#ios-sourcemap-${{ env.STAGING_VERSION }} + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload iOS build to GitHub Release + run: gh release upload ${{ env.STAGING_VERSION }} ./ios-build/New\ Expensify.ipa + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload web sourcemaps to GitHub Release + run: gh release upload ${{ env.STAGING_VERSION }} ./web-sourcemaps/merged-source-map.js.map#web-sourcemap-${{ env.STAGING_VERSION }} + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload web build to GitHub Release + run: gh release upload ${{ env.STAGING_VERSION }} ./web-build-tar-gz/webBuild.tar.gz ./web-build-tar-gz/webBuild.zip + env: + GITHUB_TOKEN: ${{ github.token }} + - name: Warn deployers if staging deploy failed if: ${{ failure() }} uses: 8398a7/action-slack@v3 @@ -529,9 +617,10 @@ jobs: GITHUB_TOKEN: ${{ github.token }} SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - deployProduction: + finalizeRelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/production' + if: github.ref == 'refs/heads/staging' && ${{ needs.check-deployment-success.outputs.IS_DEPLOYED }} == 'true' + needs: [android, desktop, iOS, web, check-deployment-success] steps: - uses: actions/checkout@v4 name: Checkout @@ -547,10 +636,27 @@ jobs: OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} OS_BOTIFY_PRIVATE_KEY: ${{ secrets.OS_BOTIFY_PRIVATE_KEY }} - - name: Get current app version - run: echo "PRODUCTION_VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" + - name: Upload web sourcemaps to GitHub Release + run: gh release upload ${{ env.PRODUCTION_VERSION }} ./web-sourcemaps/merged-source-map.js.map#web-sourcemap-${{ env.PRODUCTION_VERSION }} --clobber + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload web build to GitHub Release + run: gh release upload ${{ env.PRODUCTION_VERSION }} ./web-build-tar-gz/webBuild.tar.gz ./web-build-tar-gz/webBuild.zip --clobber + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload desktop sourcemaps to GitHub Release + run: gh release upload ${{ env.PRODUCTION_VERSION }} ./desktop-sourcemaps/merged-source-map.js.map#desktop-sourcemap-${{ env.PRODUCTION_VERSION }} --clobber + env: + GITHUB_TOKEN: ${{ github.token }} + + - name: Upload desktop build to GitHub Release + run: gh release upload ${{ env.PRODUCTION_VERSION }} ./desktop-build/NewExpensify.dmg --clobber + env: + GITHUB_TOKEN: ${{ github.token }} - - name: πŸš€ Edit the release to be no longer a prerelease to deploy production πŸš€ + - name: πŸš€ Edit the release to be no longer a prerelease πŸš€ run: | LATEST_RELEASE="$(gh release list --exclude-pre-releases --json tagName,isLatest --jq '.[] | select(.isLatest) | .tagName')" gh api --method POST /repos/Expensify/App/releases/generate-notes -f "tag_name=${{ env.PRODUCTION_VERSION }}" -f "previous_tag_name=$LATEST_RELEASE" >> releaseNotes.md From dcfb320e6ccd410b19cf9fd13d6fdf7d344b6233 Mon Sep 17 00:00:00 2001 From: dominictb Date: Thu, 5 Sep 2024 18:57:37 +0700 Subject: [PATCH 50/77] fix: remove redundant constant --- src/CONST.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 6bdc731d775e..603c024ba33e 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1340,7 +1340,6 @@ const CONST = { STUDENT_AMBASSADOR: 'studentambassadors@expensify.com', SVFG: 'svfg@expensify.com', EXPENSIFY_EMAIL_DOMAIN: '@expensify.com', - ANONYMOUS_USER_DOMAIN: '@expensify.anon', }, CONCIERGE_DISPLAY_NAME: 'Concierge', From 4d61ae79c47bbbbdffe6670a642933ea43309bb5 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:11:31 +0100 Subject: [PATCH 51/77] remove platformDeploy.yml file and modify it's usages --- .../awaitStagingDeploys.ts | 2 +- .../javascript/awaitStagingDeploys/index.js | 2 +- .../getDeployPullRequestList.ts | 22 +- .../getDeployPullRequestList/index.js | 16 +- .../scripts/validateActionsAndWorkflows.sh | 2 +- .github/workflows/platformDeploy.yml | 487 ------------------ tests/unit/awaitStagingDeploysTest.ts | 30 +- 7 files changed, 52 insertions(+), 509 deletions(-) delete mode 100644 .github/workflows/platformDeploy.yml diff --git a/.github/actions/javascript/awaitStagingDeploys/awaitStagingDeploys.ts b/.github/actions/javascript/awaitStagingDeploys/awaitStagingDeploys.ts index 96bb17a14354..e18019144e4e 100644 --- a/.github/actions/javascript/awaitStagingDeploys/awaitStagingDeploys.ts +++ b/.github/actions/javascript/awaitStagingDeploys/awaitStagingDeploys.ts @@ -18,7 +18,7 @@ function run() { GitHubUtils.octokit.actions.listWorkflowRuns({ owner: CONST.GITHUB_OWNER, repo: CONST.APP_REPO, - workflow_id: 'platformDeploy.yml', + workflow_id: 'deploy.yml', event: 'push', branch: tag, }), diff --git a/.github/actions/javascript/awaitStagingDeploys/index.js b/.github/actions/javascript/awaitStagingDeploys/index.js index 7bdbafc0b722..561cc980a4e5 100644 --- a/.github/actions/javascript/awaitStagingDeploys/index.js +++ b/.github/actions/javascript/awaitStagingDeploys/index.js @@ -12138,7 +12138,7 @@ function run() { GithubUtils_1.default.octokit.actions.listWorkflowRuns({ owner: CONST_1.default.GITHUB_OWNER, repo: CONST_1.default.APP_REPO, - workflow_id: 'platformDeploy.yml', + workflow_id: 'deploy.yml', event: 'push', branch: tag, }), diff --git a/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts b/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts index da946b78a056..5d5dbc7e2f29 100644 --- a/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts +++ b/.github/actions/javascript/getDeployPullRequestList/getDeployPullRequestList.ts @@ -35,7 +35,7 @@ async function isReleaseValidBaseForEnvironment(releaseTag: string, isProduction } /** - * Was a given platformDeploy workflow run successful on at least one platform? + * Was a given deploy workflow run successful on at least one platform? */ async function wasDeploySuccessful(runID: number) { const jobsForWorkflowRun = ( @@ -82,7 +82,7 @@ async function run() { console.log(`Looking for PRs deployed to ${deployEnv} in ${inputTag}...`); - const completedDeploys = ( + const platformDeploys = ( await GithubUtils.octokit.actions.listWorkflowRuns({ owner: github.context.repo.owner, repo: github.context.repo.repo, @@ -95,6 +95,24 @@ async function run() { // because if a build fails on even one platform, then it will have the status 'failure' .filter((workflowRun) => workflowRun.conclusion !== 'cancelled'); + const deploys = ( + await GithubUtils.octokit.actions.listWorkflowRuns({ + owner: github.context.repo.owner, + repo: github.context.repo.repo, + // eslint-disable-next-line @typescript-eslint/naming-convention + workflow_id: 'deploy.yml', + status: 'completed', + }) + ).data.workflow_runs + // Note: we filter out cancelled runs instead of looking only for success runs + // because if a build fails on even one platform, then it will have the status 'failure' + .filter((workflowRun) => workflowRun.conclusion !== 'cancelled'); + + // W've combined platformDeploy.yml and deploy.yml + // TODO: Remove this once there are successful staging and production deploys using the new deploy.yml workflow + const completedDeploys = [...deploys, ...platformDeploys]; + completedDeploys.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()); + // Find the most recent deploy workflow targeting the correct environment, for which at least one of the build jobs finished successfully let lastSuccessfulDeploy = completedDeploys.shift(); diff --git a/.github/actions/javascript/getDeployPullRequestList/index.js b/.github/actions/javascript/getDeployPullRequestList/index.js index 300cb1edc0ed..58cc364c2fae 100644 --- a/.github/actions/javascript/getDeployPullRequestList/index.js +++ b/.github/actions/javascript/getDeployPullRequestList/index.js @@ -11526,7 +11526,7 @@ async function isReleaseValidBaseForEnvironment(releaseTag, isProductionDeploy) return !isPrerelease; } /** - * Was a given platformDeploy workflow run successful on at least one platform? + * Was a given deploy workflow run successful on at least one platform? */ async function wasDeploySuccessful(runID) { const jobsForWorkflowRun = (await GithubUtils_1.default.octokit.actions.listJobsForWorkflowRun({ @@ -11566,7 +11566,7 @@ async function run() { const isProductionDeploy = !!(0, ActionUtils_1.getJSONInput)('IS_PRODUCTION_DEPLOY', { required: false }, false); const deployEnv = isProductionDeploy ? 'production' : 'staging'; console.log(`Looking for PRs deployed to ${deployEnv} in ${inputTag}...`); - const completedDeploys = (await GithubUtils_1.default.octokit.actions.listWorkflowRuns({ + const platformDeploys = (await GithubUtils_1.default.octokit.actions.listWorkflowRuns({ owner: github.context.repo.owner, repo: github.context.repo.repo, // eslint-disable-next-line @typescript-eslint/naming-convention @@ -11576,6 +11576,18 @@ async function run() { // Note: we filter out cancelled runs instead of looking only for success runs // because if a build fails on even one platform, then it will have the status 'failure' .filter((workflowRun) => workflowRun.conclusion !== 'cancelled'); + const deploys = (await GithubUtils_1.default.octokit.actions.listWorkflowRuns({ + owner: github.context.repo.owner, + repo: github.context.repo.repo, + // eslint-disable-next-line @typescript-eslint/naming-convention + workflow_id: 'deploy.yml', + status: 'completed', + })).data.workflow_runs + // Note: we filter out cancelled runs instead of looking only for success runs + // because if a build fails on even one platform, then it will have the status 'failure' + .filter((workflowRun) => workflowRun.conclusion !== 'cancelled'); + // W've combined platformDeploy.yml and deploy.yml, deploys are the most recent ones + const completedDeploys = [...deploys, ...platformDeploys]; // Find the most recent deploy workflow targeting the correct environment, for which at least one of the build jobs finished successfully let lastSuccessfulDeploy = completedDeploys.shift(); if (!lastSuccessfulDeploy) { diff --git a/.github/scripts/validateActionsAndWorkflows.sh b/.github/scripts/validateActionsAndWorkflows.sh index 07348a302f20..fadb39c88e45 100755 --- a/.github/scripts/validateActionsAndWorkflows.sh +++ b/.github/scripts/validateActionsAndWorkflows.sh @@ -45,7 +45,7 @@ for ((i=0; i < ${#WORKFLOWS[@]}; i++)); do # Skip linting e2e workflow due to bug here: https://github.com/SchemaStore/schemastore/issues/2579 if [[ "$WORKFLOW" == './workflows/e2ePerformanceTests.yml' || "$WORKFLOW" == './workflows/testBuild.yml' - || "$WORKFLOW" == './workflows/platformDeploy.yml' ]]; then + || "$WORKFLOW" == './workflows/deploy.yml' ]]; then continue fi diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml deleted file mode 100644 index bacab79998f9..000000000000 --- a/.github/workflows/platformDeploy.yml +++ /dev/null @@ -1,487 +0,0 @@ -name: Build and deploy android, desktop, iOS, and web clients - -# This workflow is run when a release or prerelease is created -on: - release: - types: [prereleased, released] - -env: - SHOULD_DEPLOY_PRODUCTION: ${{ github.event.action == 'released' }} - -concurrency: - group: ${{ github.workflow }}-${{ github.event.action }} - cancel-in-progress: true - -jobs: - validateActor: - runs-on: ubuntu-latest - outputs: - IS_DEPLOYER: ${{ fromJSON(steps.isUserDeployer.outputs.IS_DEPLOYER) || github.actor == 'OSBotify' || github.actor == 'os-botify[bot]' }} - steps: - - name: Check if user is deployer - id: isUserDeployer - run: | - if gh api /orgs/Expensify/teams/mobile-deployers/memberships/${{ github.actor }} --silent; then - echo "IS_DEPLOYER=true" >> "$GITHUB_OUTPUT" - else - echo "IS_DEPLOYER=false" >> "$GITHUB_OUTPUT" - fi - env: - GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - - # Note: we're updating the checklist before running the deploys and assuming that it will succeed on at least one platform - deployChecklist: - name: Create or update deploy checklist - uses: ./.github/workflows/createDeployChecklist.yml - if: ${{ github.event.action != 'released' }} - needs: validateActor - secrets: inherit - - android: - # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly - name: Build and deploy Android - needs: validateActor - if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} - runs-on: ubuntu-latest-xl - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Configure MapBox SDK - run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} - - - name: Setup Node - uses: ./.github/actions/composite/setupNode - - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: 'oracle' - java-version: '17' - - - name: Setup Ruby - uses: ruby/setup-ruby@v1.190.0 - with: - bundler-cache: true - - - name: Decrypt keystore - run: cd android/app && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output my-upload-key.keystore my-upload-key.keystore.gpg - env: - LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} - - - name: Decrypt json key - run: cd android/app && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output android-fastlane-json-key.json android-fastlane-json-key.json.gpg - env: - LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} - - - name: Set version in ENV - run: echo "VERSION_CODE=$(grep -o 'versionCode\s\+[0-9]\+' android/app/build.gradle | awk '{ print $2 }')" >> "$GITHUB_ENV" - - - name: Run Fastlane - run: bundle exec fastlane android ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'beta' }} - env: - RUBYOPT: '-rostruct' - MYAPP_UPLOAD_STORE_PASSWORD: ${{ secrets.MYAPP_UPLOAD_STORE_PASSWORD }} - MYAPP_UPLOAD_KEY_PASSWORD: ${{ secrets.MYAPP_UPLOAD_KEY_PASSWORD }} - VERSION: ${{ env.VERSION_CODE }} - - - name: Upload Android build to Browser Stack - if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: curl -u "$BROWSERSTACK" -X POST "https://api-cloud.browserstack.com/app-live/upload" -F "file=@./android/app/build/outputs/bundle/productionRelease/app-production-release.aab" - env: - BROWSERSTACK: ${{ secrets.BROWSERSTACK }} - - - name: Upload Android sourcemaps to GitHub Release - if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: gh release upload ${{ github.event.release.tag_name }} android/app/build/generated/sourcemaps/react/productionRelease/index.android.bundle.map#android-sourcemap-${{ github.event.release.tag_name }} - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload Android build to GitHub Release - if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: gh release upload ${{ github.event.release.tag_name }} android/app/build/outputs/bundle/productionRelease/app-production-release.aab - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Warn deployers if Android production deploy failed - if: ${{ failure() && fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - uses: 8398a7/action-slack@v3 - with: - status: custom - custom_payload: | - { - channel: '#deployer', - attachments: [{ - color: "#DB4545", - pretext: ``, - text: `πŸ’₯ Android production deploy failed. Please manually submit ${{ github.event.release.tag_name }} in the . πŸ’₯`, - }] - } - env: - GITHUB_TOKEN: ${{ github.token }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - - desktop: - # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly - name: Build and deploy Desktop - needs: validateActor - if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} - runs-on: macos-14-large - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node - uses: ./.github/actions/composite/setupNode - - - name: Decrypt Developer ID Certificate - run: cd desktop && gpg --quiet --batch --yes --decrypt --passphrase="$DEVELOPER_ID_SECRET_PASSPHRASE" --output developer_id.p12 developer_id.p12.gpg - env: - DEVELOPER_ID_SECRET_PASSPHRASE: ${{ secrets.DEVELOPER_ID_SECRET_PASSPHRASE }} - - - name: Build desktop app - run: | - if [[ ${{ env.SHOULD_DEPLOY_PRODUCTION }} == 'true' ]]; then - npm run desktop-build - else - npm run desktop-build-staging - fi - env: - CSC_LINK: ${{ secrets.CSC_LINK }} - CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - GCP_GEOLOCATION_API_KEY: $${{ secrets.GCP_GEOLOCATION_API_KEY_PRODUCTION }} - - - name: Upload desktop sourcemaps to GitHub Release - run: gh release upload ${{ github.event.release.tag_name }} desktop/dist/www/merged-source-map.js.map#desktop-sourcemap-${{ github.event.release.tag_name }} --clobber - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload desktop build to GitHub Release - run: gh release upload ${{ github.event.release.tag_name }} desktop-build/NewExpensify.dmg --clobber - env: - GITHUB_TOKEN: ${{ github.token }} - - iOS: - # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly - name: Build and deploy iOS - needs: validateActor - if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} - env: - DEVELOPER_DIR: /Applications/Xcode_15.2.0.app/Contents/Developer - runs-on: macos-13-xlarge - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Configure MapBox SDK - run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} - - - name: Setup Node - id: setup-node - uses: ./.github/actions/composite/setupNode - - - name: Setup Ruby - uses: ruby/setup-ruby@v1.190.0 - with: - bundler-cache: true - - - name: Cache Pod dependencies - uses: actions/cache@v4 - id: pods-cache - with: - path: ios/Pods - key: ${{ runner.os }}-pods-cache-${{ hashFiles('ios/Podfile.lock', 'firebase.json') }} - - - name: Compare Podfile.lock and Manifest.lock - id: compare-podfile-and-manifest - run: echo "IS_PODFILE_SAME_AS_MANIFEST=${{ hashFiles('ios/Podfile.lock') == hashFiles('ios/Pods/Manifest.lock') }}" >> "$GITHUB_OUTPUT" - - - name: Install cocoapods - uses: nick-fields/retry@3f757583fb1b1f940bc8ef4bf4734c8dc02a5847 - if: steps.pods-cache.outputs.cache-hit != 'true' || steps.compare-podfile-and-manifest.outputs.IS_PODFILE_SAME_AS_MANIFEST != 'true' || steps.setup-node.outputs.cache-hit != 'true' - with: - timeout_minutes: 10 - max_attempts: 5 - command: scripts/pod-install.sh - - - name: Decrypt AppStore profile - run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output NewApp_AppStore.mobileprovision NewApp_AppStore.mobileprovision.gpg - env: - LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} - - - name: Decrypt AppStore Notification Service profile - run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output NewApp_AppStore_Notification_Service.mobileprovision NewApp_AppStore_Notification_Service.mobileprovision.gpg - env: - LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} - - - name: Decrypt certificate - run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output Certificates.p12 Certificates.p12.gpg - env: - LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} - - - name: Decrypt App Store Connect API key - run: cd ios && gpg --quiet --batch --yes --decrypt --passphrase="$LARGE_SECRET_PASSPHRASE" --output ios-fastlane-json-key.json ios-fastlane-json-key.json.gpg - env: - LARGE_SECRET_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} - - - name: Set iOS version in ENV - run: echo "IOS_VERSION=$(echo '${{ github.event.release.tag_name }}' | tr '-' '.')" >> "$GITHUB_ENV" - - - name: Run Fastlane - run: bundle exec fastlane ios ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'beta' }} - env: - APPLE_CONTACT_EMAIL: ${{ secrets.APPLE_CONTACT_EMAIL }} - APPLE_CONTACT_PHONE: ${{ secrets.APPLE_CONTACT_PHONE }} - APPLE_DEMO_EMAIL: ${{ secrets.APPLE_DEMO_EMAIL }} - APPLE_DEMO_PASSWORD: ${{ secrets.APPLE_DEMO_PASSWORD }} - VERSION: ${{ env.IOS_VERSION }} - - - name: Upload iOS build to Browser Stack - if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: curl -u "$BROWSERSTACK" -X POST "https://api-cloud.browserstack.com/app-live/upload" -F "file=@/Users/runner/work/App/App/New Expensify.ipa" - env: - BROWSERSTACK: ${{ secrets.BROWSERSTACK }} - - - name: Upload iOS sourcemaps to GitHub Release - if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: gh release upload ${{ github.event.release.tag_name }} main.jsbundle.map#ios-sourcemap-${{ github.event.release.tag_name }} - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload iOS build to GitHub Release - if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: gh release upload ${{ github.event.release.tag_name }} /Users/runner/work/App/App/New\ Expensify.ipa - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Warn deployers if iOS production deploy failed - if: ${{ failure() && fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - uses: 8398a7/action-slack@v3 - with: - status: custom - custom_payload: | - { - channel: '#deployer', - attachments: [{ - color: "#DB4545", - pretext: ``, - text: `πŸ’₯ iOS production deploy failed. Please manually submit ${{ env.IOS_VERSION }} in the . πŸ’₯`, - }] - } - env: - GITHUB_TOKEN: ${{ github.token }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - - web: - # WARNING: getDeployPullRequestList depends on this job name. do not change job name without adjusting that action accordingly - name: Build and deploy Web - needs: validateActor - if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }} - runs-on: ubuntu-latest-xl - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node - uses: ./.github/actions/composite/setupNode - - - name: Setup Cloudflare CLI - run: pip3 install cloudflare==2.19.0 - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - - name: Build web - run: | - if [[ ${{ env.SHOULD_DEPLOY_PRODUCTION }} == 'true' ]]; then - npm run build - else - npm run build-staging - fi - - - name: Build storybook docs - continue-on-error: true - run: | - if [[ ${{ env.SHOULD_DEPLOY_PRODUCTION }} == 'true' ]]; then - npm run storybook-build - else - npm run storybook-build-staging - fi - - - name: Deploy to S3 - run: | - aws s3 cp --recursive --acl public-read "$GITHUB_WORKSPACE"/dist ${{ env.S3_URL }}/ - aws s3 cp --acl public-read --content-type 'application/json' --metadata-directive REPLACE ${{ env.S3_URL }}/.well-known/apple-app-site-association ${{ env.S3_URL }}/.well-known/apple-app-site-association - aws s3 cp --acl public-read --content-type 'application/json' --metadata-directive REPLACE ${{ env.S3_URL }}/.well-known/apple-app-site-association ${{env.S3_URL }}/apple-app-site-association - env: - S3_URL: s3://${{ env.SHOULD_DEPLOY_PRODUCTION != 'true' && 'staging-' || '' }}expensify-cash - - - name: Purge Cloudflare cache - run: /home/runner/.local/bin/cli4 --verbose --delete hosts=["${{ env.SHOULD_DEPLOY_PRODUCTION != 'true' && 'staging.' || '' }}new.expensify.com"] /zones/:9ee042e6cfc7fd45e74aa7d2f78d617b/purge_cache - env: - CF_API_KEY: ${{ secrets.CLOUDFLARE_TOKEN }} - - - name: Verify staging deploy - if: ${{ !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: | - sleep 5 - DOWNLOADED_VERSION="$(wget -q -O /dev/stdout https://staging.new.expensify.com/version.json | jq -r '.version')" - if [[ '${{ github.event.release.tag_name }}' != "$DOWNLOADED_VERSION" ]]; then - echo "Error: deployed version $DOWNLOADED_VERSION does not match local version ${{ github.event.release.tag_name }}. Something went wrong..." - exit 1 - fi - - - name: Verify production deploy - if: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - run: | - sleep 5 - DOWNLOADED_VERSION="$(wget -q -O /dev/stdout https://new.expensify.com/version.json | jq -r '.version')" - if [[ '${{ github.event.release.tag_name }}' != "$DOWNLOADED_VERSION" ]]; then - echo "Error: deployed version $DOWNLOADED_VERSION does not match local version ${{ github.event.release.tag_name }}. Something went wrong..." - exit 1 - fi - - - name: Upload web sourcemaps to GitHub Release - run: gh release upload ${{ github.event.release.tag_name }} dist/merged-source-map.js.map#web-sourcemap-${{ github.event.release.tag_name }} --clobber - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload web build to GitHub Release - run: | - tar -czvf webBuild.tar.gz dist - zip -r webBuild.zip dist - gh release upload ${{ github.event.release.tag_name }} webBuild.tar.gz webBuild.zip --clobber - env: - GITHUB_TOKEN: ${{ github.token }} - - postSlackMessageOnFailure: - name: Post a Slack message when any platform fails to build or deploy - runs-on: ubuntu-latest - if: ${{ failure() }} - needs: [android, desktop, iOS, web] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Post Slack message on failure - uses: ./.github/actions/composite/announceFailedWorkflowInSlack - with: - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - - # Build a version of iOS and Android HybridApp if we are deploying to staging - hybridApp: - runs-on: ubuntu-latest - needs: validateActor - if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) && github.event.action != 'released' }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: 'Deploy HybridApp' - run: gh workflow run --repo Expensify/Mobile-Deploy deploy.yml -f force_build=true -f build_version="$(npm run print-version --silent)" - env: - GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - - postSlackMessageOnSuccess: - name: Post a Slack message when all platforms deploy successfully - runs-on: ubuntu-latest - if: ${{ success() }} - needs: [android, desktop, iOS, web] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set version - run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" - - - name: 'Announces the deploy in the #announce Slack room' - uses: 8398a7/action-slack@v3 - with: - status: custom - custom_payload: | - { - channel: '#announce', - attachments: [{ - color: 'good', - text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'staging' }} πŸŽ‰οΈ`, - }] - } - env: - GITHUB_TOKEN: ${{ github.token }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - - - name: 'Announces the deploy in the #deployer Slack room' - uses: 8398a7/action-slack@v3 - with: - status: custom - custom_payload: | - { - channel: '#deployer', - attachments: [{ - color: 'good', - text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'staging' }} πŸŽ‰οΈ`, - }] - } - env: - GITHUB_TOKEN: ${{ github.token }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - - - name: 'Announces a production deploy in the #expensify-open-source Slack room' - uses: 8398a7/action-slack@v3 - if: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - with: - status: custom - custom_payload: | - { - channel: '#expensify-open-source', - attachments: [{ - color: 'good', - text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to production πŸŽ‰οΈ`, - }] - } - env: - GITHUB_TOKEN: ${{ github.token }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - - postGithubComment: - name: Post a GitHub comment when platforms are done building and deploying - runs-on: ubuntu-latest - if: ${{ !cancelled() }} - needs: [android, desktop, iOS, web] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node - uses: ./.github/actions/composite/setupNode - - - name: Set version - run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" - - - name: Get Release Pull Request List - id: getReleasePRList - uses: ./.github/actions/javascript/getDeployPullRequestList - with: - TAG: ${{ env.VERSION }} - GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - IS_PRODUCTION_DEPLOY: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - - - name: Comment on issues - uses: ./.github/actions/javascript/markPullRequestsAsDeployed - with: - PR_LIST: ${{ steps.getReleasePRList.outputs.PR_LIST }} - IS_PRODUCTION_DEPLOY: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - DEPLOY_VERSION: ${{ env.VERSION }} - GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - ANDROID: ${{ needs.android.result }} - DESKTOP: ${{ needs.desktop.result }} - IOS: ${{ needs.iOS.result }} - WEB: ${{ needs.web.result }} diff --git a/tests/unit/awaitStagingDeploysTest.ts b/tests/unit/awaitStagingDeploysTest.ts index 64d79c9faf94..4d3384f11959 100644 --- a/tests/unit/awaitStagingDeploysTest.ts +++ b/tests/unit/awaitStagingDeploysTest.ts @@ -33,8 +33,8 @@ type MockedFunctionListResponse = jest.MockedFunction<() => Promise { const defaultReturn = Promise.resolve({data: {workflow_runs: []}}); @@ -44,11 +44,11 @@ const mockListWorkflowRuns = jest.fn().mockImplementation((args: Workflow) => { } if (args.branch !== undefined) { - return mockListPlatformDeploysForTag(); + return mockListDeploysForTag(); } - if (args.workflow_id === 'platformDeploy.yml') { - return mockListPlatformDeploys(); + if (args.workflow_id === 'deploy.yml') { + return mockListDeploys(); } if (args.workflow_id === 'preDeploy.yml') { @@ -89,7 +89,7 @@ describe('awaitStagingDeploys', () => { mockGetInput.mockImplementation(() => undefined); // First ping - mockListPlatformDeploys.mockResolvedValueOnce({ + mockListDeploys.mockResolvedValueOnce({ data: { workflow_runs: [COMPLETED_WORKFLOW, INCOMPLETE_WORKFLOW, INCOMPLETE_WORKFLOW], }, @@ -101,7 +101,7 @@ describe('awaitStagingDeploys', () => { }); // Second ping - mockListPlatformDeploys.mockResolvedValueOnce({ + mockListDeploys.mockResolvedValueOnce({ data: { workflow_runs: [COMPLETED_WORKFLOW, COMPLETED_WORKFLOW, INCOMPLETE_WORKFLOW], }, @@ -113,7 +113,7 @@ describe('awaitStagingDeploys', () => { }); // Third ping - mockListPlatformDeploys.mockResolvedValueOnce({ + mockListDeploys.mockResolvedValueOnce({ data: { workflow_runs: [COMPLETED_WORKFLOW, COMPLETED_WORKFLOW, COMPLETED_WORKFLOW], }, @@ -125,7 +125,7 @@ describe('awaitStagingDeploys', () => { }); // Fourth ping - mockListPlatformDeploys.mockResolvedValueOnce({ + mockListDeploys.mockResolvedValueOnce({ data: { workflow_runs: [COMPLETED_WORKFLOW, COMPLETED_WORKFLOW, COMPLETED_WORKFLOW], }, @@ -149,12 +149,12 @@ describe('awaitStagingDeploys', () => { mockGetInput.mockImplementation(() => 'my-tag'); // First ping - mockListPlatformDeploysForTag.mockResolvedValueOnce({ + mockListDeploysForTag.mockResolvedValueOnce({ data: { workflow_runs: [INCOMPLETE_WORKFLOW], }, }); - mockListPlatformDeploys.mockResolvedValueOnce({ + mockListDeploys.mockResolvedValueOnce({ data: { workflow_runs: [INCOMPLETE_WORKFLOW, INCOMPLETE_WORKFLOW], }, @@ -166,12 +166,12 @@ describe('awaitStagingDeploys', () => { }); // Second ping - mockListPlatformDeploysForTag.mockResolvedValueOnce({ + mockListDeploys.mockResolvedValueOnce({ data: { workflow_runs: [INCOMPLETE_WORKFLOW], }, }); - mockListPlatformDeploys.mockResolvedValueOnce({ + mockListDeploys.mockResolvedValueOnce({ data: { workflow_runs: [INCOMPLETE_WORKFLOW, COMPLETED_WORKFLOW], }, @@ -183,12 +183,12 @@ describe('awaitStagingDeploys', () => { }); // Third ping - mockListPlatformDeploysForTag.mockResolvedValueOnce({ + mockListDeploys.mockResolvedValueOnce({ data: { workflow_runs: [COMPLETED_WORKFLOW], }, }); - mockListPlatformDeploys.mockResolvedValueOnce({ + mockListDeploys.mockResolvedValueOnce({ data: { workflow_runs: [INCOMPLETE_WORKFLOW, COMPLETED_WORKFLOW, INCOMPLETE_WORKFLOW], }, From ed72e2d8fd04bf4921158ec62b7575cb31c3d841 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:24:37 +0100 Subject: [PATCH 52/77] correct absolute path --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c49d56cedb0e..25bde7def7e7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -267,7 +267,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: ios-build - path: ./Users/runner/work/App/App/New\ Expensify.ipa + path: /Users/runner/work/App/App/New\ Expensify.ipa - name: Warn deployers if iOS production deploy failed if: ${{ failure() && fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} From 338dade37900ea2c4f484af163ae05db7c910f22 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:25:25 +0100 Subject: [PATCH 53/77] correctly set env.PRODUCTION_VERSION --- .github/workflows/deploy.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 25bde7def7e7..9f3345f3be79 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -636,6 +636,9 @@ jobs: OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} OS_BOTIFY_PRIVATE_KEY: ${{ secrets.OS_BOTIFY_PRIVATE_KEY }} + - name: Get current app version + run: echo "PRODUCTION_VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" + - name: Upload web sourcemaps to GitHub Release run: gh release upload ${{ env.PRODUCTION_VERSION }} ./web-sourcemaps/merged-source-map.js.map#web-sourcemap-${{ env.PRODUCTION_VERSION }} --clobber env: From 1bd8fe11c502134f74eb4c4735292d6edca9ef46 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:27:34 +0100 Subject: [PATCH 54/77] build gh actions --- .github/actions/javascript/getDeployPullRequestList/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/actions/javascript/getDeployPullRequestList/index.js b/.github/actions/javascript/getDeployPullRequestList/index.js index 58cc364c2fae..3faaeb28f548 100644 --- a/.github/actions/javascript/getDeployPullRequestList/index.js +++ b/.github/actions/javascript/getDeployPullRequestList/index.js @@ -11586,8 +11586,10 @@ async function run() { // Note: we filter out cancelled runs instead of looking only for success runs // because if a build fails on even one platform, then it will have the status 'failure' .filter((workflowRun) => workflowRun.conclusion !== 'cancelled'); - // W've combined platformDeploy.yml and deploy.yml, deploys are the most recent ones + // W've combined platformDeploy.yml and deploy.yml + // TODO: Remove this once there are successful staging and production deploys using the new deploy.yml workflow const completedDeploys = [...deploys, ...platformDeploys]; + completedDeploys.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()); // Find the most recent deploy workflow targeting the correct environment, for which at least one of the build jobs finished successfully let lastSuccessfulDeploy = completedDeploys.shift(); if (!lastSuccessfulDeploy) { From e0be56db6cfdd2de9991df9190176b2b12384759 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:58:45 +0100 Subject: [PATCH 55/77] correct branch name --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9f3345f3be79..bafe6064d020 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -619,7 +619,7 @@ jobs: finalizeRelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/staging' && ${{ needs.check-deployment-success.outputs.IS_DEPLOYED }} == 'true' + if: github.ref == 'refs/heads/production' && ${{ needs.check-deployment-success.outputs.IS_DEPLOYED }} == 'true' needs: [android, desktop, iOS, web, check-deployment-success] steps: - uses: actions/checkout@v4 From b0925ef90d5c4bb8f6bfd7fe9ba6129048f1dcdf Mon Sep 17 00:00:00 2001 From: war-in Date: Thu, 5 Sep 2024 15:08:57 +0200 Subject: [PATCH 56/77] use debounced state for theme provider --- src/components/ThemeProvider.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/ThemeProvider.tsx b/src/components/ThemeProvider.tsx index a20dc353394e..9582b0f60a57 100644 --- a/src/components/ThemeProvider.tsx +++ b/src/components/ThemeProvider.tsx @@ -1,4 +1,5 @@ import React, {useEffect, useMemo} from 'react'; +import useDebouncedState from '@hooks/useDebouncedState'; import useThemePreferenceWithStaticOverride from '@hooks/useThemePreferenceWithStaticOverride'; import DomUtils from '@libs/DomUtils'; // eslint-disable-next-line no-restricted-imports @@ -12,8 +13,13 @@ type ThemeProviderProps = React.PropsWithChildren & { function ThemeProvider({children, theme: staticThemePreference}: ThemeProviderProps) { const themePreference = useThemePreferenceWithStaticOverride(staticThemePreference); + const [, debouncedMyTheme, setMyTheme] = useDebouncedState(themePreference); - const theme = useMemo(() => themes[themePreference], [themePreference]); + useEffect(() => { + setMyTheme(themePreference); + }, [setMyTheme, themePreference]); + + const theme = useMemo(() => themes[debouncedMyTheme], [debouncedMyTheme]); useEffect(() => { DomUtils.addCSS(DomUtils.getAutofilledInputStyle(theme.text), 'autofill-input'); From 302242376a8e353fd96f3deac72ca0cedaaa9800 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:10:00 +0100 Subject: [PATCH 57/77] Fix lint errors --- .github/workflows/deploy.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index bafe6064d020..954bee410b60 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -32,7 +32,7 @@ jobs: deployChecklist: name: Create or update deploy checklist uses: ./.github/workflows/createDeployChecklist.yml - if: !fromJSON(env.SHOULD_DEPLOY_PRODUCTION) + if: github.ref == 'refs/heads/staging' needs: validateActor secrets: inherit @@ -520,18 +520,17 @@ jobs: id: check-success run: | success="false" - if [ "${{ needs.android.result }}" == 'success' ] || \ - [ "${{ needs.iOS.result }}" == 'success' ] || \ - [ "${{ needs.desktop.result }}" == 'success' ] || \ - [ "${{ needs.web.result }}" == 'success' ]; then + if [ "${{ needs.android.result }}" == "success" ] || \ + [ "${{ needs.iOS.result }}" == "success" ] || \ + [ "${{ needs.desktop.result }}" == "success" ] || \ + [ "${{ needs.web.result }}" == "success" ]; then success="true" fi - echo "IS_DEPLOYED=$success" >> $GITHUB_ENV - echo "::set-output name=IS_DEPLOYED::$success" + echo "IS_DEPLOYED=\"$success\"" >> "$GITHUB_OUTPUT" createPrerelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/staging' && ${{ needs.check-deployment-success.outputs.IS_DEPLOYED }} == 'true' + if: github.ref == 'refs/heads/staging' && needs.check-deployment-success.outputs.IS_DEPLOYED == 'true' needs: [android, desktop, iOS, web, check-deployment-success] steps: - name: Checkout staging branch @@ -619,7 +618,7 @@ jobs: finalizeRelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/production' && ${{ needs.check-deployment-success.outputs.IS_DEPLOYED }} == 'true' + if: github.ref == 'refs/heads/production' && needs.check-deployment-success.outputs.IS_DEPLOYED == 'true' needs: [android, desktop, iOS, web, check-deployment-success] steps: - uses: actions/checkout@v4 From 24789b9075fd9db8999b9745c3e8428d78a19eef Mon Sep 17 00:00:00 2001 From: war-in Date: Thu, 5 Sep 2024 15:10:40 +0200 Subject: [PATCH 58/77] rename --- src/components/ThemeProvider.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ThemeProvider.tsx b/src/components/ThemeProvider.tsx index 9582b0f60a57..fe6a2e86bc00 100644 --- a/src/components/ThemeProvider.tsx +++ b/src/components/ThemeProvider.tsx @@ -13,13 +13,13 @@ type ThemeProviderProps = React.PropsWithChildren & { function ThemeProvider({children, theme: staticThemePreference}: ThemeProviderProps) { const themePreference = useThemePreferenceWithStaticOverride(staticThemePreference); - const [, debouncedMyTheme, setMyTheme] = useDebouncedState(themePreference); + const [, debouncedTheme, setDebouncedTheme] = useDebouncedState(themePreference); useEffect(() => { - setMyTheme(themePreference); - }, [setMyTheme, themePreference]); + setDebouncedTheme(themePreference); + }, [setDebouncedTheme, themePreference]); - const theme = useMemo(() => themes[debouncedMyTheme], [debouncedMyTheme]); + const theme = useMemo(() => themes[debouncedTheme], [debouncedTheme]); useEffect(() => { DomUtils.addCSS(DomUtils.getAutofilledInputStyle(theme.text), 'autofill-input'); From e38a58ea2ba90cd6b23d13e110269a2734256c22 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 14:16:18 +0100 Subject: [PATCH 59/77] Fix failing test --- tests/unit/awaitStagingDeploysTest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/awaitStagingDeploysTest.ts b/tests/unit/awaitStagingDeploysTest.ts index 4d3384f11959..26ce2778de40 100644 --- a/tests/unit/awaitStagingDeploysTest.ts +++ b/tests/unit/awaitStagingDeploysTest.ts @@ -166,7 +166,7 @@ describe('awaitStagingDeploys', () => { }); // Second ping - mockListDeploys.mockResolvedValueOnce({ + mockListDeploysForTag.mockResolvedValueOnce({ data: { workflow_runs: [INCOMPLETE_WORKFLOW], }, @@ -183,7 +183,7 @@ describe('awaitStagingDeploys', () => { }); // Third ping - mockListDeploys.mockResolvedValueOnce({ + mockListDeploysForTag.mockResolvedValueOnce({ data: { workflow_runs: [COMPLETED_WORKFLOW], }, From 2af4d0a2c28fbb6ed97d0f55bdcab053af87d7f8 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 5 Sep 2024 13:16:23 +0000 Subject: [PATCH 60/77] Update version to 9.0.29-10 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index c03948c3c42e..494728f49198 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009002909 - versionName "9.0.29-9" + versionCode 1009002910 + versionName "9.0.29-10" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index dbcc744d94b0..8d53ea38aeda 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.29.9 + 9.0.29.10 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 9f1147d9e0db..1609fea84206 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.29.9 + 9.0.29.10 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 59eb7d9727eb..2218c45f1e89 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.29 CFBundleVersion - 9.0.29.9 + 9.0.29.10 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 3935090b322a..1d323d9a59bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.29-9", + "version": "9.0.29-10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.29-9", + "version": "9.0.29-10", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index b9039a4f08f8..0ff52eed30e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.29-9", + "version": "9.0.29-10", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 960b3a4be99d69f0f7a6a97b832d8bddc0f444a0 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:00:00 +0100 Subject: [PATCH 61/77] Re-order jobs --- .github/workflows/deploy.yml | 206 +++++++++++++++++------------------ 1 file changed, 103 insertions(+), 103 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 954bee410b60..612e910191b3 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -414,110 +414,14 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - postSlackMessageOnSuccess: - name: Post a Slack message when all platforms deploy successfully - runs-on: ubuntu-latest - if: ${{ success() }} - needs: [android, desktop, iOS, web] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set current App version in Env - run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" - - - name: 'Announces the deploy in the #announce Slack room' - uses: 8398a7/action-slack@v3 - with: - status: custom - custom_payload: | - { - channel: '#announce', - attachments: [{ - color: 'good', - text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'staging' }} πŸŽ‰οΈ`, - }] - } - env: - GITHUB_TOKEN: ${{ github.token }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - - - name: 'Announces the deploy in the #deployer Slack room' - uses: 8398a7/action-slack@v3 - with: - status: custom - custom_payload: | - { - channel: '#deployer', - attachments: [{ - color: 'good', - text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'staging' }} πŸŽ‰οΈ`, - }] - } - env: - GITHUB_TOKEN: ${{ github.token }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - - - name: 'Announces a production deploy in the #expensify-open-source Slack room' - uses: 8398a7/action-slack@v3 - if: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - with: - status: custom - custom_payload: | - { - channel: '#expensify-open-source', - attachments: [{ - color: 'good', - text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to production πŸŽ‰οΈ`, - }] - } - env: - GITHUB_TOKEN: ${{ github.token }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} - - postGithubComment: - name: Post a GitHub comment when platforms are done building and deploying - runs-on: ubuntu-latest - if: ${{ !cancelled() }} - needs: [android, desktop, iOS, web] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node - uses: ./.github/actions/composite/setupNode - - - name: Set current App version in Env - run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" - - - name: Get Release Pull Request List - id: getReleasePRList - uses: ./.github/actions/javascript/getDeployPullRequestList - with: - TAG: ${{ env.VERSION }} - GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - IS_PRODUCTION_DEPLOY: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - - - name: Comment on issues - uses: ./.github/actions/javascript/markPullRequestsAsDeployed - with: - PR_LIST: ${{ steps.getReleasePRList.outputs.PR_LIST }} - IS_PRODUCTION_DEPLOY: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} - DEPLOY_VERSION: ${{ env.VERSION }} - GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - ANDROID: ${{ needs.android.result }} - DESKTOP: ${{ needs.desktop.result }} - IOS: ${{ needs.iOS.result }} - WEB: ${{ needs.web.result }} - - check-deployment-success: + checkDeploymentSuccess: runs-on: ubuntu-latest outputs: - IS_DEPLOYED: ${{ steps.check-success.outputs.IS_DEPLOYED }} + IS_DEPLOYED: ${{ steps.checkDeploymentSuccess.outputs.IS_DEPLOYED }} needs: [android, desktop, iOS, web] steps: - name: Check deployment success on at least one platform - id: check-success + id: checkDeploymentSuccess run: | success="false" if [ "${{ needs.android.result }}" == "success" ] || \ @@ -530,8 +434,8 @@ jobs: createPrerelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/staging' && needs.check-deployment-success.outputs.IS_DEPLOYED == 'true' - needs: [android, desktop, iOS, web, check-deployment-success] + if: github.ref == 'refs/heads/staging' && needs.checkDeploymentSuccess.outputs.IS_DEPLOYED == 'true' + needs: [checkDeploymentSuccess] steps: - name: Checkout staging branch uses: actions/checkout@v4 @@ -618,8 +522,8 @@ jobs: finalizeRelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/production' && needs.check-deployment-success.outputs.IS_DEPLOYED == 'true' - needs: [android, desktop, iOS, web, check-deployment-success] + if: github.ref == 'refs/heads/production' && needs.checkDeploymentSuccess.outputs.IS_DEPLOYED == 'true' + needs: [checkDeploymentSuccess] steps: - uses: actions/checkout@v4 name: Checkout @@ -683,3 +587,99 @@ jobs: env: GITHUB_TOKEN: ${{ github.token }} SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + postSlackMessageOnSuccess: + name: Post a Slack message when all platforms deploy successfully + runs-on: ubuntu-latest + if: ${{ success() }} + needs: [createPrerelease, finalizeRelease] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set current App version in Env + run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" + + - name: 'Announces the deploy in the #announce Slack room' + uses: 8398a7/action-slack@v3 + with: + status: custom + custom_payload: | + { + channel: '#announce', + attachments: [{ + color: 'good', + text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'staging' }} πŸŽ‰οΈ`, + }] + } + env: + GITHUB_TOKEN: ${{ github.token }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + - name: 'Announces the deploy in the #deployer Slack room' + uses: 8398a7/action-slack@v3 + with: + status: custom + custom_payload: | + { + channel: '#deployer', + attachments: [{ + color: 'good', + text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) && 'production' || 'staging' }} πŸŽ‰οΈ`, + }] + } + env: + GITHUB_TOKEN: ${{ github.token }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + - name: 'Announces a production deploy in the #expensify-open-source Slack room' + uses: 8398a7/action-slack@v3 + if: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + with: + status: custom + custom_payload: | + { + channel: '#expensify-open-source', + attachments: [{ + color: 'good', + text: `πŸŽ‰οΈ Successfully deployed ${process.env.AS_REPO} to production πŸŽ‰οΈ`, + }] + } + env: + GITHUB_TOKEN: ${{ github.token }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} + + postGithubComment: + name: Post a GitHub comment when platforms are done building and deploying + runs-on: ubuntu-latest + if: ${{ !cancelled() }} + needs: [createPrerelease, finalizeRelease] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: ./.github/actions/composite/setupNode + + - name: Set current App version in Env + run: echo "VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" + + - name: Get Release Pull Request List + id: getReleasePRList + uses: ./.github/actions/javascript/getDeployPullRequestList + with: + TAG: ${{ env.VERSION }} + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} + IS_PRODUCTION_DEPLOY: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + + - name: Comment on issues + uses: ./.github/actions/javascript/markPullRequestsAsDeployed + with: + PR_LIST: ${{ steps.getReleasePRList.outputs.PR_LIST }} + IS_PRODUCTION_DEPLOY: ${{ fromJSON(env.SHOULD_DEPLOY_PRODUCTION) }} + DEPLOY_VERSION: ${{ env.VERSION }} + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} + ANDROID: ${{ needs.android.result }} + DESKTOP: ${{ needs.desktop.result }} + IOS: ${{ needs.iOS.result }} + WEB: ${{ needs.web.result }} From 626142b30910f57ff4b2c9cffd53c21c75526124 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:14:25 +0100 Subject: [PATCH 62/77] Correct conditions --- .github/workflows/deploy.yml | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 612e910191b3..7777ea50d4d6 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -417,24 +417,33 @@ jobs: checkDeploymentSuccess: runs-on: ubuntu-latest outputs: - IS_DEPLOYED: ${{ steps.checkDeploymentSuccess.outputs.IS_DEPLOYED }} + IS_AT_LEAST_ONE_PLATFORM_DEPLOYED: ${{ steps.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED }} + IS_ALL_PLATFORMS_DEPLOYED: ${{ steps.checkDeploymentSuccess.outputs.IS_ALL_PLATFORMS_DEPLOYED }} needs: [android, desktop, iOS, web] steps: - name: Check deployment success on at least one platform id: checkDeploymentSuccess run: | - success="false" + isAtLeastOnePlatformDeployed="false" + isAllPlatformsDeployed="false" if [ "${{ needs.android.result }}" == "success" ] || \ [ "${{ needs.iOS.result }}" == "success" ] || \ [ "${{ needs.desktop.result }}" == "success" ] || \ [ "${{ needs.web.result }}" == "success" ]; then - success="true" + isAtLeastOnePlatformDeployed="true" fi - echo "IS_DEPLOYED=\"$success\"" >> "$GITHUB_OUTPUT" + if [ "${{ needs.android.result }}" == "success" ] && \ + [ "${{ needs.iOS.result }}" == "success" ] && \ + [ "${{ needs.desktop.result }}" == "success" ] && \ + [ "${{ needs.web.result }}" == "success" ]; then + isAllPlatformsDeployed="true" + fi + echo "IS_AT_LEAST_ONE_PLATFORM_DEPLOYED=\"$isAtLeastOnePlatformDeployed\"" >> "$GITHUB_OUTPUT" + echo "IS_ALL_PLATFORMS_DEPLOYED=\"$isAllPlatformsDeployed\"" >> "$GITHUB_OUTPUT" createPrerelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/staging' && needs.checkDeploymentSuccess.outputs.IS_DEPLOYED == 'true' + if: github.ref == 'refs/heads/staging' && needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED == 'true' needs: [checkDeploymentSuccess] steps: - name: Checkout staging branch @@ -522,7 +531,7 @@ jobs: finalizeRelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/production' && needs.checkDeploymentSuccess.outputs.IS_DEPLOYED == 'true' + if: github.ref == 'refs/heads/production' && needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED == 'true' needs: [checkDeploymentSuccess] steps: - uses: actions/checkout@v4 @@ -591,8 +600,8 @@ jobs: postSlackMessageOnSuccess: name: Post a Slack message when all platforms deploy successfully runs-on: ubuntu-latest - if: ${{ success() }} - needs: [createPrerelease, finalizeRelease] + if: needs.checkDeploymentSuccess.outputs.IS_ALL_PLATFORMS_DEPLOYED == 'true' + needs: [checkDeploymentSuccess, createPrerelease, finalizeRelease] steps: - name: Checkout uses: actions/checkout@v4 @@ -652,8 +661,8 @@ jobs: postGithubComment: name: Post a GitHub comment when platforms are done building and deploying runs-on: ubuntu-latest - if: ${{ !cancelled() }} - needs: [createPrerelease, finalizeRelease] + if: needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED == 'true' + needs: [checkDeploymentSuccess, createPrerelease, finalizeRelease] steps: - name: Checkout uses: actions/checkout@v4 From 217a2e327f8d8809b7127ddfd6718be5657d94e9 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:24:41 +0100 Subject: [PATCH 63/77] Fix validate gh actions error --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7777ea50d4d6..f73ebe2f3778 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -662,7 +662,7 @@ jobs: name: Post a GitHub comment when platforms are done building and deploying runs-on: ubuntu-latest if: needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED == 'true' - needs: [checkDeploymentSuccess, createPrerelease, finalizeRelease] + needs: [android, desktop, iOS, web, checkDeploymentSuccess, createPrerelease, finalizeRelease] steps: - name: Checkout uses: actions/checkout@v4 From 2de5aea46d5b457312d96c4bcbd55099760a660a Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 5 Sep 2024 14:42:51 +0000 Subject: [PATCH 64/77] Update version to 9.0.29-11 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 494728f49198..845861443b26 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009002910 - versionName "9.0.29-10" + versionCode 1009002911 + versionName "9.0.29-11" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 8d53ea38aeda..e8f80bf19cd0 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.29.10 + 9.0.29.11 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 1609fea84206..481ad2b4455c 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.29.10 + 9.0.29.11 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 2218c45f1e89..01df9d9c7e1a 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.29 CFBundleVersion - 9.0.29.10 + 9.0.29.11 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 1d323d9a59bd..f73248b653df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.29-10", + "version": "9.0.29-11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.29-10", + "version": "9.0.29-11", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 0ff52eed30e1..2caac633ed4a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.29-10", + "version": "9.0.29-11", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 82b6db1657a2a40a65bcc4f14cd356fafc8b39ad Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 5 Sep 2024 16:30:42 +0000 Subject: [PATCH 65/77] Update version to 9.0.29-12 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 845861443b26..36367d998888 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009002911 - versionName "9.0.29-11" + versionCode 1009002912 + versionName "9.0.29-12" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index e8f80bf19cd0..10cf6c684603 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.29.11 + 9.0.29.12 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 481ad2b4455c..7fa947d25678 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.29.11 + 9.0.29.12 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 01df9d9c7e1a..67d84f39807f 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.29 CFBundleVersion - 9.0.29.11 + 9.0.29.12 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index f73248b653df..096c7213977d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.29-11", + "version": "9.0.29-12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.29-11", + "version": "9.0.29-12", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 2caac633ed4a..def82426f252 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.29-11", + "version": "9.0.29-12", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 156b8b0da67d1df00b2dbc0aa0f25ed2f03f9ef3 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 5 Sep 2024 19:02:50 +0000 Subject: [PATCH 66/77] Update version to 9.0.30-0 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 4 ++-- ios/NewExpensifyTests/Info.plist | 4 ++-- ios/NotificationServiceExtension/Info.plist | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 36367d998888..ec89d22093b8 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009002912 - versionName "9.0.29-12" + versionCode 1009003000 + versionName "9.0.30-0" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 10cf6c684603..e287188fff48 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 9.0.29 + 9.0.30 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.29.12 + 9.0.30.0 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 7fa947d25678..2c474cdbd13d 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 9.0.29 + 9.0.30 CFBundleSignature ???? CFBundleVersion - 9.0.29.12 + 9.0.30.0 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 67d84f39807f..f4b347708a31 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -11,9 +11,9 @@ CFBundleName $(PRODUCT_NAME) CFBundleShortVersionString - 9.0.29 + 9.0.30 CFBundleVersion - 9.0.29.12 + 9.0.30.0 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 096c7213977d..ad786c3fecc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.29-12", + "version": "9.0.30-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.29-12", + "version": "9.0.30-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index def82426f252..1438dceae7a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.29-12", + "version": "9.0.30-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 89eab38dfaf9a1fda4fa34915449fd5f2651703e Mon Sep 17 00:00:00 2001 From: rory Date: Thu, 5 Sep 2024 12:28:13 -0700 Subject: [PATCH 67/77] Fix edited release body --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6b1b72f1f901..4a1ba5c28bc7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -73,7 +73,7 @@ jobs: - name: πŸš€ Edit the release to be no longer a prerelease to deploy production πŸš€ run: | LATEST_RELEASE="$(gh release list --exclude-pre-releases --json tagName,isLatest --jq '.[] | select(.isLatest) | .tagName')" - gh api --method POST /repos/Expensify/App/releases/generate-notes -f "tag_name=${{ env.PRODUCTION_VERSION }}" -f "previous_tag_name=$LATEST_RELEASE" >> releaseNotes.md + gh api --method POST /repos/Expensify/App/releases/generate-notes -f "tag_name=${{ env.PRODUCTION_VERSION }}" -f "previous_tag_name=$LATEST_RELEASE" | jq -r '.body' >> releaseNotes.md gh release edit ${{ env.PRODUCTION_VERSION }} --prerelease=false --latest --notes-file releaseNotes.md env: GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} From bbb5722af13d7842d6796a1d30e3e5408abe272c Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:52:18 +0100 Subject: [PATCH 68/77] Address review comments --- .github/workflows/deploy.yml | 98 ++++++++++-------------------------- 1 file changed, 26 insertions(+), 72 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f73ebe2f3778..fc3f022f166b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -446,12 +446,6 @@ jobs: if: github.ref == 'refs/heads/staging' && needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED == 'true' needs: [checkDeploymentSuccess] steps: - - name: Checkout staging branch - uses: actions/checkout@v4 - with: - ref: staging - token: ${{ secrets.OS_BOTIFY_TOKEN }} - - name: Setup git for OSBotify uses: ./.github/actions/composite/setupGitForOSBotifyApp id: setupGitForOSBotify @@ -471,45 +465,20 @@ jobs: env: GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} - - name: Upload Android sourcemaps to GitHub Release - run: gh release upload ${{ env.STAGING_VERSION }} ./android-sourcemaps/index.android.bundle.map#android-sourcemap-${{ env.STAGING_VERSION }} - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload Android build to GitHub Release - run: gh release upload ${{ env.STAGING_VERSION }} ./android-build/app-production-release.aab - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload desktop sourcemaps to GitHub Release - run: gh release upload ${{ env.STAGING_VERSION }} ./desktop-sourcemaps/merged-source-map.js.map#desktop-sourcemap-${{ env.STAGING_VERSION }} - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload desktop build to GitHub Release - run: gh release upload ${{ env.STAGING_VERSION }} ./desktop-build/NewExpensify.dmg - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload iOS sourcemaps to GitHub Release - run: gh release upload ${{ env.STAGING_VERSION }} ./ios-sourcemaps/main.jsbundle.map#ios-sourcemap-${{ env.STAGING_VERSION }} - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload iOS build to GitHub Release - run: gh release upload ${{ env.STAGING_VERSION }} ./ios-build/New\ Expensify.ipa - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload web sourcemaps to GitHub Release - run: gh release upload ${{ env.STAGING_VERSION }} ./web-sourcemaps/merged-source-map.js.map#web-sourcemap-${{ env.STAGING_VERSION }} - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload web build to GitHub Release - run: gh release upload ${{ env.STAGING_VERSION }} ./web-build-tar-gz/webBuild.tar.gz ./web-build-tar-gz/webBuild.zip - env: - GITHUB_TOKEN: ${{ github.token }} + - name: Upload artifacts to GitHub Release + run: | + gh release upload ${{ env.STAGING_VERSION }} \ + ./android-sourcemaps/index.android.bundle.map#android-sourcemap-${{ env.STAGING_VERSION }} \ + ./android-build/app-production-release.aab \ + ./desktop-sourcemaps/merged-source-map.js.map#desktop-sourcemap-${{ env.STAGING_VERSION }} \ + ./desktop-build/NewExpensify.dmg \ + ./ios-sourcemaps/main.jsbundle.map#ios-sourcemap-${{ env.STAGING_VERSION }} \ + ./ios-build/New\ Expensify.ipa \ + ./web-sourcemaps/merged-source-map.js.map#web-sourcemap-${{ env.STAGING_VERSION }} \ + ./web-build-tar-gz/webBuild.tar.gz \ + ./web-build-zip/webBuild.zip + env: + GITHUB_TOKEN: ${{ github.token }} - name: Warn deployers if staging deploy failed if: ${{ failure() }} @@ -531,15 +500,9 @@ jobs: finalizeRelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/production' && needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED == 'true' + if: github.ref == 'refs/heads/production' && fromJSON(needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED) needs: [checkDeploymentSuccess] steps: - - uses: actions/checkout@v4 - name: Checkout - with: - ref: production - token: ${{ secrets.OS_BOTIFY_TOKEN }} - - name: Setup git for OSBotify uses: ./.github/actions/composite/setupGitForOSBotifyApp id: setupGitForOSBotify @@ -551,25 +514,16 @@ jobs: - name: Get current app version run: echo "PRODUCTION_VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" - - name: Upload web sourcemaps to GitHub Release - run: gh release upload ${{ env.PRODUCTION_VERSION }} ./web-sourcemaps/merged-source-map.js.map#web-sourcemap-${{ env.PRODUCTION_VERSION }} --clobber - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload web build to GitHub Release - run: gh release upload ${{ env.PRODUCTION_VERSION }} ./web-build-tar-gz/webBuild.tar.gz ./web-build-tar-gz/webBuild.zip --clobber - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload desktop sourcemaps to GitHub Release - run: gh release upload ${{ env.PRODUCTION_VERSION }} ./desktop-sourcemaps/merged-source-map.js.map#desktop-sourcemap-${{ env.PRODUCTION_VERSION }} --clobber - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Upload desktop build to GitHub Release - run: gh release upload ${{ env.PRODUCTION_VERSION }} ./desktop-build/NewExpensify.dmg --clobber + - name: Upload artifacts to GitHub Release + run: | + gh release upload ${{ env.STAGING_VERSION }} \ + ./desktop-sourcemaps/merged-source-map.js.map#desktop-sourcemap-${{ env.STAGING_VERSION }} \ + ./desktop-build/NewExpensify.dmg \ + ./web-sourcemaps/merged-source-map.js.map#web-sourcemap-${{ env.STAGING_VERSION }} \ + ./web-build-tar-gz/webBuild.tar.gz \ + ./web-build-zip/webBuild.zip env: - GITHUB_TOKEN: ${{ github.token }} + GITHUB_TOKEN: ${{ github.token }} - name: πŸš€ Edit the release to be no longer a prerelease πŸš€ run: | @@ -659,9 +613,9 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} postGithubComment: - name: Post a GitHub comment when platforms are done building and deploying + name: Post a GitHub comments on all deployed PRs when platforms are done building and deploying runs-on: ubuntu-latest - if: needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED == 'true' + if: fromJSON(needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED) needs: [android, desktop, iOS, web, checkDeploymentSuccess, createPrerelease, finalizeRelease] steps: - name: Checkout From 68febf34fddc92f7dc98e6d7e8f4af3e37bdf983 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 5 Sep 2024 20:32:41 +0000 Subject: [PATCH 69/77] Update version to 9.0.30-1 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index ec89d22093b8..c4ebad1968ce 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009003000 - versionName "9.0.30-0" + versionCode 1009003001 + versionName "9.0.30-1" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index e287188fff48..f968e0400f81 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.30.0 + 9.0.30.1 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 2c474cdbd13d..789386890392 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.30.0 + 9.0.30.1 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index f4b347708a31..3317a5a1e868 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.30 CFBundleVersion - 9.0.30.0 + 9.0.30.1 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index ad786c3fecc3..b3d8344a7a27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.30-0", + "version": "9.0.30-1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.30-0", + "version": "9.0.30-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 1438dceae7a5..1454fb9cd73e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.30-0", + "version": "9.0.30-1", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 855f2882f4af68689d2e215eab9f7fb3591a4d9e Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 5 Sep 2024 20:35:04 +0000 Subject: [PATCH 70/77] Update version to 9.0.30-2 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index c4ebad1968ce..46759a0ef1df 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009003001 - versionName "9.0.30-1" + versionCode 1009003002 + versionName "9.0.30-2" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index f968e0400f81..4830e5cb97fc 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.30.1 + 9.0.30.2 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 789386890392..009d4bb55275 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.30.1 + 9.0.30.2 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 3317a5a1e868..5d5b5f9100ca 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.30 CFBundleVersion - 9.0.30.1 + 9.0.30.2 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index b3d8344a7a27..109bfb731988 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.30-1", + "version": "9.0.30-2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.30-1", + "version": "9.0.30-2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 1454fb9cd73e..c97dab96dc3c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.30-1", + "version": "9.0.30-2", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From c5e90ed9ff2c9a2346f4161726d4da6e402a6105 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 5 Sep 2024 20:35:18 +0000 Subject: [PATCH 71/77] Update version to 9.0.30-3 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 46759a0ef1df..9122b890061c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009003002 - versionName "9.0.30-2" + versionCode 1009003003 + versionName "9.0.30-3" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 4830e5cb97fc..e83937d06f1e 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.30.2 + 9.0.30.3 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 009d4bb55275..466d38d99f1f 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.30.2 + 9.0.30.3 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 5d5b5f9100ca..179648c11306 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.30 CFBundleVersion - 9.0.30.2 + 9.0.30.3 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 109bfb731988..b372198cf029 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.30-2", + "version": "9.0.30-3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.30-2", + "version": "9.0.30-3", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index c97dab96dc3c..c02668c3d677 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.30-2", + "version": "9.0.30-3", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 951919d39a368bed8a6c73566b3f79c9b95fc14f Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 5 Sep 2024 22:30:08 +0100 Subject: [PATCH 72/77] address review comments --- .github/workflows/deploy.yml | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index fc3f022f166b..ad6a1da0deaa 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -32,7 +32,7 @@ jobs: deployChecklist: name: Create or update deploy checklist uses: ./.github/workflows/createDeployChecklist.yml - if: github.ref == 'refs/heads/staging' + if: ${{ github.ref == 'refs/heads/staging' }} needs: validateActor secrets: inherit @@ -443,9 +443,17 @@ jobs: createPrerelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/staging' && needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED == 'true' + if: ${{ github.ref == 'refs/heads/staging' && fromJSON(needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED) }} needs: [checkDeploymentSuccess] steps: + # The command "gh release create" also creates and pushes a tag for the version if one does not already exist, + # So we need to checkout the staging branch and create that tag from the staging branch. + - name: Checkout staging branch + uses: actions/checkout@v4 + with: + ref: staging + token: ${{ secrets.OS_BOTIFY_TOKEN }} + - name: Setup git for OSBotify uses: ./.github/actions/composite/setupGitForOSBotifyApp id: setupGitForOSBotify @@ -500,9 +508,15 @@ jobs: finalizeRelease: runs-on: ubuntu-latest - if: github.ref == 'refs/heads/production' && fromJSON(needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED) + if: ${{ github.ref == 'refs/heads/production' && fromJSON(needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED) }} needs: [checkDeploymentSuccess] steps: + - uses: actions/checkout@v4 + name: Checkout + with: + ref: production + token: ${{ secrets.OS_BOTIFY_TOKEN }} + - name: Setup git for OSBotify uses: ./.github/actions/composite/setupGitForOSBotifyApp id: setupGitForOSBotify @@ -554,7 +568,7 @@ jobs: postSlackMessageOnSuccess: name: Post a Slack message when all platforms deploy successfully runs-on: ubuntu-latest - if: needs.checkDeploymentSuccess.outputs.IS_ALL_PLATFORMS_DEPLOYED == 'true' + if: ${{ fromJSON(needs.checkDeploymentSuccess.outputs.IS_ALL_PLATFORMS_DEPLOYED) }} needs: [checkDeploymentSuccess, createPrerelease, finalizeRelease] steps: - name: Checkout @@ -615,7 +629,7 @@ jobs: postGithubComment: name: Post a GitHub comments on all deployed PRs when platforms are done building and deploying runs-on: ubuntu-latest - if: fromJSON(needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED) + if: ${{ fromJSON(needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED) }} needs: [android, desktop, iOS, web, checkDeploymentSuccess, createPrerelease, finalizeRelease] steps: - name: Checkout From 2797f92dcbf99f6d498f2b74acc277786111a9b2 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 5 Sep 2024 21:37:03 +0000 Subject: [PATCH 73/77] Update version to 9.0.30-4 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 9122b890061c..8486d57c4a0a 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009003003 - versionName "9.0.30-3" + versionCode 1009003004 + versionName "9.0.30-4" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index e83937d06f1e..7f36ee4af5bc 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.30.3 + 9.0.30.4 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 466d38d99f1f..ebb19431c4bf 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.30.3 + 9.0.30.4 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 179648c11306..10b26cdcd969 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.30 CFBundleVersion - 9.0.30.3 + 9.0.30.4 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index b372198cf029..1defa5d34007 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.30-3", + "version": "9.0.30-4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.30-3", + "version": "9.0.30-4", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index c02668c3d677..66eeb5d877c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.30-3", + "version": "9.0.30-4", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 2778eee547a4382b7028a53f332886dd79a5b868 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 6 Sep 2024 00:28:13 +0000 Subject: [PATCH 74/77] Update version to 9.0.30-5 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 8486d57c4a0a..c290af495d86 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009003004 - versionName "9.0.30-4" + versionCode 1009003005 + versionName "9.0.30-5" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 7f36ee4af5bc..ae334ad126ba 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.30.4 + 9.0.30.5 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index ebb19431c4bf..7512bc941905 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.30.4 + 9.0.30.5 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 10b26cdcd969..c27f70c33b49 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.30 CFBundleVersion - 9.0.30.4 + 9.0.30.5 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 1defa5d34007..94d52d9209b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.30-4", + "version": "9.0.30-5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.30-4", + "version": "9.0.30-5", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 66eeb5d877c1..46f82660ff8d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.30-4", + "version": "9.0.30-5", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 60d27cf623d1d17f9a7ab7751b2a2b5f56288eb9 Mon Sep 17 00:00:00 2001 From: rory Date: Thu, 5 Sep 2024 17:44:05 -0700 Subject: [PATCH 75/77] Create and push tag before updating checklist --- .github/workflows/deploy.yml | 57 ++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 3279ffcd50a0..d4cbfc8e86b5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -28,12 +28,35 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} + createTag: + needs: validateActor + if: ${{ github.ref == 'refs/heads/staging' }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.OS_BOTIFY_TOKEN }} + + - name: Setup git for OSBotify + uses: ./.github/actions/composite/setupGitForOSBotifyApp + id: setupGitForOSBotify + with: + GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} + OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} + OS_BOTIFY_PRIVATE_KEY: ${{ secrets.OS_BOTIFY_PRIVATE_KEY }} + + - name: Create and push tag + run: | + git tag "$(jq -r .version < package.json)" + git push origin --tags + # Note: we're updating the checklist before running the deploys and assuming that it will succeed on at least one platform deployChecklist: name: Create or update deploy checklist uses: ./.github/workflows/createDeployChecklist.yml if: ${{ github.ref == 'refs/heads/staging' }} - needs: validateActor + needs: createTag secrets: inherit android: @@ -45,7 +68,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - + - name: Configure MapBox SDK run: ./scripts/setup-mapbox-sdk.sh ${{ secrets.MAPBOX_SDK_DOWNLOAD_TOKEN }} @@ -446,24 +469,11 @@ jobs: if: ${{ github.ref == 'refs/heads/staging' && fromJSON(needs.checkDeploymentSuccess.outputs.IS_AT_LEAST_ONE_PLATFORM_DEPLOYED) }} needs: [checkDeploymentSuccess] steps: - # The command "gh release create" also creates and pushes a tag for the version if one does not already exist, - # So we need to checkout the staging branch and create that tag from the staging branch. - name: Checkout staging branch uses: actions/checkout@v4 - with: - ref: staging - token: ${{ secrets.OS_BOTIFY_TOKEN }} - - - name: Setup git for OSBotify - uses: ./.github/actions/composite/setupGitForOSBotifyApp - id: setupGitForOSBotify - with: - GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} - OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} - OS_BOTIFY_PRIVATE_KEY: ${{ secrets.OS_BOTIFY_PRIVATE_KEY }} - name: Get current app version - run: echo "STAGING_VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" + run: echo "STAGING_VERSION=$(jq -r .version < package.json)" >> "$GITHUB_ENV" - name: Download all workflow run artifacts uses: actions/download-artifact@v4 @@ -486,7 +496,7 @@ jobs: ./web-build-tar-gz/webBuild.tar.gz \ ./web-build-zip/webBuild.zip env: - GITHUB_TOKEN: ${{ github.token }} + GITHUB_TOKEN: ${{ github.token }} - name: Warn deployers if staging deploy failed if: ${{ failure() }} @@ -513,17 +523,6 @@ jobs: steps: - uses: actions/checkout@v4 name: Checkout - with: - ref: production - token: ${{ secrets.OS_BOTIFY_TOKEN }} - - - name: Setup git for OSBotify - uses: ./.github/actions/composite/setupGitForOSBotifyApp - id: setupGitForOSBotify - with: - GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }} - OS_BOTIFY_APP_ID: ${{ secrets.OS_BOTIFY_APP_ID }} - OS_BOTIFY_PRIVATE_KEY: ${{ secrets.OS_BOTIFY_PRIVATE_KEY }} - name: Get current app version run: echo "PRODUCTION_VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV" @@ -537,7 +536,7 @@ jobs: ./web-build-tar-gz/webBuild.tar.gz \ ./web-build-zip/webBuild.zip env: - GITHUB_TOKEN: ${{ github.token }} + GITHUB_TOKEN: ${{ github.token }} - name: πŸš€ Edit the release to be no longer a prerelease πŸš€ run: | From 94cf03dc41cbb171390f448d3d3dc4020c8cf35a Mon Sep 17 00:00:00 2001 From: rory Date: Thu, 5 Sep 2024 17:50:10 -0700 Subject: [PATCH 76/77] Use regular github token instead of OSBotify token to create and update release --- .github/workflows/deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d4cbfc8e86b5..e18cbe15fc6b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -481,7 +481,7 @@ jobs: - name: πŸš€ Create prerelease πŸš€ run: gh release create ${{ env.STAGING_VERSION }} --title ${{ env.STAGING_VERSION }} --generate-notes --prerelease --target staging env: - GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} + GITHUB_TOKEN: ${{ github.token }} - name: Upload artifacts to GitHub Release run: | @@ -544,7 +544,7 @@ jobs: gh api --method POST /repos/Expensify/App/releases/generate-notes -f "tag_name=${{ env.PRODUCTION_VERSION }}" -f "previous_tag_name=$LATEST_RELEASE" | jq -r '.body' >> releaseNotes.md gh release edit ${{ env.PRODUCTION_VERSION }} --prerelease=false --latest --notes-file releaseNotes.md env: - GITHUB_TOKEN: ${{ steps.setupGitForOSBotify.outputs.OS_BOTIFY_API_TOKEN }} + GITHUB_TOKEN: ${{ github.token }} - name: Warn deployers if production deploy failed if: ${{ failure() }} From 7375e15b66c626569dd62838fe25878f2dabb8fc Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 6 Sep 2024 00:54:24 +0000 Subject: [PATCH 77/77] Update version to 9.0.30-6 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index c290af495d86..e748b5af89cd 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009003005 - versionName "9.0.30-5" + versionCode 1009003006 + versionName "9.0.30-6" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index ae334ad126ba..d02d8b2397a1 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.30.5 + 9.0.30.6 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 7512bc941905..631a3ab1d031 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 9.0.30.5 + 9.0.30.6 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index c27f70c33b49..ade1dc089435 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 9.0.30 CFBundleVersion - 9.0.30.5 + 9.0.30.6 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 94d52d9209b9..99a5892a8b3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "9.0.30-5", + "version": "9.0.30-6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.30-5", + "version": "9.0.30-6", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 46f82660ff8d..58ca057efee4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "9.0.30-5", + "version": "9.0.30-6", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",