Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type {OnyxUpdate} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import type CONST from './CONST';
import type {OnboardingCompanySize} from './CONST';
Expand Down Expand Up @@ -503,6 +504,9 @@ const ONYXKEYS = {
/** Information about loading states while talking with AI sales */
TALK_TO_AI_SALES: 'talkToAISales',

/** Onyx updates that should be stored after sequential queue is flushed */
QUEUE_FLUSHED_DATA: 'queueFlushedData',

/** Set when we are loading bill when downgrade */
IS_LOADING_BILL_WHEN_DOWNGRADE: 'isLoadingBillWhenDowngrade',

Expand Down Expand Up @@ -1020,6 +1024,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.NVP_PRIORITY_MODE]: ValueOf<typeof CONST.PRIORITY_MODE>;
[ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE]: OnyxTypes.BlockedFromConcierge;
[ONYXKEYS.TALK_TO_AI_SALES]: OnyxTypes.TalkToAISales;
[ONYXKEYS.QUEUE_FLUSHED_DATA]: OnyxUpdate[];

// The value of this nvp is a string representation of the date when the block expires, or an empty string if the user is not blocked
[ONYXKEYS.NVP_BLOCKED_FROM_CHAT]: string;
Expand Down
1 change: 1 addition & 0 deletions src/libs/API/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type OnyxData = {
successData?: OnyxUpdate[];
failureData?: OnyxUpdate[];
finallyData?: OnyxUpdate[];
queueFlushedData?: OnyxUpdate[];
};

/**
Expand Down
72 changes: 67 additions & 5 deletions src/libs/Network/SequentialQueue.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type {OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import {
deleteRequestsByIndices as deletePersistedRequestsByIndices,
Expand Down Expand Up @@ -72,7 +73,37 @@ function flushOnyxUpdatesQueue() {
Log.info('[SequentialQueue] Queue already paused');
return;
}
flushQueue();
return flushQueue();
}

let queueFlushedDataToStore: OnyxUpdate[] = [];

Onyx.connect({
key: ONYXKEYS.QUEUE_FLUSHED_DATA,
callback: (val) => {
if (!val) {
return;
}
queueFlushedDataToStore = val;
},
});

function saveQueueFlushedData(...onyxUpdates: OnyxUpdate[]) {
const newValue = [...queueFlushedDataToStore, ...onyxUpdates];
// eslint-disable-next-line rulesdir/prefer-actions-set-data
return Onyx.set(ONYXKEYS.QUEUE_FLUSHED_DATA, newValue).then(() => {
Log.info('[SequentialQueue] QueueFlushedData has been stored.', false, {newValue});
});
}
function clearQueueFlushedData() {
// eslint-disable-next-line rulesdir/prefer-actions-set-data
return Onyx.set(ONYXKEYS.QUEUE_FLUSHED_DATA, null).then(() => {
queueFlushedDataToStore.length = 0;
Log.info('[SequentialQueue] QueueFlushedData has been cleared.');
});
}
function getQueueFlushedData() {
return queueFlushedDataToStore;
}

/**
Expand Down Expand Up @@ -119,6 +150,12 @@ function process(): Promise<void> {

Log.info('[SequentialQueue] Removing persisted request because it was processed successfully.', false, {request: requestToProcess});
endPersistedRequestAndRemoveFromQueue(requestToProcess);

if (requestToProcess.queueFlushedData) {
Log.info('[SequentialQueue] Will store queueFlushedData.', false, {queueFlushedData: requestToProcess.queueFlushedData});
saveQueueFlushedData(...requestToProcess.queueFlushedData);
}

sequentialQueueRequestThrottle.clear();
return process();
})
Expand Down Expand Up @@ -207,7 +244,17 @@ function flush(shouldResetPromise = true) {

// The queue can be paused when we sync the data with backend so we should only update the Onyx data when the queue is empty
if (getAllPersistedRequests().length === 0) {
flushOnyxUpdatesQueue();
flushOnyxUpdatesQueue()?.then(() => {
const queueFlushedData = getQueueFlushedData();
if (queueFlushedData.length === 0) {
return;
}
Log.info('[SequentialQueue] Will store queueFlushedData.', false, {queueFlushedData});
Onyx.update(queueFlushedData).then(() => {
Log.info('[SequentialQueue] QueueFlushedData has been stored.', false, {queueFlushedData});
clearQueueFlushedData();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clearQueueFlushedData does not seem to clear the data from Onyx. Please have a look at the following test video.

57587-onyx-clear-issue.mp4

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It turns out that set(KEY, [])does not work. I changed tonull` and will try to figure it out

});
});
}
});
},
Expand Down Expand Up @@ -287,11 +334,11 @@ function push(newRequest: OnyxRequest) {

// If the queue is running this request will run once it has finished processing the current batch
if (isSequentialQueueRunning) {
isReadyPromise.then(() => flush());
isReadyPromise.then(() => flush(true));
return;
}

flush();
flush(true);
}

function getCurrentRequest(): Promise<void> {
Expand Down Expand Up @@ -322,5 +369,20 @@ function resetQueue(): void {
resolveIsReadyPromise?.();
}

export {flush, getCurrentRequest, isRunning, isPaused, push, waitForIdle, pause, unpause, process, resetQueue, sequentialQueueRequestThrottle};
export {
flush,
getCurrentRequest,
isPaused,
isRunning,
pause,
process,
push,
resetQueue,
sequentialQueueRequestThrottle,
unpause,
waitForIdle,
getQueueFlushedData,
saveQueueFlushedData,
clearQueueFlushedData,
};
export type {RequestError};
13 changes: 7 additions & 6 deletions src/libs/actions/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,18 +260,19 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false, isFullReconnect = fals
value: true,
},
],
successData: [
successData: [],
finallyData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.HAS_LOADED_APP,
value: true,
key: ONYXKEYS.IS_LOADING_REPORT_DATA,
value: false,
},
],
finallyData: [
queueFlushedData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.IS_LOADING_REPORT_DATA,
value: false,
key: ONYXKEYS.HAS_LOADED_APP,
value: true,
},
],
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy}: Reimbursemen
isNonUSDWorkspace={isNonUSDWorkspace}
setNonUSDBankAccountStep={setNonUSDBankAccountStep}
setUSDBankAccountStep={setUSDBankAccountStep}
policyID={policyIDParam}
/>
);
}
Expand Down
5 changes: 3 additions & 2 deletions src/pages/workspace/withPolicy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,11 @@ export default function <TProps extends WithPolicyProps, TRef>(
): React.ComponentType<Omit<TProps, keyof WithPolicyOnyxProps> & RefAttributes<TRef>> {
function WithPolicy(props: Omit<TProps, keyof WithPolicyOnyxProps>, ref: ForwardedRef<TRef>) {
const policyID = getPolicyIDFromRoute(props.route as PolicyRoute);

const [hasLoadedApp] = useOnyx(ONYXKEYS.HAS_LOADED_APP, {canBeMissing: true});
const [policy, policyResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: true});
const [policyDraft, policyDraftResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`, {canBeMissing: true});
const isLoadingPolicy = isLoadingOnyxValue(policyResults, policyDraftResults);
/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */
const isLoadingPolicy = !hasLoadedApp || isLoadingOnyxValue(policyResults, policyDraftResults);

