Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
cd961e4
memo header and reportScreenProps
sumo-slonik Nov 25, 2025
4360b72
add preload
sumo-slonik Nov 25, 2025
9062688
fix compiler in reports screen
sumo-slonik Dec 2, 2025
0b40de3
Merge branch 'main' into feature/kuba-nowakowski/improve_performance_…
sumo-slonik Dec 2, 2025
ef7241d
fix compiler
sumo-slonik Dec 2, 2025
66a4661
Merge branch 'main' into feature/kuba-nowakowski/improve_performance_…
sumo-slonik Dec 3, 2025
5ac39ed
fix preload commit, and dependency array
sumo-slonik Dec 3, 2025
72e13e0
add comment to custom logic
sumo-slonik Dec 3, 2025
5775107
Merge branch 'main' into feature/kuba-nowakowski/improve_performance_…
sumo-slonik Dec 3, 2025
49b4f8e
change order of preload arr
sumo-slonik Dec 4, 2025
2b2cbaa
Merge branch 'main' into feature/kuba-nowakowski/improve_performance_…
sumo-slonik Dec 4, 2025
221c028
Merge branch 'refs/heads/main' into feature/kuba-nowakowski/improve_p…
dariusz-biela Dec 17, 2025
66553b2
Merge branch 'main' into feature/kuba-nowakowski/improve_performance_…
dariusz-biela Dec 18, 2025
2afc2a2
Merge branch 'main' into feature/kuba-nowakowski/improve_performance_…
dariusz-biela Jan 12, 2026
8c9e056
Merge branch 'main' into feature/kuba-nowakowski/improve_performance_…
dariusz-biela Jan 12, 2026
b072b5c
chore: fix eslint errors
dariusz-biela Jan 12, 2026
427bcf6
fix: improve shouldShowNotFoundPage logic in ReportScreen
dariusz-biela Jan 12, 2026
188a321
Merge branch 'main' into feature/kuba-nowakowski/improve_performance_…
dariusz-biela Jan 13, 2026
be19b55
chore: removes useMemo from ReportsSplitNavigator
dariusz-biela Jan 14, 2026
84532e5
fix: add missing isInSidePanel prop to HeaderView
dariusz-biela Jan 14, 2026
b56f8c9
fix: prevent NotFound flash by adding firstRender guard and handling …
dariusz-biela Jan 15, 2026
cadb9e9
fix: redirect to parent report or Concierge when rendered report is d…
dariusz-biela Jan 20, 2026
9c637d2
Merge branch 'main' into feature/kuba-nowakowski/improve_performance_…
sumo-slonik Jan 23, 2026
5ddb9ac
comment usage of state inside of use effect
sumo-slonik Jan 23, 2026
f917245
comment usage of state inside of use effect
sumo-slonik Jan 23, 2026
7ca5741
fix prettier
sumo-slonik Jan 23, 2026
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
9 changes: 8 additions & 1 deletion src/components/Navigation/NavigationTabBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,15 @@ function NavigationTabBar({selectedTab, isTopLevelBar = false, shouldShowFloatin
name: CONST.TELEMETRY.SPAN_NAVIGATE_TO_INBOX_TAB,
op: CONST.TELEMETRY.SPAN_NAVIGATE_TO_INBOX_TAB,
});

if (!shouldUseNarrowLayout && isRoutePreloaded(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR)) {
// We use dispatch here because the correct screens and params are preloaded and set up in usePreloadFullScreenNavigators.
navigationRef.dispatch(StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR));
return;
}

Navigation.navigate(ROUTES.HOME);
}, [selectedTab]);
}, [selectedTab, shouldUseNarrowLayout]);

