Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
be05136
feat(inbox): make report detail sections collapsible
posthog[bot] Jul 30, 2026
692654e
feat(mcp-gateway): implement the team MCP gateway UI behind the mcp-g…
cvolzer3 Jul 31, 2026
ac00720
fix(mcp-gateway): resolve the added server in the register mutation i…
cvolzer3 Jul 31, 2026
d01fef1
feat: add member list search and preview
cvolzer3 Jul 31, 2026
37b8575
refactor: remove agent creation from team view
cvolzer3 Jul 31, 2026
f6d79c7
Remove agent call status from team view
cvolzer3 Jul 31, 2026
6c05fb8
feat(mcp-gateway): refine server detail experience
cvolzer3 Jul 31, 2026
19b6bcf
Unify MCP server detail row backgrounds
cvolzer3 Jul 31, 2026
6c91f32
Hide empty shared MCP server section
cvolzer3 Jul 31, 2026
40fe731
fix(mcp-gateway): remove service account prefix from agent handles
cvolzer3 Jul 31, 2026
e895d1d
feat(mcp-gateway): let members manage agent access
cvolzer3 Jul 31, 2026
685e5d9
fix(mcp-gateway): prevent stale policy and access state
cvolzer3 Jul 31, 2026
e3978d0
feat(mcp-gateway): refine team server management
cvolzer3 Jul 31, 2026
a89d1ca
fix(mcp-gateway): parse paginated members response
cvolzer3 Jul 31, 2026
2a202da
fix(mcp-gateway): drop shared connections from the gateway client
cvolzer3 Jul 31, 2026
285a5f0
feat(mcp-gateway): compose the servers home from the sparse registry …
cvolzer3 Jul 31, 2026
525d62d
fix(scouts): keep the scout enable switch grey when off
cvolzer3 Jul 31, 2026
4bbb9d7
fix(mcp-gateway): drop token rotation from the agent detail page
cvolzer3 Jul 31, 2026
2fde68e
refactor(mcp-gateway): drop the unrendered policy-baseline and rules …
cvolzer3 Jul 31, 2026
d607d59
fix(mcp-gateway): discover a server's tools when someone connects
cvolzer3 Jul 31, 2026
dc59141
fix(mcp-gateway): don't badge deleted-actor audit rows as "human"
cvolzer3 Jul 31, 2026
923a313
docs: correct isFeatureEnabled return value when flags never load
cvolzer3 Jul 31, 2026
f463fa5
fix(mcp-gateway): reset GiveAccessDialog draft so policies don't leak…
cvolzer3 Jul 31, 2026
ced13c0
fix(mcp-gateway): stop the rail showing disabled connections as conne…
cvolzer3 Jul 31, 2026
53347be
fix(mcp-gateway): use the template icon_domain for materialized serve…
cvolzer3 Jul 31, 2026
afd9e17
fix(mcp-servers): never include rule-locked tools in bulk approval wr…
cvolzer3 Jul 31, 2026
d2ecfb8
fix(mcp-gateway): derive the member delete affordance from the sessio…
cvolzer3 Jul 31, 2026
0fd92e1
fix(mcp-gateway): show one bulk trio and drop Needs Approval for agen…
cvolzer3 Jul 31, 2026
c8b4a12
fix(mcp-gateway): honor the server's auth type when connecting instea…
cvolzer3 Jul 31, 2026
f11f3d3
fix(mcp-gateway): stamp the session user as grantor in the optimistic…
cvolzer3 Jul 31, 2026
c4ecb71
fix(mcp-gateway): give connected members a refresh-tools affordance
cvolzer3 Jul 31, 2026
81ad90f
fix(mcp-gateway): reset access draft with dialog key
cvolzer3 Jul 31, 2026
8ab6d7d
Merging 81ad90f4cce844ed68f95ba7f4f4f0af97e51fd5 into trunk-temp/pr-3…
trunk-io[bot] Jul 31, 2026
b2c8b8c
Merging be051364623dc521c1a0c524ec9488ae6e6a8891 into trunk-temp/pr-3…
trunk-io[bot] Jul 31, 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
64 changes: 29 additions & 35 deletions apps/mobile/src/app/inbox/[...id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import * as Haptics from "expo-haptics";
import { useLocalSearchParams, useRouter } from "expo-router";
import {
CaretDown,
CaretRight,
ChatCircle,
Lightning,
Play,
Expand Down Expand Up @@ -47,6 +46,7 @@ import {
} from "@/features/inbox/components/DismissReportSheet";
import { ReportActivity } from "@/features/inbox/components/ReportActivity";
import { ReportFeedbackFooter } from "@/features/inbox/components/ReportFeedbackFooter";
import { ReportSection } from "@/features/inbox/components/ReportSection";
import { SignalCard } from "@/features/inbox/components/SignalCard";
import {
type ReviewerActionExtra,
Expand Down Expand Up @@ -156,6 +156,7 @@ export default function ReportDetailScreen() {
const [dismissOpen, setDismissOpen] = useState(false);
const [discussOpen, setDiscussOpen] = useState(false);
const [createPrFeedbackOpen, setCreatePrFeedbackOpen] = useState(false);
const [summaryExpanded, setSummaryExpanded] = useState(true);
const [signalsExpanded, setSignalsExpanded] = useState(false);

const artefactsQuery = useInboxReportArtefacts(reportId ?? null);
Expand Down Expand Up @@ -519,11 +520,17 @@ export default function ReportDetailScreen() {

{/* Summary */}
{report.summary && (
<View className="mb-4" style={{ opacity: isReady ? 1 : 0.7 }}>
<MarkdownText
content={formatSignalReportSummaryMarkdown(report.summary)}
/>
</View>
<ReportSection
title="Summary"
expanded={summaryExpanded}
onToggle={() => setSummaryExpanded((prev) => !prev)}
>
<View style={{ opacity: isReady ? 1 : 0.7 }}>
<MarkdownText
content={formatSignalReportSummaryMarkdown(report.summary)}
/>
</View>
</ReportSection>
)}

{/* Suggested reviewers */}
Expand All @@ -538,35 +545,22 @@ export default function ReportDetailScreen() {

{/* Signals */}
{signals.length > 0 && (
<View className="mb-4">
<Pressable
onPress={handleToggleSignals}
hitSlop={6}
accessibilityRole="button"
accessibilityState={{ expanded: signalsExpanded }}
className="mb-2 flex-row items-center gap-1.5 self-start py-1 active:opacity-60"
>
{signalsExpanded ? (
<CaretDown size={14} color={themeColors.gray[12]} />
) : (
<CaretRight size={14} color={themeColors.gray[12]} />
)}
<Text className="font-semibold text-[14px] text-gray-12">
Signals ({signals.length})
</Text>
</Pressable>
{signalsExpanded && (
<View className="gap-2">
{signals.map((signal) => (
<SignalCard
key={signal.signal_id}
signal={signal}
finding={findingsBySignalId.get(signal.signal_id)}
/>
))}
</View>
)}
</View>
<ReportSection
title="Signals"
count={signals.length}
expanded={signalsExpanded}
onToggle={handleToggleSignals}
>
<View className="gap-2">
{signals.map((signal) => (
<SignalCard
key={signal.signal_id}
signal={signal}
finding={findingsBySignalId.get(signal.signal_id)}
/>
))}
</View>
</ReportSection>
)}
{signalsQuery.isLoading && (
<Text className="text-[12px] text-gray-9">Loading signals…</Text>
Expand Down
70 changes: 70 additions & 0 deletions apps/mobile/src/features/inbox/components/ReportSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Text } from "@components/text";
import { CaretDown, CaretRight } from "phosphor-react-native";
import type { ReactNode } from "react";
import { Pressable, View } from "react-native";
import { useThemeColors } from "@/lib/theme";

interface ReportSectionProps {
title: string;
/** Appended to the title as `(n)` – omit for sections without a count. */
count?: number;
/** Icon rendered before the title (e.g. `<ClockCounterClockwise size={14} />`). */
icon?: ReactNode;
expanded: boolean;
onToggle: () => void;
/**
* Controls rendered at the end of the header row, outside the disclosure so
* they stay independently tappable.
*/
rightSlot?: ReactNode;
children: ReactNode;
}

/**
* Collapsible section on the report detail screen (Summary, Reviewers,
* Signals). Mirrors the desktop `DetailSection` disclosure so the same report
* can be scanned the same way on either host. Expansion state is owned by the
* caller – the Signals disclosure fires analytics when it opens.
*/
export function ReportSection({
title,
count,
icon,
expanded,
onToggle,
rightSlot,
children,
}: ReportSectionProps) {
const themeColors = useThemeColors();

return (
<View className="mb-4">
<View className="mb-2 flex-row items-center gap-2">
<Pressable
onPress={onToggle}
hitSlop={6}
accessibilityRole="button"
accessibilityState={{ expanded }}
className="shrink flex-row items-center gap-1.5 py-1 active:opacity-60"
>
{expanded ? (
<CaretDown size={14} color={themeColors.gray[12]} />
) : (
<CaretRight size={14} color={themeColors.gray[12]} />
)}
{icon}
<Text className="font-semibold text-[14px] text-gray-12">
{count === undefined ? title : `${title} (${count})`}
</Text>
</Pressable>
{rightSlot ? (
<>
<View className="flex-1" />
{rightSlot}
</>
) : null}
</View>
{expanded ? children : null}
</View>
);
}
183 changes: 94 additions & 89 deletions apps/mobile/src/features/inbox/components/SuggestedReviewers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { openExternalUrl } from "@/lib/openExternalUrl";
import { useThemeColors } from "@/lib/theme";
import { useUpdateSuggestedReviewers } from "../hooks/useInboxReports";
import { EditReviewersSheet } from "./EditReviewersSheet";
import { ReportSection } from "./ReportSection";

export type ReviewerActionExtra = Pick<
InboxReportActionProperties,
Expand All @@ -50,6 +51,7 @@ export function SuggestedReviewers({
}: SuggestedReviewersProps) {
const themeColors = useThemeColors();
const [editOpen, setEditOpen] = useState(false);
const [expanded, setExpanded] = useState(true);
const { mutate: updateReviewers, isPending } =
useUpdateSuggestedReviewers(reportId);

Expand Down Expand Up @@ -108,96 +110,99 @@ export function SuggestedReviewers({
};

return (
<View className="mb-4">
<View className="mb-2 flex-row items-center gap-2">
<Text className="font-semibold text-[12px] text-gray-10 uppercase tracking-wide">
Suggested reviewers
</Text>
{isPending && (
<ActivityIndicator size="small" color={themeColors.gray[9]} />
)}
<View className="flex-1" />
<Pressable
onPress={() => setEditOpen(true)}
disabled={isPending}
accessibilityLabel="Add suggested reviewer"
hitSlop={6}
className="flex-row items-center gap-1 rounded-full border border-gray-6 px-2.5 py-1 active:opacity-70 disabled:opacity-50"
>
<Plus size={12} color={themeColors.gray[11]} weight="bold" />
<Text className="text-[12px] text-gray-11">Add</Text>
</Pressable>
</View>

{displayReviewers.length === 0 ? (
<Text className="text-[13px] text-gray-9">
No reviewers assigned. Use “Add” to suggest one.
</Text>
) : (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ gap: 8 }}
>
{displayReviewers.map((reviewer) => {
const isMe =
!!reviewer.user?.uuid &&
!!meUuid &&
reviewer.user.uuid === meUuid;
const displayName =
reviewer.user?.first_name ??
reviewer.github_name ??
reviewer.github_login;
return (
<View
key={reviewer.user?.uuid ?? reviewer.github_login}
className="flex-row items-center gap-2 rounded-full border border-gray-6 bg-gray-2 py-1.5 pr-1.5 pl-1.5"
>
<Pressable
onPress={() => {
fireAction("click_suggested_reviewer", {
suggested_reviewer_login: reviewer.github_login,
});
openExternalUrl(
`https://github.com/${reviewer.github_login}`,
);
}}
hitSlop={4}
className="flex-row items-center gap-2 active:opacity-70"
<>
<ReportSection
title="Suggested reviewers"
expanded={expanded}
onToggle={() => setExpanded((prev) => !prev)}
rightSlot={
<View className="flex-row items-center gap-2">
{isPending && (
<ActivityIndicator size="small" color={themeColors.gray[9]} />
)}
<Pressable
onPress={() => setEditOpen(true)}
disabled={isPending}
accessibilityLabel="Add suggested reviewer"
hitSlop={6}
className="flex-row items-center gap-1 rounded-full border border-gray-6 px-2.5 py-1 active:opacity-70 disabled:opacity-50"
>
<Plus size={12} color={themeColors.gray[11]} weight="bold" />
<Text className="text-[12px] text-gray-11">Add</Text>
</Pressable>
</View>
}
>
{displayReviewers.length === 0 ? (
<Text className="text-[13px] text-gray-9">
No reviewers assigned. Use “Add” to suggest one.
</Text>
) : (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ gap: 8 }}
>
{displayReviewers.map((reviewer) => {
const isMe =
!!reviewer.user?.uuid &&
!!meUuid &&
reviewer.user.uuid === meUuid;
const displayName =
reviewer.user?.first_name ??
reviewer.github_name ??
reviewer.github_login;
return (
<View
key={reviewer.user?.uuid ?? reviewer.github_login}
className="flex-row items-center gap-2 rounded-full border border-gray-6 bg-gray-2 py-1.5 pr-1.5 pl-1.5"
>
<Image
source={{
uri: `https://github.com/${reviewer.github_login}.png?size=48`,
<Pressable
onPress={() => {
fireAction("click_suggested_reviewer", {
suggested_reviewer_login: reviewer.github_login,
});
openExternalUrl(
`https://github.com/${reviewer.github_login}`,
);
}}
className="h-6 w-6 rounded-full bg-gray-4"
/>
<Text className="text-[13px] text-gray-12">
{displayName}
</Text>
{isMe && (
<View className="rounded bg-status-warning/20 px-1 py-0.5">
<Eye
size={10}
color={themeColors.status.warning}
weight="bold"
/>
</View>
)}
</Pressable>
<Pressable
onPress={() => removeReviewer(reviewer)}
disabled={isPending}
accessibilityLabel={`Remove ${displayName}`}
hitSlop={6}
className="h-5 w-5 items-center justify-center rounded-full active:bg-gray-4 disabled:opacity-50"
>
<X size={12} color={themeColors.gray[10]} weight="bold" />
</Pressable>
</View>
);
})}
</ScrollView>
)}
hitSlop={4}
className="flex-row items-center gap-2 active:opacity-70"
>
<Image
source={{
uri: `https://github.com/${reviewer.github_login}.png?size=48`,
}}
className="h-6 w-6 rounded-full bg-gray-4"
/>
<Text className="text-[13px] text-gray-12">
{displayName}
</Text>
{isMe && (
<View className="rounded bg-status-warning/20 px-1 py-0.5">
<Eye
size={10}
color={themeColors.status.warning}
weight="bold"
/>
</View>
)}
</Pressable>
<Pressable
onPress={() => removeReviewer(reviewer)}
disabled={isPending}
accessibilityLabel={`Remove ${displayName}`}
hitSlop={6}
className="h-5 w-5 items-center justify-center rounded-full active:bg-gray-4 disabled:opacity-50"
>
<X size={12} color={themeColors.gray[10]} weight="bold" />
</Pressable>
</View>
);
})}
</ScrollView>
)}
</ReportSection>

<EditReviewersSheet
visible={editOpen}
Expand All @@ -206,6 +211,6 @@ export function SuggestedReviewers({
onClose={() => setEditOpen(false)}
onToggle={toggleReviewer}
/>
</View>
</>
);
}
Loading
Loading