if (policyID && policyID.length > 0) {
updateLastAccessedWorkspace(policyID);
Expand Down
3 changes: 3 additions & 0 deletions src/types/onyx/Request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ type OnyxData = {

/** Onyx instructions that are executed before request is made to the server */
optimisticData?: OnyxUpdate[];

/** Onyx instructions that are executed when Onyx queue is flushed */
queueFlushedData?: OnyxUpdate[];
};

/** HTTP request method names */
Expand Down
35 changes: 24 additions & 11 deletions tests/unit/SequentialQueueTest.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Onyx from 'react-native-onyx';
import type {OnyxUpdate} from 'react-native-onyx';
import {waitForActiveRequestsToBeEmpty} from '@libs/E2E/utils/NetworkInterceptor';
import {getAll, getLength, getOngoingRequest} from '@userActions/PersistedRequests';
import ONYXKEYS from '@src/ONYXKEYS';
Expand All @@ -13,18 +14,16 @@ const request: Request = {
successData: [{key: 'userMetadata', onyxMethod: 'set', value: {accountID: 1234}}],
failureData: [{key: 'userMetadata', onyxMethod: 'set', value: {}}],
};

describe('SequentialQueue', () => {
beforeAll(() => {
Onyx.init({
keys: ONYXKEYS,
});
beforeAll(() => {
Onyx.init({
keys: ONYXKEYS,
});
beforeEach(() => {
global.fetch = TestHelper.getGlobalFetchMock();
return Onyx.clear().then(waitForBatchedUpdates);
});

});
beforeEach(() => {
global.fetch = TestHelper.getGlobalFetchMock();
return Onyx.clear().then(waitForBatchedUpdates);
});
describe('SequentialQueue', () => {
it('should push one request and persist one', () => {
SequentialQueue.push(request);
expect(getLength()).toBe(1);
Expand Down Expand Up @@ -258,3 +257,17 @@ describe('SequentialQueue', () => {
expect(getAll().length).toBe(1);
});
});

describe('SequentialQueue - QueueFlushedData', () => {
it('should add to queueFlushedData', async () => {
const updates: OnyxUpdate[] = [{key: 'userMetadata', onyxMethod: 'set', value: {accountID: 1234}}];
await SequentialQueue.saveQueueFlushedData(...updates);
expect(SequentialQueue.getQueueFlushedData()).toEqual([{key: 'userMetadata', onyxMethod: 'set', value: {accountID: 1234}}]);
});
it('should clear queueFlushedData', async () => {
const updates: OnyxUpdate[] = [{key: 'userMetadata', onyxMethod: 'set', value: {accountID: 1234}}];
await SequentialQueue.saveQueueFlushedData(...updates);
await SequentialQueue.clearQueueFlushedData();
expect(SequentialQueue.getQueueFlushedData()).toEqual([]);
});
});