const [lastSearchParams] = useOnyx(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {canBeMissing: true});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useMemo, useState} from 'react';
import React, {useState} from 'react';
import usePermissions from '@hooks/usePermissions';
import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator';
import FreezeWrapper from '@libs/Navigation/AppNavigator/FreezeWrapper';
Expand Down Expand Up @@ -27,14 +27,11 @@ function ReportsSplitNavigator({route}: PlatformStackScreenProps<AuthScreensPara
const {isBetaEnabled} = usePermissions();
const splitNavigatorScreenOptions = useSplitNavigatorScreenOptions();

// Determine if the current URL indicates a transition.
const isTransitioning = useMemo(() => {
const currentURL = getCurrentUrl();
return currentURL.includes(ROUTES.TRANSITION_BETWEEN_APPS);
}, []);

const [initialReportID] = useState(() => {
const currentURL = getCurrentUrl();
// Determine if the current URL indicates a transition.
const isTransitioning = currentURL.includes(ROUTES.TRANSITION_BETWEEN_APPS);

const reportIdFromPath = currentURL && new URL(currentURL).pathname.match(CONST.REGEX.REPORT_ID_FROM_PATH)?.at(1);
if (reportIdFromPath) {
return reportIdFromPath;
Expand All @@ -54,6 +51,13 @@ function ReportsSplitNavigator({route}: PlatformStackScreenProps<AuthScreensPara
// This hook preloads the screens of adjacent tabs to make changing tabs faster.
usePreloadFullScreenNavigators();

const isOpenOnAdminRoom = shouldOpenOnAdminRoom();

const reportScreenInitialParams = {
reportID: initialReportID,
openOnAdminRoom: isOpenOnAdminRoom ? true : undefined,
};

return (
<FreezeWrapper>
<Split.Navigator
Expand All @@ -70,7 +74,7 @@ function ReportsSplitNavigator({route}: PlatformStackScreenProps<AuthScreensPara
/>
<Split.Screen
name={SCREENS.REPORT}
initialParams={{reportID: initialReportID, openOnAdminRoom: shouldOpenOnAdminRoom() ? true : undefined}}
initialParams={reportScreenInitialParams}
getComponent={loadReportScreen}
/>
</Split.Navigator>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import {getPreservedNavigatorState} from './createSplitNavigator/usePreserveNavi
// This timing is used to call the preload function after a tab change, when the initial tab screen has already been rendered.
const TIMING_TO_CALL_PRELOAD = 1000;

// Currently, only the Workspaces, Account tabs are preloaded. The remaining tabs will be supported soon.
const TABS_TO_PRELOAD = [NAVIGATION_TABS.WORKSPACES, NAVIGATION_TABS.SETTINGS];
// Currently the Inbox, Workspaces and Account tabs are preloaded, while Search is not preloaded due to its potential complexity.
const TABS_TO_PRELOAD = [NAVIGATION_TABS.HOME, NAVIGATION_TABS.WORKSPACES, NAVIGATION_TABS.SETTINGS];

function preloadWorkspacesTab(navigation: PlatformStackNavigationProp<AuthScreensParamList>) {
const state = getWorkspacesTabStateFromSessionStorage() ?? navigation.getState();
Expand Down
130 changes: 71 additions & 59 deletions src/pages/home/ReportScreen.tsx
Copy link
Contributor

Choose a reason for hiding this comment

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

image

Sorry, my work got slightly delayed because I was busy with the biometrics tasks.

Based on what Kuba shared with me, I prepared a simple solution for the Deleted Report Screen. However, it does have some drawbacks.
That’s why I’d like to propose a few additional approaches:


1. Solution based on Jakub’s proposal

software-mansion-labs#278

We add a state variable to the ReportScreen that stores whether the report was available in the current context.
The user needs to have rendered this ReportScreen before and then return to it later. Only in that case will they see the Deleted message.
If the user hasn’t opened this report before, or refreshes the page, or navigates back using the browser buttons, we lose this state and display the standard notFound page.


2. Persisting this state in Onyx

This would solve part of the problem, but if the user has never visited the report and it gets deleted by someone else, they will still see the notFound page.


3. Listening to all Report changes and storing missing IDs in Onyx

We could monitor all changes in Reports and store IDs of missing ones under a new Onyx key.
This may introduce performance overhead, since it requires listening to updates for all reports.
However, it allows us to detect most deletion events.


4. Storing deleted report IDs on the backend

This is the most complex solution to implement but provides the best UX, as it lets us reliably detect all deleted reports.


5. Do nothing

The PR already improves performance, and the notFound page already informs the user that something may have happened or that the report was deleted.


I kept the explanation brief to avoid overwhelming you with unnecessary details at this stage.
If anything is unclear, feel free to ask!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dubielzyk-expensify What do you think about this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Can't speak to the technical side, but I like that we now have a specific deleted empty state instead of not found.

cc @trjExpensify and @dannymcclain for thoughts though.

Copy link
Contributor

@dariusz-biela dariusz-biela Dec 19, 2025

Choose a reason for hiding this comment

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

@dubielzyk-expensify
I honestly can't find this "deleted empty state". Could you tell me how to enter this state?

From what I've noticed in production, depending on the situation, we either redirect immediately or display the "not found" screen:

image

Copy link
Contributor

Choose a reason for hiding this comment

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

Can't speak to the technical side, but I like that we now have a specific deleted empty state instead of not found.

Agree - I bet we could riff on that illustration but I dig using the trashcan, and I think having a dedicated "this was deleted" instead of "it's not here" is so much more clear.

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand your point of view and I agree with it. Unfortunately, every solution that would allow us to add this state introduces significant implementation overhead.

My recommendation would be to merge this PR and create a separate issue dedicated to the DeletedReportScreen. This PR is important because it significantly improves the UX by reducing loading times. With a new issue, we would be able to calmly discuss the technical aspects, especially since, as you can see, there are several possible implementation paths.

Regarding the current PR, it introduces a small change compared with the production version:

In production, navigating back to a deleted report sometimes redirects the user to another chat. This PR instead displays a NotFound screen, which I believe is a more predictable and intuitive behavior from the user's perspective. Additionally, this change brings us a step closer to the future implementation of the DeletedReportScreen, since the app will already start showing a placeholder (NotFound) in places where we plan to introduce that dedicated screen.

What do you think about this approach?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds okay to me, but keen to hear what @Expensify/product thinks

Copy link
Contributor

Choose a reason for hiding this comment

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

Discussed in slack and the descision is to keep this super simple now and just show the classic not found page https://expensify.slack.com/archives/C05LX9D6E07/p1767656608792629

Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ function ReportScreen({route, navigation, isInSidePanel = false}: ReportScreenPr
const reportActionIDFromRoute = route?.params?.reportActionID;
const isFocused = useIsFocused();
const prevIsFocused = usePrevious(isFocused);
const firstRenderRef = useRef(true);
const [firstRender, setFirstRender] = useState(true);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you explain the reason why use state instead of ref?

Copy link
Contributor Author

@sumo-slonik sumo-slonik Dec 3, 2025

Choose a reason for hiding this comment

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

Thanks to replacing useRef with useState, we were able to enable the React Compiler. The benefit we previously got from useRef was minimal anyway, because we were already using setState below, which triggered a re-render. Now that ref is no longer used inside the effect, the React Compiler can properly memoize the component, resulting in better performance.

Copy link
Contributor

Choose a reason for hiding this comment

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

Though this ref was introduced 2 years ago, last usage was 10 months ago.
We need to make sure that this removal doesn't reintroduce #55251

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This bug no longer occurs because newly created expenses are now displayed in the new report view, and in that view the issue does not appear when removing expense.

Screen.Recording.2025-12-04.at.10.20.34.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Screen.Recording.2025-12-04.at.10.48.17.mov

const isSkippingOpenReport = useRef(false);
const flatListRef = useRef<FlatList>(null);
Expand Down Expand Up @@ -311,8 +310,6 @@ function ReportScreen({route, navigation, isInSidePanel = false}: ReportScreenPr
const [isBannerVisible, setIsBannerVisible] = useState(true);
const [scrollPosition, setScrollPosition] = useState<ScrollPosition>({});

const wasReportAccessibleRef = useRef(false);
Copy link
Contributor

Choose a reason for hiding this comment

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

Need to confirm this removal won't reintroduce #65853, #65914.

This was previously removed in #65622 but reverted due to regression above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm already checking whether this doesn't reproduce. Thanks for finding it, because I have a feeling it might show up, since I think I had checked different cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I’m not sure what the correct behavior should be here. If we try to navigate to a deleted report, should we see the “Oops” screen or not?
Currently, on my branch, the screen is displayed (previously it wasn’t), but I saw an issue where “works as designed” was marked, stating that it should appear.

image

The message on the page also seems appropriate, since it informs us that we’re trying to navigate to an expense that has already been deleted.

Screen.Recording.2025-12-04.at.10.50.51.mov

It seems to me that it would be best if the @Expensify/design team spoke up about what the correct flow should be here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the @Expensify/design team decides it should be an upss page, I’ll keep it. If not, I’ll add navigation wherever they think it’s appropriate in that situation.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure exactly where I would expect to land when I went back to the inbox, but it wouldn't be a not found screen. @dubielzyk-expensify @Expensify/product-pr do y'all have any opinions on where a user should land here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

From a technical point of view, getting information about whether or not an expense is deleted is the first step to both navigating and showing information that an expense has been deleted. So I can do what you see fit.

Copy link
Contributor

Choose a reason for hiding this comment

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

My take would be that and basically just swap the text and illustration to this:

CleanShot 2025-12-08 at 13 52 38@2x

But curious to hear if @dannymcclain agrees. And @Expensify/product-pr 's take too

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that text and illustration is much better than a generic one when we know the absolute reason. The cloud guy is in a ton of places, and it's somewhat not as helpful when it's ambiguously positioned (i.e "it could be this, or that, maybe even this!").

That said, I generally don't really like the pattern of returning to an error screen if it can be avoided by removing the deleted report from the stack. So I think my preference would be something that accommodates that, really.

CC: @JmillsExpensify @mountiny

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm into that empty state because like Tom mentioned it's much more clear. But I definitely see his point about us purposely landing someone on an "error" page. I'm just having a hard time thinking of a sensible place to land someone.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I currently have a higher-priority task related to SAML. As soon as I’m done with it (most likely on Tuesday), I’ll take care of the fixes for the new empty state


const viewportOffsetTop = useViewportOffsetTop();

const {reportPendingAction, reportErrors} = getReportOfflinePendingActionAndErrors(report);
Expand Down Expand Up @@ -370,14 +367,6 @@ function ReportScreen({route, navigation, isInSidePanel = false}: ReportScreenPr
hideEmojiPicker(true);
}, [prevIsFocused, isFocused]);

useEffect(() => {
if (!report?.reportID) {
wasReportAccessibleRef.current = false;
return;
}
wasReportAccessibleRef.current = true;
}, [report?.reportID]);

const backTo = route?.params?.backTo as string;
const onBackButtonPress = useCallback(
(prioritizeBackTo = false) => {
Expand Down Expand Up @@ -410,40 +399,55 @@ function ReportScreen({route, navigation, isInSidePanel = false}: ReportScreenPr
[isInSidePanel, backTo, isInNarrowPaneModal, closeSidePanel],
);

let headerView = (
<HeaderView
reportID={reportIDFromRoute}
onNavigationMenuButtonClicked={onBackButtonPress}
report={report}
parentReportAction={parentReportAction}
shouldUseNarrowLayout={shouldUseNarrowLayout}
isInSidePanel={isInSidePanel}
/>
);
const headerView = useMemo(() => {
if (isTransactionThreadView) {
return (
<MoneyRequestHeader
report={report}
policy={policy}
parentReportAction={parentReportAction}
onBackButtonPress={onBackButtonPress}
/>
);
}

if (isTransactionThreadView) {
headerView = (
<MoneyRequestHeader
report={report}
policy={policy}
parentReportAction={parentReportAction}
onBackButtonPress={onBackButtonPress}
/>
);
}
if (isMoneyRequestOrInvoiceReport) {
return (
<MoneyReportHeader
report={report}
policy={policy}
transactionThreadReportID={transactionThreadReportID}
isLoadingInitialReportActions={reportMetadata.isLoadingInitialReportActions}
reportActions={reportActions}
onBackButtonPress={onBackButtonPress}
/>
);
}

if (isMoneyRequestOrInvoiceReport) {
headerView = (
<MoneyReportHeader
return (
<HeaderView
reportID={reportIDFromRoute}
onNavigationMenuButtonClicked={onBackButtonPress}
report={report}
policy={policy}
transactionThreadReportID={transactionThreadReportID}
isLoadingInitialReportActions={reportMetadata.isLoadingInitialReportActions}
reportActions={reportActions}
onBackButtonPress={onBackButtonPress}
parentReportAction={parentReportAction}
shouldUseNarrowLayout={shouldUseNarrowLayout}
Comment on lines +449 to +453

Choose a reason for hiding this comment

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

P2 Badge Pass isInSidePanel to HeaderView

When ReportScreen is rendered in the side panel, HeaderView relies on isInSidePanel to suppress the search router/side panel button and to show the correct back/close affordances. The refactor now omits this prop, so side-panel report screens will render the main-view header (wrong buttons/visibility) and lose the side-panel-specific behavior. This is user-visible whenever a report is opened in the side panel.

Useful? React with 👍 / 👎.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good finding. Report screen can also be in side panel so this should be tested too.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I tested it, and it changes the button from the back arrow to the close arrow, and it works.

I've already added a commit to this PR.

image

isInSidePanel={isInSidePanel}
/>
);
}
}, [
isTransactionThreadView,
isMoneyRequestOrInvoiceReport,
report,
policy,
parentReportAction,
onBackButtonPress,
transactionThreadReportID,
reportMetadata.isLoadingInitialReportActions,
reportActions,
reportIDFromRoute,
shouldUseNarrowLayout,
isInSidePanel,
]);

useEffect(() => {
if (!transactionThreadReportID || !route?.params?.reportActionID || !isOneTransactionThread(childReport, report, linkedAction)) {
Expand All @@ -462,7 +466,7 @@ function ReportScreen({route, navigation, isInSidePanel = false}: ReportScreenPr

const prevIsLinkedActionDeleted = usePrevious(linkedAction ? isLinkedActionDeleted : undefined);

const lastReportActionIDFromRoute = usePrevious(!firstRenderRef.current ? reportActionIDFromRoute : undefined);
const lastReportActionIDFromRoute = usePrevious(!firstRender ? reportActionIDFromRoute : undefined);

const [isNavigatingToDeletedAction, setIsNavigatingToDeletedAction] = useState(false);

Expand Down Expand Up @@ -498,25 +502,34 @@ function ReportScreen({route, navigation, isInSidePanel = false}: ReportScreenPr
const currentReportIDFormRoute = route.params?.reportID;

// eslint-disable-next-line rulesdir/no-negated-variables
const shouldShowNotFoundPage = useMemo(
(): boolean => {
if (shouldShowNotFoundLinkedAction) {
return true;
}
const shouldShowNotFoundPage = useMemo((): boolean => {
const isLoading = !!isLoadingApp || !!isLoadingReportData || !!reportMetadata?.isLoadingInitialReportActions;
const reportExists = !!reportID || !!isOptimisticDelete || !!userLeavingStatus;
const isInvalidReportPath = !!currentReportIDFormRoute && !isValidReportIDFromPath(currentReportIDFormRoute);

if (isLoadingApp !== false) {
return false;
}
if (shouldShowNotFoundLinkedAction) {
return true;
}

if (!wasReportAccessibleRef.current && !firstRenderRef.current && !reportID && !isOptimisticDelete && !reportMetadata?.isLoadingInitialReportActions && !userLeavingStatus) {
return true;
}
if (isLoading) {
return false;
}

return !!currentReportIDFormRoute && !isValidReportIDFromPath(currentReportIDFormRoute);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[firstRender, shouldShowNotFoundLinkedAction, reportID, isOptimisticDelete, reportMetadata?.isLoadingInitialReportActions, userLeavingStatus, currentReportIDFormRoute],
Comment on lines -533 to -534
Copy link
Contributor

@dariusz-biela dariusz-biela Jan 12, 2026

Choose a reason for hiding this comment

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

An incomplete dependency array was created in this PR #56819.
We have removed this change and this bug no longer occurs.

Tests

  1. Open any report
  2. Skeleton loader should visible while messages are being fetched
  3. Skeleton loader should disappear once data is loaded and be replaced with report actions.
  4. If there is no data fetched, there should be empty state component with "No activity yet" information.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add that test to the PR description please

Copy link
Contributor

Choose a reason for hiding this comment

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

@sumo-slonik
Can you add these tests to the PR description? I don't have permission to do that.

It might also be worth including information in the description that the redirect has been removed from the non-existent report and that we're now showing the "not found" state.

);
if (!reportExists) {
return true;
}

return isInvalidReportPath;
}, [
shouldShowNotFoundLinkedAction,
isLoadingApp,
isLoadingReportData,
reportMetadata?.isLoadingInitialReportActions,
reportID,
isOptimisticDelete,
userLeavingStatus,
currentReportIDFormRoute,
]);

const createOneTransactionThreadReport = useCallback(() => {
const currentReportTransaction = getReportTransactions(reportID).filter((transaction) => transaction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE);
Expand Down Expand Up @@ -693,8 +706,7 @@ function ReportScreen({route, navigation, isInSidePanel = false}: ReportScreenPr

useEffect(() => {
// We don't want this effect to run on the first render.
if (firstRenderRef.current) {
firstRenderRef.current = false;
if (firstRender) {
setFirstRender(false);
return;
}
Expand Down
Loading