Skip to content

perf: create reportAttributes derived value #58476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f5c0355
add onyx source value to derived values
TMisiukiewicz Mar 13, 2025
47f2872
pass sourceValues to compute for collection keys
TMisiukiewicz Mar 13, 2025
189608f
fix types
TMisiukiewicz Mar 13, 2025
46c2cf5
add report attributes derived value
TMisiukiewicz Mar 13, 2025
70ae349
generate report name for reports
TMisiukiewicz Mar 14, 2025
6805b5f
Merge branch 'main' into perf/create-report-attributes-derived-value
TMisiukiewicz Mar 14, 2025
15dbb15
add comments to type
TMisiukiewicz Mar 14, 2025
d703077
fix iteration of reportAttributes
TMisiukiewicz Mar 14, 2025
f7083d7
always set onyx derived value
TMisiukiewicz Mar 17, 2025
c870ebe
Merge branch 'main' into perf/create-report-attributes-derived-value
TMisiukiewicz Mar 17, 2025
d83d30d
Merge branch 'main' into perf/create-report-attributes-derived-value
TMisiukiewicz Mar 27, 2025
c65ca4c
Merge remote-tracking branch 'upstream/main' into perf/create-report-…
TMisiukiewicz Mar 27, 2025
de67ca6
Merge branch 'main' into perf/create-report-attributes-derived-value
TMisiukiewicz Mar 28, 2025
753ee26
Merge branch 'main' into perf/create-report-attributes-derived-value
TMisiukiewicz Mar 31, 2025
fad7276
Merge remote-tracking branch 'upstream/main' into perf/create-report-…
TMisiukiewicz Mar 31, 2025
a50796f
fix navigateAfterOnboardingTest
TMisiukiewicz Mar 31, 2025
92b3891
Merge branch 'main' into perf/create-report-attributes-derived-value
TMisiukiewicz Apr 1, 2025
991681b
Merge remote-tracking branch 'origin/main' into perf/create-report-at…
TMisiukiewicz Apr 2, 2025
ebb56f0
fix GroupChatNameTest
TMisiukiewicz Apr 3, 2025
a30eedc
do not calculate if empty personal details
TMisiukiewicz Apr 3, 2025
41f9412
Merge branch 'main' into perf/create-report-attributes-derived-value
TMisiukiewicz Apr 3, 2025
7a941fe
expect error on ts compute args
TMisiukiewicz Apr 3, 2025
0daf3b1
Merge remote-tracking branch 'upstream/main' into perf/create-report-…
TMisiukiewicz Apr 3, 2025
5c986cd
Merge branch 'main' into perf/create-report-attributes-derived-value
TMisiukiewicz Apr 7, 2025
249b7b9
update personal details description
TMisiukiewicz Apr 7, 2025
88b5665
Merge remote-tracking branch 'upstream/main' into perf/create-report-…
TMisiukiewicz Apr 9, 2025
d11bb5a
Merge remote-tracking branch 'upstream/main' into perf/create-report-…
TMisiukiewicz Apr 11, 2025
5abf1b4
better readability of getReportName conditions
TMisiukiewicz Apr 11, 2025
9156f6b
add basic tests for getReportName
TMisiukiewicz Apr 11, 2025
d29f863
remove report name cache
TMisiukiewicz Apr 14, 2025
4a9f804
recompute report attributes on locale change
TMisiukiewicz Apr 14, 2025
fb8ea68
Merge remote-tracking branch 'origin/main' into perf/create-report-at…
TMisiukiewicz Apr 15, 2025
c1802c2
improve readability of onyxderived types
TMisiukiewicz Apr 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ const ONYXKEYS = {
},
DERIVED: {
CONCIERGE_CHAT_REPORT_ID: 'conciergeChatReportID',
REPORT_ATTRIBUTES: 'reportAttributes',
},
} as const;

