diff --git a/packages/react-devtools-shared/src/__tests__/store-test.js b/packages/react-devtools-shared/src/__tests__/store-test.js
index 2e56462aac9a..0a62c089dd13 100644
--- a/packages/react-devtools-shared/src/__tests__/store-test.js
+++ b/packages/react-devtools-shared/src/__tests__/store-test.js
@@ -297,6 +297,269 @@ describe('Store', () => {
});
});
+ describe('Activity hidden state', () => {
+ // @reactVersion >= 19
+ it('should mark Activity subtree elements as hidden when mode is hidden', async () => {
+ const Activity = React.Activity || React.unstable_Activity;
+
+ function Child() {
+ return
child
;
+ }
+
+ function App({hidden}) {
+ return (
+
+
+
+ );
+ }
+
+ await actAsync(() => {
+ render();
+ });
+
+ // Activity element should be marked as hidden and collapsed
+ const activityElement = store.getElementAtIndex(1);
+ expect(activityElement.displayName).toBe('Activity');
+ expect(activityElement.isActivityHidden).toBe(true);
+ expect(activityElement.isInsideHiddenActivity).toBe(false);
+ expect(activityElement.isCollapsed).toBe(true);
+
+ // Expand to access children
+ store.toggleIsCollapsed(activityElement.id, false);
+
+ // Children should still be in the tree but marked as inside hidden Activity
+ const childElement = store.getElementAtIndex(2);
+ expect(childElement.displayName).toBe('Child');
+ expect(childElement.isInsideHiddenActivity).toBe(true);
+ });
+
+ // @reactVersion >= 19
+ it('should not mark Activity subtree as hidden when mode is visible', async () => {
+ const Activity = React.Activity || React.unstable_Activity;
+
+ function Child() {
+ return child
;
+ }
+
+ function App() {
+ return (
+
+
+
+ );
+ }
+
+ await actAsync(() => {
+ render();
+ });
+
+ const activityElement = store.getElementAtIndex(1);
+ expect(activityElement.displayName).toBe('Activity');
+ expect(activityElement.isActivityHidden).toBe(false);
+ expect(activityElement.isInsideHiddenActivity).toBe(false);
+ expect(activityElement.isCollapsed).toBe(false);
+
+ const childElement = store.getElementAtIndex(2);
+ expect(childElement.displayName).toBe('Child');
+ expect(childElement.isInsideHiddenActivity).toBe(false);
+ });
+
+ // @reactVersion >= 19
+ it('should update hidden state when Activity mode toggles', async () => {
+ const Activity = React.Activity || React.unstable_Activity;
+
+ function Child() {
+ return child
;
+ }
+
+ function App({hidden}) {
+ return (
+
+
+
+ );
+ }
+
+ // Start visible
+ await actAsync(() => {
+ render();
+ });
+
+ let activityElement = store.getElementAtIndex(1);
+ expect(activityElement.isActivityHidden).toBe(false);
+ expect(activityElement.isCollapsed).toBe(false);
+
+ let childElement = store.getElementAtIndex(2);
+ expect(childElement.isInsideHiddenActivity).toBe(false);
+
+ // Toggle to hidden — children remain but subtree collapses
+ await actAsync(() => {
+ render();
+ });
+
+ activityElement = store.getElementAtIndex(1);
+ expect(activityElement.isActivityHidden).toBe(true);
+ expect(activityElement.isCollapsed).toBe(true);
+
+ // Expand to verify children are still marked
+ store.toggleIsCollapsed(activityElement.id, false);
+
+ childElement = store.getElementAtIndex(2);
+ expect(childElement.displayName).toBe('Child');
+ expect(childElement.isInsideHiddenActivity).toBe(true);
+
+ // Toggle back to visible — subtree expands automatically
+ await actAsync(() => {
+ render();
+ });
+
+ activityElement = store.getElementAtIndex(1);
+ expect(activityElement.isActivityHidden).toBe(false);
+ expect(activityElement.isCollapsed).toBe(false);
+
+ childElement = store.getElementAtIndex(2);
+ expect(childElement.isInsideHiddenActivity).toBe(false);
+ });
+
+ // @reactVersion >= 19
+ it('should propagate hidden state to deeply nested children', async () => {
+ const Activity = React.Activity || React.unstable_Activity;
+
+ function GrandChild() {
+ return grandchild
;
+ }
+ function Child() {
+ return ;
+ }
+
+ function App({hidden}) {
+ return (
+
+
+
+ );
+ }
+
+ await actAsync(() => {
+ render();
+ });
+
+ const activityElement = store.getElementAtIndex(1);
+ expect(activityElement.displayName).toBe('Activity');
+ expect(activityElement.isActivityHidden).toBe(true);
+ expect(activityElement.isCollapsed).toBe(true);
+
+ // Expand to access children
+ store.toggleIsCollapsed(activityElement.id, false);
+
+ const childElement = store.getElementAtIndex(2);
+ expect(childElement.displayName).toBe('Child');
+ expect(childElement.isInsideHiddenActivity).toBe(true);
+
+ const grandChildElement = store.getElementAtIndex(3);
+ expect(grandChildElement.displayName).toBe('GrandChild');
+ expect(grandChildElement.isInsideHiddenActivity).toBe(true);
+ });
+
+ // @reactVersion >= 19
+ it('should collapse hidden Activity subtree by default', async () => {
+ const Activity = React.Activity || React.unstable_Activity;
+
+ function Child() {
+ return child
;
+ }
+
+ function App({hidden}) {
+ return (
+
+
+
+ );
+ }
+
+ // Hidden Activity should be collapsed
+ await actAsync(() => {
+ render();
+ });
+
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ ▾
+ ▸
+ `);
+
+ // Toggle to visible — should expand
+ await actAsync(() => {
+ render();
+ });
+
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ ▾
+ ▾
+
+ `);
+
+ // Toggle back to hidden — should collapse again
+ await actAsync(() => {
+ render();
+ });
+
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ ▾
+ ▸
+ `);
+ });
+
+ // @reactVersion >= 19
+ it('should dim nested visible Activity inside a hidden Activity', async () => {
+ const Activity = React.Activity || React.unstable_Activity;
+
+ function Leaf() {
+ return leaf
;
+ }
+
+ function App() {
+ return (
+
+
+
+
+
+ );
+ }
+
+ await actAsync(() => {
+ render();
+ });
+
+ // Outer Activity: hidden, collapsed, not dimmed itself
+ const outerActivity = store.getElementAtIndex(1);
+ expect(outerActivity.displayName).toBe('Activity');
+ expect(outerActivity.nameProp).toBe('outer');
+ expect(outerActivity.isActivityHidden).toBe(true);
+ expect(outerActivity.isInsideHiddenActivity).toBe(false);
+ expect(outerActivity.isCollapsed).toBe(true);
+
+ // Expand to access inner elements
+ store.toggleIsCollapsed(outerActivity.id, false);
+
+ // Inner Activity: visible, but inside hidden outer so still dimmed
+ const innerActivity = store.getElementAtIndex(2);
+ expect(innerActivity.displayName).toBe('Activity');
+ expect(innerActivity.nameProp).toBe('inner');
+ expect(innerActivity.isActivityHidden).toBe(false);
+ expect(innerActivity.isInsideHiddenActivity).toBe(true);
+
+ // Leaf: inside both, dimmed
+ const leaf = store.getElementAtIndex(3);
+ expect(leaf.displayName).toBe('Leaf');
+ expect(leaf.isInsideHiddenActivity).toBe(true);
+ });
+ });
+
describe('collapseNodesByDefault:false', () => {
beforeEach(() => {
store.collapseNodesByDefault = false;
@@ -3361,9 +3624,10 @@ describe('Store', () => {
expect(store).toMatchInlineSnapshot(`
[root]
▾
-
+ ▸
[suspense-root] rects={[{x:1,y:2,width:15,height:1}]}
+
`);
@@ -3378,7 +3642,7 @@ describe('Store', () => {
expect(store).toMatchInlineSnapshot(`
[root]
▾
- ▾
+ ▾
▾
▾
@@ -3397,9 +3661,10 @@ describe('Store', () => {
expect(store).toMatchInlineSnapshot(`
[root]
▾
-
+ ▸
[suspense-root] rects={[{x:1,y:2,width:15,height:1}, {x:1,y:2,width:15,height:1}]}
+
`);
@@ -3411,7 +3676,7 @@ describe('Store', () => {
expect(store).toMatchInlineSnapshot(`
[root]
▾
- ▾
+ ▾
▾
▾
@@ -3604,7 +3869,7 @@ describe('Store', () => {
expect(store).toMatchInlineSnapshot(`
[root]
-
+ ▸
`);
await actAsync(() => {
@@ -3613,7 +3878,7 @@ describe('Store', () => {
expect(store).toMatchInlineSnapshot(`
[root]
- ▾
+ ▾
▾
`);
diff --git a/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js b/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js
index f29801b95e9e..1ef17e4c5475 100644
--- a/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js
+++ b/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js
@@ -229,9 +229,9 @@ describe('Store component filters', () => {
expect(store).toMatchInlineSnapshot(`
[root]
- ▾
+ ▾
-
+ ▸
`);
await actAsync(
@@ -244,6 +244,7 @@ describe('Store component filters', () => {
expect(store).toMatchInlineSnapshot(`
[root]
+
`);
await actAsync(
@@ -255,9 +256,9 @@ describe('Store component filters', () => {
expect(store).toMatchInlineSnapshot(`
[root]
- ▾
+ ▾
-
+ ▸
`);
}
});
@@ -871,12 +872,12 @@ describe('Store component filters', () => {
expect(store).toMatchInlineSnapshot(`
[root]
▾
- ▾
+ ▾
▾
▾
▾
- ▾
+ ▾
▾
▾
@@ -896,12 +897,12 @@ describe('Store component filters', () => {
expect(store).toMatchInlineSnapshot(`
[root]
- ▾
+ ▾
▾
▾
▾
- ▸
+ ▸
[suspense-root] rects={[{x:1,y:2,width:4,height:1}, {x:1,y:2,width:13,height:1}]}
@@ -912,12 +913,12 @@ describe('Store component filters', () => {
expect(store).toMatchInlineSnapshot(`
[root]
▾
- ▾
+ ▾
▾
▾
▾
- ▾
+ ▾
▾
▾
diff --git a/packages/react-devtools-shared/src/backend/fiber/renderer.js b/packages/react-devtools-shared/src/backend/fiber/renderer.js
index aa7fe9d6ee84..1193d23b469c 100644
--- a/packages/react-devtools-shared/src/backend/fiber/renderer.js
+++ b/packages/react-devtools-shared/src/backend/fiber/renderer.js
@@ -43,6 +43,8 @@ import {
ElementTypeActivity,
ElementTypeVirtual,
StrictMode,
+ ActivityHiddenMode,
+ ActivityVisibleMode,
} from 'react-devtools-shared/src/frontend/types';
import {
deletePathInObject,
@@ -2407,6 +2409,20 @@ export function attach(
pushOperation(StrictMode);
}
}
+
+ // If this is an Activity component, check if it's hidden.
+ if (fiber.tag === ActivityComponent) {
+ const offscreenChild = fiber.child;
+ if (
+ offscreenChild !== null &&
+ offscreenChild.tag === OffscreenComponent &&
+ offscreenChild.memoizedState !== null
+ ) {
+ pushOperation(TREE_OPERATION_SET_SUBTREE_MODE);
+ pushOperation(id);
+ pushOperation(ActivityHiddenMode);
+ }
+ }
}
let componentLogsEntry = fiberToComponentLogsMap.get(fiber);
@@ -3071,6 +3087,17 @@ export function attach(
}
}
+ // Returns true if this is a hidden OffscreenComponent that belongs to
+ // an Activity boundary (as opposed to Suspense). Activity's children
+ // should remain visible in the DevTools tree even when hidden.
+ function isActivityHiddenOffscreen(fiber: Fiber): boolean {
+ return (
+ isHiddenOffscreen(fiber) &&
+ fiber.return !== null &&
+ fiber.return.tag === ActivityComponent
+ );
+ }
+
/**
* Offscreen of suspended Suspense
*/
@@ -3975,7 +4002,16 @@ export function attach(
isInDisconnectedSubtree = stashedDisconnected;
}
} else if (isHiddenOffscreen(fiber)) {
- // hidden Activity is noisy.
+ if (isActivityHiddenOffscreen(fiber)) {
+ // Activity's hidden children should still be visible in DevTools.
+ if (fiber.child !== null) {
+ mountChildrenRecursively(
+ fiber.child,
+ traceNearestHostComponentUpdate,
+ );
+ }
+ }
+ // Otherwise, hidden Offscreen (e.g. non-Activity) is noisy.
// Including it may show overlapping Suspense rects
} else if (fiber.tag === SuspenseComponent && OffscreenComponent === -1) {
// Legacy Suspense without the Offscreen wrapper. For the modern Suspense we just handle the
@@ -4308,8 +4344,9 @@ export function attach(
while (child !== null) {
if (child.kind === FILTERED_FIBER_INSTANCE) {
const fiber = child.data;
- if (isHiddenOffscreen(fiber)) {
+ if (isHiddenOffscreen(fiber) && !isActivityHiddenOffscreen(fiber)) {
// The children of this Offscreen are hidden so they don't get added.
+ // Activity's hidden children are still shown in the tree.
} else {
addUnfilteredChildrenIDs(child, nextChildren);
}
@@ -5093,22 +5130,42 @@ export function attach(
updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren;
}
} else if (nextIsHidden) {
- if (prevWasHidden) {
+ if (isActivityHiddenOffscreen(nextFiber)) {
+ // Activity's hidden children stay visible in the DevTools tree.
+ // Whether staying hidden or transitioning to hidden, update normally.
+ updateFlags |= updateChildrenRecursively(
+ nextFiber.child,
+ prevFiber.child,
+ traceNearestHostComponentUpdate,
+ );
+ } else if (prevWasHidden) {
// still hidden. Nothing to do.
} else {
// We're hiding the children. Remove them from the Frontend
unmountRemainingChildren();
}
} else if (prevWasHidden && !nextIsHidden) {
- // Since we don't mount hidden children and unmount children when hiding,
- // we need to enter the mount path when revealing.
- const nextChildSet = nextFiber.child;
- if (nextChildSet !== null) {
- mountChildrenRecursively(
- nextChildSet,
+ if (
+ nextFiber.return !== null &&
+ nextFiber.return.tag === ActivityComponent
+ ) {
+ // Activity children were never unmounted, so just update normally.
+ updateFlags |= updateChildrenRecursively(
+ nextFiber.child,
+ prevFiber.child,
traceNearestHostComponentUpdate,
);
- updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren;
+ } else {
+ // Since we don't mount hidden children and unmount children when hiding,
+ // we need to enter the mount path when revealing.
+ const nextChildSet = nextFiber.child;
+ if (nextChildSet !== null) {
+ mountChildrenRecursively(
+ nextChildSet,
+ traceNearestHostComponentUpdate,
+ );
+ updateFlags |= ShouldResetChildren | ShouldResetSuspenseChildren;
+ }
}
} else if (
nextFiber.tag === SuspenseComponent &&
@@ -5242,6 +5299,31 @@ export function attach(
}
if (fiberInstance !== null) {
+ // Detect Activity hidden/visible mode changes.
+ if (
+ nextFiber.tag === ActivityComponent &&
+ fiberInstance.kind === FIBER_INSTANCE
+ ) {
+ const prevOffscreen = prevFiber.child;
+ const nextOffscreen = nextFiber.child;
+ if (
+ prevOffscreen !== null &&
+ nextOffscreen !== null &&
+ prevOffscreen.tag === OffscreenComponent &&
+ nextOffscreen.tag === OffscreenComponent
+ ) {
+ const prevHidden = prevOffscreen.memoizedState !== null;
+ const nextHidden = nextOffscreen.memoizedState !== null;
+ if (prevHidden !== nextHidden) {
+ pushOperation(TREE_OPERATION_SET_SUBTREE_MODE);
+ pushOperation(fiberInstance.id);
+ pushOperation(
+ nextHidden ? ActivityHiddenMode : ActivityVisibleMode,
+ );
+ }
+ }
+ }
+
removePreviousSuspendedBy(
fiberInstance,
previousSuspendedBy,
@@ -5384,9 +5466,11 @@ export function attach(
if (
(child.kind === FIBER_INSTANCE ||
child.kind === FILTERED_FIBER_INSTANCE) &&
- isHiddenOffscreen(child.data)
+ isHiddenOffscreen(child.data) &&
+ !isActivityHiddenOffscreen(child.data)
) {
// This instance's children should remain disconnected.
+ // Activity's hidden children are still shown in the tree.
} else {
reconnectChildrenRecursively(child);
}
diff --git a/packages/react-devtools-shared/src/devtools/store.js b/packages/react-devtools-shared/src/devtools/store.js
index 3849da9e5736..d7f857f7049e 100644
--- a/packages/react-devtools-shared/src/devtools/store.js
+++ b/packages/react-devtools-shared/src/devtools/store.js
@@ -48,7 +48,11 @@ import {
BRIDGE_PROTOCOL,
currentBridgeProtocol,
} from 'react-devtools-shared/src/bridge';
-import {StrictMode} from 'react-devtools-shared/src/frontend/types';
+import {
+ StrictMode,
+ ActivityHiddenMode,
+ ActivityVisibleMode,
+} from 'react-devtools-shared/src/frontend/types';
import {withPermissionsCheck} from 'react-devtools-shared/src/frontend/utils/withPermissionsCheck';
import type {
@@ -1491,6 +1495,8 @@ export default class Store extends EventEmitter<{
id,
isCollapsed: false, // Never collapse roots; it would hide the entire tree.
isStrictModeNonCompliant,
+ isActivityHidden: false,
+ isInsideHiddenActivity: false,
key: null,
nameProp: null,
ownerID: 0,
@@ -1560,6 +1566,10 @@ export default class Store extends EventEmitter<{
id,
isCollapsed: this._collapseNodesByDefault,
isStrictModeNonCompliant: parentElement.isStrictModeNonCompliant,
+ isActivityHidden: false,
+ isInsideHiddenActivity:
+ parentElement.isInsideHiddenActivity ||
+ parentElement.isActivityHidden,
key,
nameProp,
ownerID,
@@ -1728,6 +1738,42 @@ export default class Store extends EventEmitter<{
this._recursivelyUpdateSubtree(id, element => {
element.isStrictModeNonCompliant = false;
});
+ } else if (mode === ActivityHiddenMode) {
+ const element = this._idToElement.get(id);
+ if (element != null) {
+ element.isActivityHidden = true;
+ element.children.forEach(childID =>
+ this._recursivelyUpdateSubtree(childID, child => {
+ child.isInsideHiddenActivity = true;
+ }),
+ );
+ // Collapse hidden Activity subtrees by default.
+ if (!element.isCollapsed) {
+ element.isCollapsed = true;
+ if (element.children.length > 0) {
+ const weightDelta = 1 - element.weight;
+ const parentElement = this._idToElement.get(element.parentID);
+ this._adjustParentTreeWeight(parentElement, weightDelta);
+ }
+ }
+ }
+ } else if (mode === ActivityVisibleMode) {
+ const element = this._idToElement.get(id);
+ if (element != null) {
+ element.isActivityHidden = false;
+ element.children.forEach(childID =>
+ this._recursivelyUpdateSubtree(childID, child => {
+ child.isInsideHiddenActivity = false;
+ }),
+ );
+ // Expand Activity subtree when it becomes visible.
+ if (element.isCollapsed && element.children.length > 0) {
+ element.isCollapsed = false;
+ const weightDelta = element.weight - 1;
+ const parentElement = this._idToElement.get(element.parentID);
+ this._adjustParentTreeWeight(parentElement, weightDelta);
+ }
+ }
}
if (__DEBUG__) {
@@ -2075,7 +2121,9 @@ export default class Store extends EventEmitter<{
const previousHasUniqueSuspenders = suspense.hasUniqueSuspenders;
debug(
'Suspender changes',
- `Suspense node ${id} unique suspenders set to ${String(hasUniqueSuspenders)} (was ${String(previousHasUniqueSuspenders)})`,
+ `Suspense node ${id} unique suspenders set to ${String(
+ hasUniqueSuspenders,
+ )} (was ${String(previousHasUniqueSuspenders)})`,
);
}
diff --git a/packages/react-devtools-shared/src/devtools/utils.js b/packages/react-devtools-shared/src/devtools/utils.js
index b6438b47623c..876e01345b45 100644
--- a/packages/react-devtools-shared/src/devtools/utils.js
+++ b/packages/react-devtools-shared/src/devtools/utils.js
@@ -10,6 +10,7 @@
import JSON5 from 'json5';
import type {ReactFunctionLocation} from 'shared/ReactTypes';
+import {ElementTypeActivity} from 'react-devtools-shared/src/frontend/types';
import type {
Element,
SuspenseNode,
@@ -44,6 +45,11 @@ export function printElement(
const hocs =
hocDisplayNames === null ? '' : ` [${hocDisplayNames.join('][')}]`;
+ let mode = '';
+ if (element.type === ElementTypeActivity) {
+ mode = ` mode="${element.isActivityHidden ? 'hidden' : 'visible'}"`;
+ }
+
let suffix = '';
if (includeWeight) {
suffix = ` (${element.isCollapsed ? 1 : element.weight})`;
@@ -51,7 +57,7 @@ export function printElement(
return `${' '.repeat(element.depth + 1)}${prefix} <${
element.displayName || 'null'
- }${key}${name}>${hocs}${suffix}`;
+ }${key}${name}${mode}>${hocs}${suffix}`;
}
function printRects(rects: SuspenseNode['rects']): string {
diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Element.js b/packages/react-devtools-shared/src/devtools/views/Components/Element.js
index 43e611fd1bd5..da71f86dd797 100644
--- a/packages/react-devtools-shared/src/devtools/views/Components/Element.js
+++ b/packages/react-devtools-shared/src/devtools/views/Components/Element.js
@@ -126,6 +126,8 @@ export default function Element({data, index, style}: Props): React.Node {
displayName,
hocDisplayNames,
isStrictModeNonCompliant,
+ isActivityHidden,
+ isInsideHiddenActivity,
key,
nameProp,
compiledWithForget,
@@ -168,9 +170,15 @@ export default function Element({data, index, style}: Props): React.Node {
onMouseLeave={handleMouseLeave}
onMouseDown={handleClick}
onDoubleClick={handleDoubleClick}
+ title={
+ isInsideHiddenActivity
+ ? 'This component is inside a hidden Activity subtree.'
+ : undefined
+ }
style={{
...style,
paddingLeft: elementOffset,
+ opacity: isInsideHiddenActivity ? 0.75 : 1,
}}
data-testname="ComponentTreeListItem">
{/* This wrapper is used by Tree for measurement purposes. */}
@@ -207,6 +215,18 @@ export default function Element({data, index, style}: Props): React.Node {
)}
+ {element.type === ElementTypeActivity && (
+
+ mode="
+
+ {isActivityHidden ? 'hidden' : 'visible'}
+
+ "
+
+ )}
+
+ {name}
+
+
+ );
+}
+
+function Bio() {
+ return This is a bio section.
;
+}
+
+export default function ActivityTree() {
+ const [mode, setMode] = useState('hidden');
+
+ if (Activity == null) {
+ return null;
+ }
+
+ return (
+ <>
+ Activity
+
+
+
+
+
+ >
+ );
+}
diff --git a/packages/react-devtools-shell/src/app/index.js b/packages/react-devtools-shell/src/app/index.js
index 473cc40c3bef..d23b8ca7a451 100644
--- a/packages/react-devtools-shell/src/app/index.js
+++ b/packages/react-devtools-shell/src/app/index.js
@@ -20,6 +20,7 @@ import ErrorBoundaries from './ErrorBoundaries';
import PartiallyStrictApp from './PartiallyStrictApp';
import Segments from './Segments';
import SuspenseTree from './SuspenseTree';
+import ActivityTree from './ActivityTree';
import TraceUpdatesTest from './TraceUpdatesTest';
import {ignoreErrors, ignoreLogs, ignoreWarnings} from './console';
@@ -114,6 +115,7 @@ function mountTestApp() {
mountApp(SuspenseTree);
mountApp(DeeplyNestedComponents);
mountApp(Iframe);
+ mountApp(ActivityTree);
mountApp(TraceUpdatesTest);
mountApp(Segments);