diff --git a/apps/mobile/src/app/(app)/_layout.tsx b/apps/mobile/src/app/(app)/_layout.tsx
index 52ea0e82740..33d0e9ef843 100644
--- a/apps/mobile/src/app/(app)/_layout.tsx
+++ b/apps/mobile/src/app/(app)/_layout.tsx
@@ -30,6 +30,7 @@ import { useSecurityLifecycleInvalidation } from '@/lib/hooks/use-security-lifec
import { CachePersistenceMount } from '@/lib/persist/cache-persistence-mount';
import { SystemSearchIndexMount } from '@/lib/system-search-index-mount';
import { ToolSummaryTranslationRetryMount } from '@/lib/tool-summary-translation/tool-summary-translation-retry-mount';
+import { TabBarLabelContext } from '@/lib/tab-bar-clearance';
import { useTRPC } from '@/lib/trpc';
/**
@@ -134,97 +135,101 @@ export default function AppLayout() {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/_layout.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/_layout.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/_layout.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/_layout.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/focus-areas.mounted.test.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/focus-areas.mounted.test.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/focus-areas.mounted.test.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/focus-areas.mounted.test.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/focus-areas.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/focus-areas.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/focus-areas.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/focus-areas.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/gate.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/gate.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/gate.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/gate.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/instructions.mounted.test.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/instructions.mounted.test.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/instructions.mounted.test.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/instructions.mounted.test.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/instructions.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/instructions.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/instructions.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/instructions.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/repos.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/repos.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/repos.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/repos.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/style.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/style.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/style.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/(edit)/style.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/_layout.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/_layout.tsx
similarity index 87%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/_layout.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/_layout.tsx
index 88b793d5cb0..b24e8929bad 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/_layout.tsx
+++ b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/_layout.tsx
@@ -11,7 +11,7 @@ export default function CodeReviewerPlatformLayout() {
const params = useValidatedReviewerRouteParams();
if (!params) {
- return ;
+ return ;
}
return ;
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/index.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/index.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/index.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/[platform]/index.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/index.mounted.test.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/index.mounted.test.tsx
similarity index 89%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/index.mounted.test.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/index.mounted.test.tsx
index ebb461197ec..efc078bfbba 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/index.mounted.test.tsx
+++ b/apps/mobile/src/app/(app)/code-reviewer/[scope]/index.mounted.test.tsx
@@ -50,13 +50,13 @@ beforeEach(() => {
});
describe('CodeReviewerScopeRoute invalid scope', () => {
- it('renders InvalidRouteState with the profile backTo when scope is undefined', () => {
+ it('renders InvalidRouteState with the Code Reviewer backTo when scope is undefined', () => {
useLocalSearchParamsMock.mockReturnValue({ scope: undefined });
const renderer = mountRoute();
const invalid = findByType(renderer.root, 'InvalidRouteState');
expect(invalid).toHaveLength(1);
- expect(propOf(invalid[0], 'backTo')).toBe('/(app)/(tabs)/(3_profile)');
+ expect(propOf(invalid[0], 'backTo')).toBe('/(app)/code-reviewer');
expect(findByType(renderer.root, 'PlatformListScreen')).toHaveLength(0);
act(() => {
@@ -64,13 +64,13 @@ describe('CodeReviewerScopeRoute invalid scope', () => {
});
});
- it('renders InvalidRouteState with the profile backTo when scope is an array', () => {
+ it('renders InvalidRouteState with the Code Reviewer backTo when scope is an array', () => {
useLocalSearchParamsMock.mockReturnValue({ scope: ['personal', 'org'] });
const renderer = mountRoute();
const invalid = findByType(renderer.root, 'InvalidRouteState');
expect(invalid).toHaveLength(1);
- expect(propOf(invalid[0], 'backTo')).toBe('/(app)/(tabs)/(3_profile)');
+ expect(propOf(invalid[0], 'backTo')).toBe('/(app)/code-reviewer');
expect(findByType(renderer.root, 'PlatformListScreen')).toHaveLength(0);
act(() => {
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/index.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/index.tsx
similarity index 86%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/index.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/index.tsx
index 7d5feaf312e..0584c7e7365 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/index.tsx
+++ b/apps/mobile/src/app/(app)/code-reviewer/[scope]/index.tsx
@@ -9,7 +9,7 @@ export default function CodeReviewerScopeRoute() {
const scope = parseParam(rawScope);
if (!scope) {
- return ;
+ return ;
}
return ;
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/manual-review.mounted.test.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/manual-review.mounted.test.tsx
similarity index 89%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/manual-review.mounted.test.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/manual-review.mounted.test.tsx
index ea0d669103b..fa14e241056 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/manual-review.mounted.test.tsx
+++ b/apps/mobile/src/app/(app)/code-reviewer/[scope]/manual-review.mounted.test.tsx
@@ -50,13 +50,13 @@ beforeEach(() => {
});
describe('CodeReviewerManualReviewRoute invalid scope', () => {
- it('renders InvalidRouteState with the profile backTo when scope is undefined', () => {
+ it('renders InvalidRouteState with the Code Reviewer backTo when scope is undefined', () => {
useLocalSearchParamsMock.mockReturnValue({ scope: undefined });
const renderer = mountRoute();
const invalid = findByType(renderer.root, 'InvalidRouteState');
expect(invalid).toHaveLength(1);
- expect(propOf(invalid[0], 'backTo')).toBe('/(app)/(tabs)/(3_profile)');
+ expect(propOf(invalid[0], 'backTo')).toBe('/(app)/code-reviewer');
expect(findByType(renderer.root, 'ManualReviewScreen')).toHaveLength(0);
act(() => {
@@ -64,13 +64,13 @@ describe('CodeReviewerManualReviewRoute invalid scope', () => {
});
});
- it('renders InvalidRouteState with the profile backTo when scope is an array', () => {
+ it('renders InvalidRouteState with the Code Reviewer backTo when scope is an array', () => {
useLocalSearchParamsMock.mockReturnValue({ scope: ['personal', 'org'] });
const renderer = mountRoute();
const invalid = findByType(renderer.root, 'InvalidRouteState');
expect(invalid).toHaveLength(1);
- expect(propOf(invalid[0], 'backTo')).toBe('/(app)/(tabs)/(3_profile)');
+ expect(propOf(invalid[0], 'backTo')).toBe('/(app)/code-reviewer');
expect(findByType(renderer.root, 'ManualReviewScreen')).toHaveLength(0);
act(() => {
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/manual-review.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/manual-review.tsx
similarity index 86%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/manual-review.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/manual-review.tsx
index 17786d4d302..95a78734be1 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/manual-review.tsx
+++ b/apps/mobile/src/app/(app)/code-reviewer/[scope]/manual-review.tsx
@@ -9,7 +9,7 @@ export default function CodeReviewerManualReviewRoute() {
const scope = parseParam(rawScope);
if (!scope) {
- return ;
+ return ;
}
return ;
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/review-memory.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/review-memory.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/review-memory.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/review-memory.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/[id].mounted.test.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/[id].mounted.test.tsx
similarity index 87%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/[id].mounted.test.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/[id].mounted.test.tsx
index 96b5e994d95..34fbe70a258 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/[id].mounted.test.tsx
+++ b/apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/[id].mounted.test.tsx
@@ -50,13 +50,13 @@ beforeEach(() => {
});
describe('CodeReviewerReviewDetailRoute invalid scope', () => {
- it('renders InvalidRouteState with the profile backTo when scope is undefined', () => {
+ it('renders InvalidRouteState with the Code Reviewer backTo when scope is undefined', () => {
useLocalSearchParamsMock.mockReturnValue({ scope: undefined, id: 'rev-1' });
const renderer = mountRoute();
const invalid = findByType(renderer.root, 'InvalidRouteState');
expect(invalid).toHaveLength(1);
- expect(propOf(invalid[0], 'backTo')).toBe('/(app)/(tabs)/(3_profile)');
+ expect(propOf(invalid[0], 'backTo')).toBe('/(app)/code-reviewer');
expect(findByType(renderer.root, 'ReviewDetailScreen')).toHaveLength(0);
act(() => {
@@ -64,13 +64,13 @@ describe('CodeReviewerReviewDetailRoute invalid scope', () => {
});
});
- it('renders InvalidRouteState with the profile backTo when scope is an array', () => {
+ it('renders InvalidRouteState with the Code Reviewer backTo when scope is an array', () => {
useLocalSearchParamsMock.mockReturnValue({ scope: ['personal', 'org'], id: 'rev-1' });
const renderer = mountRoute();
const invalid = findByType(renderer.root, 'InvalidRouteState');
expect(invalid).toHaveLength(1);
- expect(propOf(invalid[0], 'backTo')).toBe('/(app)/(tabs)/(3_profile)');
+ expect(propOf(invalid[0], 'backTo')).toBe('/(app)/code-reviewer');
expect(findByType(renderer.root, 'ReviewDetailScreen')).toHaveLength(0);
act(() => {
@@ -86,9 +86,7 @@ describe('CodeReviewerReviewDetailRoute invalid id', () => {
const invalid = findByType(renderer.root, 'InvalidRouteState');
expect(invalid).toHaveLength(1);
- expect(propOf(invalid[0], 'backTo')).toBe(
- '/(app)/(tabs)/(3_profile)/code-reviewer/personal/reviews'
- );
+ expect(propOf(invalid[0], 'backTo')).toBe('/(app)/code-reviewer/personal/reviews');
expect(findByType(renderer.root, 'ReviewDetailScreen')).toHaveLength(0);
act(() => {
@@ -102,9 +100,7 @@ describe('CodeReviewerReviewDetailRoute invalid id', () => {
const invalid = findByType(renderer.root, 'InvalidRouteState');
expect(invalid).toHaveLength(1);
- expect(propOf(invalid[0], 'backTo')).toBe(
- '/(app)/(tabs)/(3_profile)/code-reviewer/personal/reviews'
- );
+ expect(propOf(invalid[0], 'backTo')).toBe('/(app)/code-reviewer/personal/reviews');
expect(findByType(renderer.root, 'ReviewDetailScreen')).toHaveLength(0);
act(() => {
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/[id].tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/[id].tsx
similarity index 85%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/[id].tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/[id].tsx
index 104d78a912c..a459115c49b 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/[id].tsx
+++ b/apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/[id].tsx
@@ -11,9 +11,7 @@ export default function CodeReviewerReviewDetailRoute() {
if (!scope || !reviewId) {
const backTo = (
- scope
- ? `/(app)/(tabs)/(3_profile)/code-reviewer/${scope}/reviews`
- : '/(app)/(tabs)/(3_profile)'
+ scope ? `/(app)/code-reviewer/${scope}/reviews` : '/(app)/code-reviewer'
) as Href;
return ;
}
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/index.mounted.test.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/index.mounted.test.tsx
similarity index 89%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/index.mounted.test.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/index.mounted.test.tsx
index 67a7f34abdd..20b86da9fd6 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/index.mounted.test.tsx
+++ b/apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/index.mounted.test.tsx
@@ -50,13 +50,13 @@ beforeEach(() => {
});
describe('CodeReviewerReviewListRoute invalid scope', () => {
- it('renders InvalidRouteState with the profile backTo when scope is undefined', () => {
+ it('renders InvalidRouteState with the Code Reviewer backTo when scope is undefined', () => {
useLocalSearchParamsMock.mockReturnValue({ scope: undefined });
const renderer = mountRoute();
const invalid = findByType(renderer.root, 'InvalidRouteState');
expect(invalid).toHaveLength(1);
- expect(propOf(invalid[0], 'backTo')).toBe('/(app)/(tabs)/(3_profile)');
+ expect(propOf(invalid[0], 'backTo')).toBe('/(app)/code-reviewer');
expect(findByType(renderer.root, 'ReviewListScreen')).toHaveLength(0);
act(() => {
@@ -64,13 +64,13 @@ describe('CodeReviewerReviewListRoute invalid scope', () => {
});
});
- it('renders InvalidRouteState with the profile backTo when scope is an array', () => {
+ it('renders InvalidRouteState with the Code Reviewer backTo when scope is an array', () => {
useLocalSearchParamsMock.mockReturnValue({ scope: ['personal', 'org'] });
const renderer = mountRoute();
const invalid = findByType(renderer.root, 'InvalidRouteState');
expect(invalid).toHaveLength(1);
- expect(propOf(invalid[0], 'backTo')).toBe('/(app)/(tabs)/(3_profile)');
+ expect(propOf(invalid[0], 'backTo')).toBe('/(app)/code-reviewer');
expect(findByType(renderer.root, 'ReviewListScreen')).toHaveLength(0);
act(() => {
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/index.tsx b/apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/index.tsx
similarity index 86%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/index.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/index.tsx
index 75e3ac3eb2b..89bb3905779 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/reviews/index.tsx
+++ b/apps/mobile/src/app/(app)/code-reviewer/[scope]/reviews/index.tsx
@@ -9,7 +9,7 @@ export default function CodeReviewerReviewListRoute() {
const scope = parseParam(rawScope);
if (!scope) {
- return ;
+ return ;
}
return ;
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/index.tsx b/apps/mobile/src/app/(app)/code-reviewer/index.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/code-reviewer/index.tsx
rename to apps/mobile/src/app/(app)/code-reviewer/index.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/_layout.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/_layout.tsx
similarity index 94%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/_layout.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/_layout.tsx
index 0ce0fb9a1b7..cbae3a064ea 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/_layout.tsx
+++ b/apps/mobile/src/app/(app)/security-agent/[scope]/_layout.tsx
@@ -22,7 +22,7 @@ export default function SecurityAgentScopeLayout() {
const sheetOptions = useFormSheetScreenOptions();
if (!scope) {
- return ;
+ return ;
}
return (
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/audit-report.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/audit-report.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/audit-report.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/audit-report.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/dismiss/[id].tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/dismiss/[id].tsx
similarity index 82%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/dismiss/[id].tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/dismiss/[id].tsx
index 2a0c2436302..a475700d253 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/dismiss/[id].tsx
+++ b/apps/mobile/src/app/(app)/security-agent/[scope]/dismiss/[id].tsx
@@ -9,9 +9,7 @@ export default function SecurityAgentDismissFindingRoute() {
const findingId = parseParam(rawId);
if (!findingId) {
- return (
-
- );
+ return ;
}
return ;
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/filter.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/filter.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/filter.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/filter.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/findings/[id].tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/findings/[id].tsx
similarity index 82%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/findings/[id].tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/findings/[id].tsx
index f47d2e08e29..57f70f97460 100644
--- a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/findings/[id].tsx
+++ b/apps/mobile/src/app/(app)/security-agent/[scope]/findings/[id].tsx
@@ -9,9 +9,7 @@ export default function SecurityAgentFindingDetailRoute() {
const findingId = parseParam(rawId);
if (!findingId) {
- return (
-
- );
+ return ;
}
return ;
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/findings/index.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/findings/index.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/findings/index.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/findings/index.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/index.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/index.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/index.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/index.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/analysis.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/settings/analysis.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/analysis.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/settings/analysis.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/automation.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/settings/automation.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/automation.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/settings/automation.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/index.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/settings/index.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/index.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/settings/index.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/notifications.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/settings/notifications.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/notifications.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/settings/notifications.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/repositories.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/settings/repositories.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/repositories.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/settings/repositories.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/sla.tsx b/apps/mobile/src/app/(app)/security-agent/[scope]/settings/sla.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/settings/sla.tsx
rename to apps/mobile/src/app/(app)/security-agent/[scope]/settings/sla.tsx
diff --git a/apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/index.tsx b/apps/mobile/src/app/(app)/security-agent/index.tsx
similarity index 100%
rename from apps/mobile/src/app/(app)/(tabs)/(3_profile)/security-agent/index.tsx
rename to apps/mobile/src/app/(app)/security-agent/index.tsx
diff --git a/apps/mobile/src/components/app-unlock-screen.mounted.test.tsx b/apps/mobile/src/components/app-unlock-screen.mounted.test.tsx
index c9c1c2c0ccc..a383cbdf2a8 100644
--- a/apps/mobile/src/components/app-unlock-screen.mounted.test.tsx
+++ b/apps/mobile/src/components/app-unlock-screen.mounted.test.tsx
@@ -26,7 +26,7 @@ import fr from '@/i18n/locales/fr.json';
import AppLayout from '@/app/(app)/_layout';
import KiloClawLayout from '@/app/(app)/(tabs)/(1_kiloclaw)/_layout';
import OrganizationLayout from '@/app/(app)/(tabs)/(3_profile)/organization/_layout';
-import SecurityAgentScopeLayout from '@/app/(app)/(tabs)/(3_profile)/security-agent/[scope]/_layout';
+import SecurityAgentScopeLayout from '@/app/(app)/security-agent/[scope]/_layout';
import PrReviewNumberLayout from '@/app/(app)/pr-review/[owner]/[repo]/[number]/_layout';
import { AppUnlockProvider } from '@/lib/app-unlock-context';
diff --git a/apps/mobile/src/components/code-reviewer/bitbucket-overview.tsx b/apps/mobile/src/components/code-reviewer/bitbucket-overview.tsx
index 2f1e0323bda..96ec14147ed 100644
--- a/apps/mobile/src/components/code-reviewer/bitbucket-overview.tsx
+++ b/apps/mobile/src/components/code-reviewer/bitbucket-overview.tsx
@@ -124,7 +124,7 @@ export function BitbucketOverview({
}
const pushField = (field: string) => {
- router.push(`/(app)/(tabs)/(3_profile)/code-reviewer/${scope}/bitbucket/${field}` as Href);
+ router.push(`/(app)/code-reviewer/${scope}/bitbucket/${field}` as Href);
};
const data = config.data;
diff --git a/apps/mobile/src/components/code-reviewer/full-surface-states.mounted.test.tsx b/apps/mobile/src/components/code-reviewer/full-surface-states.mounted.test.tsx
index 3a043db05b9..5de0effb12c 100644
--- a/apps/mobile/src/components/code-reviewer/full-surface-states.mounted.test.tsx
+++ b/apps/mobile/src/components/code-reviewer/full-surface-states.mounted.test.tsx
@@ -3,7 +3,7 @@ import { createElement, type ReactElement, type ReactNode } from 'react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import '@/i18n';
-import ReposRoute from '@/app/(app)/(tabs)/(3_profile)/code-reviewer/[scope]/[platform]/(edit)/repos';
+import ReposRoute from '@/app/(app)/code-reviewer/[scope]/[platform]/(edit)/repos';
import { ReviewListScreen } from './review-list-screen';
import { renderWithProviders, type RenderWithProvidersResult } from '@/test/render-with-providers';
@@ -293,7 +293,7 @@ describe('Recent review bodies', () => {
const action = empty.props.action as ReactElement<{ onPress: () => void }>;
action.props.onPress();
expect(state.push).toHaveBeenCalledWith(
- `/(app)/(tabs)/(3_profile)/code-reviewer/personal${connected ? '/manual-review' : ''}`
+ `/(app)/code-reviewer/personal${connected ? '/manual-review' : ''}`
);
unmount();
}
diff --git a/apps/mobile/src/components/code-reviewer/manual-review-action-footer.tsx b/apps/mobile/src/components/code-reviewer/manual-review-action-footer.tsx
index 7ba83f3d61f..ca35e33f5c5 100644
--- a/apps/mobile/src/components/code-reviewer/manual-review-action-footer.tsx
+++ b/apps/mobile/src/components/code-reviewer/manual-review-action-footer.tsx
@@ -10,20 +10,20 @@ import { useTabBarBottomPadding } from '@/components/tab-screen';
* The action used to be the scroll body's last child. At large display
* densities the form is taller than the viewport, so it was clipped mid-label
* at the scroll fold, against the tab bar (explorer manual-review finding,
- * 2026-09-19). The footer keeps its own layout space clear of the tab bar, so
- * the call to action is always fully legible.
+ * 2026-09-19). The footer reserves the screen's bottom clearance, so the call
+ * to action is always fully legible.
*
* The host wraps this footer and the scroll body in the keyboard-lift view,
* which owns the bottom space while the keyboard is open. The footer's own
* clearance therefore covers only what the lift does not: a keyboard taller
- * than the tab bar drops it to 0, while a keyboard shorter than the tab bar
- * (the hardware-keyboard IME bar is one navigation bar tall) keeps the rest, so
- * the action never lands behind the tab bar (e1-fill, 2026-09-19).
+ * than the clearance drops it to 0, while a shorter one (the hardware-keyboard
+ * IME bar is one navigation bar tall) keeps the rest, so the action never lands
+ * behind the bottom edge (e1-fill, 2026-09-19).
*/
export function ManualReviewActionFooter({ children }: Readonly<{ children: ReactNode }>) {
- const tabBarBottomPadding = useTabBarBottomPadding();
+ const bottomClearance = useTabBarBottomPadding();
const keyboardLift = useKeyboardState(state => state.height);
- const bottomPadding = Math.max(0, tabBarBottomPadding - keyboardLift);
+ const bottomPadding = Math.max(0, bottomClearance - keyboardLift);
return (
{children}
diff --git a/apps/mobile/src/components/code-reviewer/manual-review-screen.mounted.test.tsx b/apps/mobile/src/components/code-reviewer/manual-review-screen.mounted.test.tsx
index 6f33722d457..afa3e25d557 100644
--- a/apps/mobile/src/components/code-reviewer/manual-review-screen.mounted.test.tsx
+++ b/apps/mobile/src/components/code-reviewer/manual-review-screen.mounted.test.tsx
@@ -4,7 +4,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
import '@/i18n';
import { act, type TestRenderer } from '@/test/renderer';
import { renderWithProviders } from '@/test/render-with-providers';
-import { getEffectiveTabBarHeight } from '@/lib/tab-bar-layout';
+import { TabBarLabelContext } from '@/lib/tab-bar-clearance';
import { ManualReviewScreen } from './manual-review-screen';
@@ -12,7 +12,7 @@ import { ManualReviewScreen } from './manual-review-screen';
// clipped mid-label at the scroll fold, under the tab bar, at 560 density. The
// fix pins the action in a footer below the scroll view, so these tests assert
// the structural guarantee (the action is not inside the scroll viewport) and
-// the footer clearance (it sits a tab bar's height above the overlay).
+// the footer clearance (it sits the screen's bottom clearance above the edge).
const BOTTOM_INSET = 24;
const TAB_SCREEN_BOTTOM_GAP = 16;
@@ -172,8 +172,13 @@ function only(items: T[], what: string): T {
}
async function renderScreen() {
+ // The root stack publishes `null`: no tab bar under this screen.
const { renderer, unmount } = await renderWithProviders(
- createElement(ManualReviewScreen, { scope: 'personal' })
+ createElement(
+ TabBarLabelContext,
+ { value: null },
+ createElement(ManualReviewScreen, { scope: 'personal' })
+ )
);
return { renderer, unmount };
}
@@ -215,7 +220,7 @@ describe.each(['android', 'ios'] as const)('ManualReviewScreen primary action on
platformState.OS = platform;
});
- it('pins the start action outside the scroll viewport, clear of the tab bar', async () => {
+ it('pins the start action outside the scroll viewport, clear of the bottom inset', async () => {
const { renderer, unmount } = await renderScreen();
const scrollViews = findAllOfType(renderer.root, 'ScrollView');
@@ -227,21 +232,15 @@ describe.each(['android', 'ios'] as const)('ManualReviewScreen primary action on
const action = only(findAllOfType(renderer.root, 'Button'), 'primary action');
const [footerClearance] = paddingBottomsAbove(action);
- expect(footerClearance).toBe(
- getEffectiveTabBarHeight({
- bottomInset: BOTTOM_INSET,
- platform,
- fontScale: 1,
- }) + TAB_SCREEN_BOTTOM_GAP
- );
+ expect(footerClearance).toBe(BOTTOM_INSET + TAB_SCREEN_BOTTOM_GAP);
unmount();
});
- it('drops the tab bar clearance while the keyboard lifts the footer', async () => {
+ it('drops the bottom clearance while the keyboard lifts the footer', async () => {
const { renderer, unmount } = await renderScreen();
- // A keyboard at least as tall as the tab bar. The footer hands the whole
+ // A keyboard at least as tall as the clearance. The footer hands the whole
// bottom space to the lift view (`KeyboardAvoidingView`), which owns it
// while the keyboard is open, so its own clearance collapses to 0.
const keyboardLift = platform === 'android' ? 300 : 324;
@@ -255,36 +254,29 @@ describe.each(['android', 'ios'] as const)('ManualReviewScreen primary action on
expect(findAllOfType(renderer.root, 'KeyboardAvoidingView')).toHaveLength(1);
// The provider clears the height when the keyboard hides; the footer
- // restores its tab-bar clearance.
+ // restores its bottom clearance.
act(() => {
keyboardStore.setHeight(0);
});
- expect(paddingBottomsAbove(action)).toEqual([
- getEffectiveTabBarHeight({ bottomInset: BOTTOM_INSET, platform, fontScale: 1 }) +
- TAB_SCREEN_BOTTOM_GAP,
- ]);
+ expect(paddingBottomsAbove(action)).toEqual([BOTTOM_INSET + TAB_SCREEN_BOTTOM_GAP]);
unmount();
});
- it('keeps the tab bar clearance a short keyboard does not cover', async () => {
+ it('keeps the footer clearance a short keyboard does not cover', async () => {
const { renderer, unmount } = await renderScreen();
- // The hardware-keyboard IME bar is one navigation bar tall; the footer keeps
- // the difference so the action never lands behind the tab bar (e1-fill).
- const keyboardLift = BOTTOM_INSET + BOTTOM_INSET;
+ // A keyboard shorter than the clearance leaves part of it uncovered; the
+ // footer keeps the difference so the action never lands behind the bottom
+ // edge (e1-fill).
+ const keyboardLift = BOTTOM_INSET;
act(() => {
keyboardStore.setHeight(keyboardLift);
});
const action = only(findAllOfType(renderer.root, 'Button'), 'primary action');
- const footerClearance = getEffectiveTabBarHeight({
- bottomInset: BOTTOM_INSET,
- platform,
- fontScale: 1,
- });
expect(paddingBottomsAbove(action)).toEqual([
- footerClearance + TAB_SCREEN_BOTTOM_GAP - keyboardLift,
+ BOTTOM_INSET + TAB_SCREEN_BOTTOM_GAP - keyboardLift,
]);
unmount();
@@ -298,11 +290,8 @@ describe.each(['android', 'ios'] as const)('ManualReviewScreen primary action on
const button = only(findAllOfType(renderer.root, 'Button'), 'primary action');
expect((button.props as { disabled: boolean }).disabled).toBe(true);
// The footer is the sole clearance source now (the deleted lift layer is
- // gone); at rest it reserves the tab bar height plus its final gap.
- expect(paddingBottomsAbove(button)).toEqual([
- getEffectiveTabBarHeight({ bottomInset: BOTTOM_INSET, platform, fontScale: 1 }) +
- TAB_SCREEN_BOTTOM_GAP,
- ]);
+ // gone); at rest it reserves the screen's bottom clearance plus its final gap.
+ expect(paddingBottomsAbove(button)).toEqual([BOTTOM_INSET + TAB_SCREEN_BOTTOM_GAP]);
unmount();
});
@@ -312,11 +301,8 @@ describe.each(['android', 'ios'] as const)('ManualReviewScreen primary action on
const button = only(findAllOfType(renderer.root, 'Button'), 'primary action');
expect((button.props as { loading: boolean }).loading).toBe(true);
// The footer is the sole clearance source now (the deleted lift layer is
- // gone); at rest it reserves the tab bar height plus its final gap.
- expect(paddingBottomsAbove(button)).toEqual([
- getEffectiveTabBarHeight({ bottomInset: BOTTOM_INSET, platform, fontScale: 1 }) +
- TAB_SCREEN_BOTTOM_GAP,
- ]);
+ // gone); at rest it reserves the screen's bottom clearance plus its final gap.
+ expect(paddingBottomsAbove(button)).toEqual([BOTTOM_INSET + TAB_SCREEN_BOTTOM_GAP]);
unmount();
});
@@ -348,9 +334,7 @@ describe.each(['android', 'ios'] as const)('ManualReviewScreen primary action on
act(() => {
action.props.onPress();
});
- expect(status.push).toHaveBeenCalledWith(
- '/(app)/(tabs)/(3_profile)/code-reviewer/personal/github'
- );
+ expect(status.push).toHaveBeenCalledWith('/(app)/code-reviewer/personal/github');
expect(findAllOfType(renderer.root, 'ScrollView')).toHaveLength(0);
unmount();
});
diff --git a/apps/mobile/src/components/code-reviewer/manual-review-screen.tsx b/apps/mobile/src/components/code-reviewer/manual-review-screen.tsx
index a85317e7d99..18618ab2c6a 100644
--- a/apps/mobile/src/components/code-reviewer/manual-review-screen.tsx
+++ b/apps/mobile/src/components/code-reviewer/manual-review-screen.tsx
@@ -119,9 +119,7 @@ export function ManualReviewScreen({ scope }: Readonly<{ scope: string }>) {
onSuccess: ({ reviewId }) => {
settle(null);
void Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
- router.replace(
- `/(app)/(tabs)/(3_profile)/code-reviewer/${scope}/reviews/${reviewId}` as Href
- );
+ router.replace(`/(app)/code-reviewer/${scope}/reviews/${reviewId}` as Href);
},
onError: error => {
// A client-deadline rejection is the stall, not a server reason:
@@ -205,7 +203,7 @@ export function ManualReviewScreen({ scope }: Readonly<{ scope: string }>) {
diff --git a/apps/mobile/src/components/code-reviewer/platform-overview-screen.tsx b/apps/mobile/src/components/code-reviewer/platform-overview-screen.tsx
index de1c666e011..aa21d616564 100644
--- a/apps/mobile/src/components/code-reviewer/platform-overview-screen.tsx
+++ b/apps/mobile/src/components/code-reviewer/platform-overview-screen.tsx
@@ -163,7 +163,7 @@ export function PlatformOverviewScreen({
}
const pushField = (field: string) => {
- router.push(`/(app)/(tabs)/(3_profile)/code-reviewer/${scope}/${platform}/${field}` as Href);
+ router.push(`/(app)/code-reviewer/${scope}/${platform}/${field}` as Href);
};
const data = config.data;
@@ -195,9 +195,7 @@ export function PlatformOverviewScreen({
onOpenReviewMemory:
platform === 'github'
? () => {
- router.push(
- `/(app)/(tabs)/(3_profile)/code-reviewer/${scope}/review-memory` as Href
- );
+ router.push(`/(app)/code-reviewer/${scope}/review-memory` as Href);
}
: undefined,
});
diff --git a/apps/mobile/src/components/code-reviewer/review-detail-screen.mounted.test.tsx b/apps/mobile/src/components/code-reviewer/review-detail-screen.mounted.test.tsx
index c88d3403c00..6dbec517545 100644
--- a/apps/mobile/src/components/code-reviewer/review-detail-screen.mounted.test.tsx
+++ b/apps/mobile/src/components/code-reviewer/review-detail-screen.mounted.test.tsx
@@ -1354,9 +1354,7 @@ describe('ReviewDetailScreen retry when Code Reviewer cannot run', () => {
act(() => {
fixSettings?.onPress?.();
});
- expect(routerMock.push).toHaveBeenCalledWith(
- '/(app)/(tabs)/(3_profile)/code-reviewer/personal/github'
- );
+ expect(routerMock.push).toHaveBeenCalledWith('/(app)/code-reviewer/personal/github');
});
it('links to the settings when the configuration needs attention', () => {
diff --git a/apps/mobile/src/components/code-reviewer/review-detail-screen.tsx b/apps/mobile/src/components/code-reviewer/review-detail-screen.tsx
index ecf5f2e76a8..d41c0cd70e7 100644
--- a/apps/mobile/src/components/code-reviewer/review-detail-screen.tsx
+++ b/apps/mobile/src/components/code-reviewer/review-detail-screen.tsx
@@ -349,9 +349,7 @@ export function ReviewDetailScreen({