Expand Down Expand Up @@ -1116,6 +1117,7 @@ type OnyxValuesMapping = {

type OnyxDerivedValuesMapping = {
[ONYXKEYS.DERIVED.CONCIERGE_CHAT_REPORT_ID]: string | undefined;
[ONYXKEYS.DERIVED.REPORT_ATTRIBUTES]: Record<string, OnyxTypes.ReportAttributes>;
};

type OnyxValues = OnyxValuesMapping & OnyxCollectionValuesMapping & OnyxFormValuesMapping & OnyxFormDraftValuesMapping & OnyxDerivedValuesMapping;
Expand Down
50 changes: 26 additions & 24 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import type {
PolicyReportField,
Report,
ReportAction,
ReportAttributes,
ReportMetadata,
ReportNameValuePairs,
ReportViolationName,
Expand Down Expand Up @@ -1029,6 +1030,17 @@ Onyx.connect({
callback: (value) => (activePolicyID = value),
});

let reportAttributes: OnyxEntry<Record<string, ReportAttributes>>;
Onyx.connect({
key: ONYXKEYS.DERIVED.REPORT_ATTRIBUTES,
callback: (value) => {
if (!value) {
return;
}
reportAttributes = value;
},
});

let newGroupChatDraft: OnyxEntry<NewGroupChatDraft>;
Onyx.connect({
key: ONYXKEYS.NEW_GROUP_CHAT_DRAFT,
Expand Down Expand Up @@ -4504,13 +4516,6 @@ function getInvoicesChatName({
return getPolicyName({report, policy: invoiceReceiverPolicy, policies});
}

const reportNameCache = new Map<string, {lastVisibleActionCreated: string; reportName: string}>();

/**
* Get a cache key for the report name.
*/
const getCacheKey = (report: OnyxEntry<Report>): string => `${report?.reportID}-${report?.lastVisibleActionCreated}-${report?.reportName}`;

/**
* Get the title for a report using only participant names. This may be used for 1:1 DMs and other non-categorized chats.
*/
Expand All @@ -4528,6 +4533,13 @@ function buildReportNameFromParticipantNames({report, personalDetails}: {report:
.join(', ');
}

function generateReportName(report: OnyxEntry<Report>): string {
if (!report) {
return '';
}
return getReportNameInternal({report});
}

/**
* Get the title for a report.
*/
Expand All @@ -4538,6 +4550,12 @@ function getReportName(
personalDetails?: Partial<PersonalDetailsList>,
invoiceReceiverPolicy?: OnyxEntry<Policy>,
): string {
// Check if we can use report name in derived values - only when we have report but no other params
const canUseDerivedValue = report && policy === undefined && parentReportActionParam === undefined && personalDetails === undefined && invoiceReceiverPolicy === undefined;

if (canUseDerivedValue && reportAttributes?.[report.reportID]) {
return reportAttributes[report.reportID].reportName;
}
return getReportNameInternal({report, policy, parentReportActionParam, personalDetails, invoiceReceiverPolicy});
}

Expand Down Expand Up @@ -4567,15 +4585,6 @@ function getReportNameInternal({
policies,
}: GetReportNameParams): string {
const reportID = report?.reportID;
const cacheKey = getCacheKey(report);

if (reportID) {
const reportNameFromCache = reportNameCache.get(cacheKey);

if (reportNameFromCache?.reportName && reportNameFromCache.reportName === report?.reportName && reportNameFromCache.reportName !== CONST.REPORT.DEFAULT_REPORT_NAME) {
return reportNameFromCache.reportName;
}
}

let formattedName: string | undefined;
let parentReportAction: OnyxEntry<ReportAction>;
Expand Down Expand Up @@ -4759,20 +4768,12 @@ function getReportNameInternal({
}

if (formattedName) {
if (reportID) {
reportNameCache.set(cacheKey, {lastVisibleActionCreated: report?.lastVisibleActionCreated ?? '', reportName: formattedName});
}

return formatReportLastMessageText(formattedName);
}

// Not a room or PolicyExpenseChat, generate title from first 5 other participants
formattedName = buildReportNameFromParticipantNames({report, personalDetails});

if (reportID) {
reportNameCache.set(cacheKey, {lastVisibleActionCreated: report?.lastVisibleActionCreated ?? '', reportName: formattedName});
}

return formattedName;
}

Expand Down Expand Up @@ -10583,6 +10584,7 @@ export {
getReportSubtitlePrefix,
getPolicyChangeMessage,
getExpenseReportStateAndStatus,
generateReportName,
navigateToLinkedReportAction,
buildOptimisticResolvedDuplicatesReportAction,
populateOptimisticReportFormula,
Expand Down
2 changes: 2 additions & 0 deletions src/libs/actions/OnyxDerived/ONYX_DERIVED_VALUES.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {ValueOf} from 'type-fest';
import ONYXKEYS from '@src/ONYXKEYS';
import conciergeChatReportIDConfig from './configs/conciergeChatReportID';
import reportAttributesConfig from './configs/reportAttributes';
import type {OnyxDerivedValueConfig} from './types';

/**
Expand All @@ -9,6 +10,7 @@ import type {OnyxDerivedValueConfig} from './types';
*/
const ONYX_DERIVED_VALUES = {
[ONYXKEYS.DERIVED.CONCIERGE_CHAT_REPORT_ID]: conciergeChatReportIDConfig,
[ONYXKEYS.DERIVED.REPORT_ATTRIBUTES]: reportAttributesConfig,
} as const satisfies {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[Key in ValueOf<typeof ONYXKEYS.DERIVED>]: OnyxDerivedValueConfig<Key, any>;
Expand Down
36 changes: 36 additions & 0 deletions src/libs/actions/OnyxDerived/configs/reportAttributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {generateReportName} from '@libs/ReportUtils';
import createOnyxDerivedValueConfig from '@userActions/OnyxDerived/createOnyxDerivedValueConfig';
import ONYXKEYS from '@src/ONYXKEYS';
import type {ReportAttributes} from '@src/types/onyx';

/**
* This derived value is used to get the report attributes for the report.
* Dependency on ONYXKEYS.PERSONAL_DETAILS_LIST is to ensure that the report attributes are generated after the personal details are available.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate more on why we need to wait for ONYXKEYS.PERSONAL_DETAILS_LIST to be available?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some report names are generated based on information stored in personal details - this ensures we calculate them only if this information is available so we do not miss anything

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, is this one example?

App/src/libs/ReportUtils.ts

Lines 4762 to 4764 in 32492c3

if (reportID) {
reportNameCache.set(cacheKey, {lastVisibleActionCreated: report?.lastVisibleActionCreated ?? '', reportName: formattedName});
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an example is getGroupChatName function that is using getDisplayNameForParticipant which is using personal details. Found it out when tests for GroupChatName were failing

*/

export default createOnyxDerivedValueConfig({
key: ONYXKEYS.DERIVED.REPORT_ATTRIBUTES,
dependencies: [ONYXKEYS.COLLECTION.REPORT, ONYXKEYS.PERSONAL_DETAILS_LIST, ONYXKEYS.NVP_PREFERRED_LOCALE],
compute: ([reports, personalDetails, preferredLocale], {currentValue, sourceValues}) => {
if (!reports || !personalDetails || !preferredLocale) {
return {};
}

const reportUpdates = sourceValues?.[ONYXKEYS.COLLECTION.REPORT];

return Object.values(reportUpdates ?? reports).reduce<Record<string, ReportAttributes>>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a concern, will it affect App load time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

App load time should not be affected, since currently the same calculations are being done in getOrderedReportIDs on app startup

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @TMisiukiewicz. Let me know your thoughts on other feedbacks.

(acc, report) => {
if (!report) {
return acc;
}

acc[report.reportID] = {
reportName: generateReportName(report),
};

return acc;
},
reportUpdates && currentValue ? currentValue : {},
);
},
});
36 changes: 24 additions & 12 deletions src/libs/actions/OnyxDerived/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import OnyxUtils from 'react-native-onyx/dist/OnyxUtils';
import Log from '@libs/Log';
import ObjectUtils from '@src/types/utils/ObjectUtils';
import ONYX_DERIVED_VALUES from './ONYX_DERIVED_VALUES';
import type {DerivedValueContext} from './types';

/**
* Initialize all Onyx derived values, store them in Onyx, and setup listeners to update them when dependencies change.
Expand All @@ -23,11 +24,12 @@ function init() {
OnyxUtils.get(key).then((storedDerivedValue) => {
let derivedValue = storedDerivedValue;
if (derivedValue) {
Log.info(`Derived value ${derivedValue} for ${key} restored from disk`);
Log.info(`Derived value for ${key} restored from disk`);
} else {
OnyxUtils.tupleGet(dependencies).then((values) => {
// @ts-expect-error TypeScript can't confirm the shape of tupleGet's return value matches the compute function's parameters
derivedValue = compute(values, {currentValue: derivedValue});
dependencyValues = values;
derivedValue = compute(values, derivedValue);
Onyx.set(key, derivedValue ?? null);
});
}
Expand All @@ -36,13 +38,23 @@ function init() {
dependencyValues[i] = value;
};

const recomputeDerivedValue = () => {
const newDerivedValue = compute(dependencyValues, derivedValue);
if (newDerivedValue !== derivedValue) {
Log.info(`[OnyxDerived] value for key ${key} changed, updating it in Onyx`, false, {old: derivedValue ?? null, new: newDerivedValue ?? null});
derivedValue = newDerivedValue;
Onyx.set(key, derivedValue ?? null);
const recomputeDerivedValue = (sourceKey?: string, sourceValue?: unknown) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, the compute function received only the current derived value as its second parameter. Now it gets a context object that includes sourceValue, keyed by the dependency that triggered the change. This allows tracking which specific dependency caused the recomputation.

This unlocks smarter downstream logic - compute can selectively recompute only affected items instead of the entire collection, like reportAttributes already does.

This behavior only applies to collections with waitForCollectionCallback: true. For non-collection dependencies or those without the flag, sourceValue is undefined since it’s always equal to the current value anyway

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @TMisiukiewicz

const context: DerivedValueContext<typeof key, typeof dependencies> = {
currentValue: derivedValue,
sourceValues: undefined,
};

// If we got a source key and value, add it to the sourceValues object
if (sourceKey && sourceValue !== undefined) {
context.sourceValues = {
[sourceKey]: sourceValue,
};
}
// @ts-expect-error TypeScript can't confirm the shape of dependencyValues matches the compute function's parameters
const newDerivedValue = compute(dependencyValues, context);
Log.info(`[OnyxDerived] updating value for ${key} in Onyx`, false, {old: derivedValue ?? null, new: newDerivedValue ?? null});
derivedValue = newDerivedValue;
Onyx.set(key, derivedValue ?? null);
};

for (let i = 0; i < dependencies.length; i++) {
Expand All @@ -52,10 +64,10 @@ function init() {
Onyx.connect({
key: dependencyOnyxKey,
waitForCollectionCallback: true,
callback: (value) => {
Log.info(`[OnyxDerived] dependency ${dependencyOnyxKey} for derived key ${key} changed, recomputing`);
callback: (value, collectionKey, sourceValue) => {
Log.info(`[OnyxDerived] dependency ${collectionKey} for derived key ${key} changed, recomputing`);
setDependencyValue(i, value as Parameters<typeof compute>[0][typeof i]);
recomputeDerivedValue();
recomputeDerivedValue(dependencyOnyxKey, sourceValue);
},
});
} else {
Expand All @@ -64,7 +76,7 @@ function init() {
callback: (value) => {
Log.info(`[OnyxDerived] dependency ${dependencyOnyxKey} for derived key ${key} changed, recomputing`);
setDependencyValue(i, value as Parameters<typeof compute>[0][typeof i]);
recomputeDerivedValue();
recomputeDerivedValue(dependencyOnyxKey);
},
});
}
Expand Down
16 changes: 11 additions & 5 deletions src/libs/actions/OnyxDerived/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import type {OnyxValue} from 'react-native-onyx';
import type {OnyxCollection, OnyxValue} from 'react-native-onyx';
import type {NonEmptyTuple, ValueOf} from 'type-fest';
import type {OnyxDerivedValuesMapping, OnyxKey} from '@src/ONYXKEYS';
import type {OnyxCollectionKey, OnyxCollectionValuesMapping, OnyxDerivedValuesMapping, OnyxKey} from '@src/ONYXKEYS';
import type ONYXKEYS from '@src/ONYXKEYS';

type DerivedValueContext<Key extends OnyxKey, Deps extends NonEmptyTuple<Exclude<OnyxKey, Key>>> = {
currentValue?: OnyxValue<Key>;
sourceValues?: {
[K in Deps[number] as K extends OnyxCollectionKey ? K : never]?: K extends keyof OnyxCollectionValuesMapping ? OnyxCollection<OnyxCollectionValuesMapping[K]> : never;
};
};

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB, but is there any way to simplify this by creating helper types, with Partial and/or adding a comment? I'm getting old and I would have to whip out my notepad to solve the boolean logic to get the resulting type right now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for your comment, mind checking if it is easier to read now?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @TMisiukiewicz - it still borders on arcane, but is way easier to understand what's going on. Thank you!

* A derived value configuration describes:
* - a tuple of Onyx keys to subscribe to (dependencies),
Expand All @@ -17,9 +24,8 @@ type OnyxDerivedValueConfig<Key extends ValueOf<typeof ONYXKEYS.DERIVED>, Deps e
args: {
[Index in keyof Deps]: OnyxValue<Deps[Index]>;
},
currentValue: OnyxValue<Key>,
context: DerivedValueContext<Key, Deps>,
) => OnyxDerivedValuesMapping[Key];
};

// eslint-disable-next-line import/prefer-default-export
export type {OnyxDerivedValueConfig};
export type {OnyxDerivedValueConfig, DerivedValueContext};
11 changes: 11 additions & 0 deletions src/types/onyx/DerivedValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* The attributes of a report.
*/
type ReportAttributes = {
/**
* The name of the report.
*/
reportName: string;
};

export default ReportAttributes;
2 changes: 2 additions & 0 deletions src/types/onyx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type Credentials from './Credentials';
import type Currency from './Currency';
import type {CurrencyList} from './Currency';
import type CustomStatusDraft from './CustomStatusDraft';
import type ReportAttributes from './DerivedValues';
import type DismissedProductTraining from './DismissedProductTraining';
import type DismissedReferralBanners from './DismissedReferralBanners';
import type Download from './Download';
Expand Down Expand Up @@ -260,5 +261,6 @@ export type {
TravelProvisioning,
SidePanel,
LastPaymentMethodType,
ReportAttributes,
TalkToAISales,
};
41 changes: 21 additions & 20 deletions tests/ui/GroupChatNameTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,26 +97,27 @@ function signInAndGetApp(reportName = '', participantAccountIDs?: number[]): Pro
})
.then(async () => {
// Simulate setting an unread report and personal details
await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, {
reportID: REPORT_ID,
reportName,
lastMessageText: 'Test',
participants,
lastActorAccountID: USER_B_ACCOUNT_ID,
type: CONST.REPORT.TYPE.CHAT,
chatType: CONST.REPORT.CHAT_TYPE.GROUP,
});

await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
[USER_A_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_A_EMAIL, USER_A_ACCOUNT_ID, 'A'),
[USER_B_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_B_EMAIL, USER_B_ACCOUNT_ID, 'B'),
[USER_C_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_C_EMAIL, USER_C_ACCOUNT_ID, 'C'),
[USER_D_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_D_EMAIL, USER_D_ACCOUNT_ID, 'D'),
[USER_E_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_E_EMAIL, USER_E_ACCOUNT_ID, 'E'),
[USER_F_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_F_EMAIL, USER_F_ACCOUNT_ID, 'F'),
[USER_G_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_G_EMAIL, USER_G_ACCOUNT_ID, 'G'),
[USER_H_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_H_EMAIL, USER_H_ACCOUNT_ID, 'H'),
});
await Promise.all([
Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, {
reportID: REPORT_ID,
reportName,
lastMessageText: 'Test',
participants,
lastActorAccountID: USER_B_ACCOUNT_ID,
type: CONST.REPORT.TYPE.CHAT,
chatType: CONST.REPORT.CHAT_TYPE.GROUP,
}),
Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
[USER_A_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_A_EMAIL, USER_A_ACCOUNT_ID, 'A'),
[USER_B_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_B_EMAIL, USER_B_ACCOUNT_ID, 'B'),
[USER_C_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_C_EMAIL, USER_C_ACCOUNT_ID, 'C'),
[USER_D_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_D_EMAIL, USER_D_ACCOUNT_ID, 'D'),
[USER_E_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_E_EMAIL, USER_E_ACCOUNT_ID, 'E'),
[USER_F_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_F_EMAIL, USER_F_ACCOUNT_ID, 'F'),
[USER_G_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_G_EMAIL, USER_G_ACCOUNT_ID, 'G'),
[USER_H_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_H_EMAIL, USER_H_ACCOUNT_ID, 'H'),
}),
]);

// We manually setting the sidebar as loaded since the onLayout event does not fire in tests
setSidebarLoaded();
Expand Down
Loading
Loading