Agent network - #684
Conversation
Ports the agent-network feature from dashboard-cloud agent-network branch (squashed net delta of 45 files against the shared cloud/oss base). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds Agent Network feature flags, shared provider and policy context, new dashboard pages for providers, policies, usage, onboarding, and control-center overlays, plus peers/navigation updates and Docker packaging. ChangesAgent Network rollout
Access Control cleanup
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
src/modules/onboarding/agent-network/AgentNetworkSignupForm.tsxOops! Something went wrong! :( ESLint: 9.39.3 TypeError: Converting circular structure to JSON Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 20
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/modules/instance-setup/InstanceSetupWizard.tsx (1)
137-152: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winClear the confirm-password error when either password field changes.
Once
validateForm()sets"Passwords do not match", updatingpasswordto match no longer clears that error becausehandleInputChangeonly resets the field being edited, andconfirmPasswordErrorgives the staleerrors.confirmPasswordvalue priority over the current form state. The UI can therefore keep showing a mismatch after the two values already match.Suggested fix
const handleInputChange = (field: keyof FormData) => (e: React.ChangeEvent<HTMLInputElement>) => { - setFormData((prev) => ({ ...prev, [field]: e.target.value })); - if (errors[field]) { - setErrors((prev) => ({ ...prev, [field]: undefined })); - } + const value = e.target.value; + setFormData((prev) => ({ ...prev, [field]: value })); + setErrors((prev) => ({ + ...prev, + [field]: undefined, + ...(field === "password" || field === "confirmPassword" + ? { confirmPassword: undefined } + : {}), + })); };Also applies to: 256-265
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/instance-setup/InstanceSetupWizard.tsx` around lines 137 - 152, Clear the confirm-password mismatch as soon as either password field changes. In `InstanceSetupWizard`, update the `handleInputChange`/password handling so changing `password` also re-evaluates and clears `confirmPassword` mismatch state when the two values match, not just when editing `confirmPassword`. Also adjust `confirmPasswordError` so current form state takes precedence over a stale `errors.confirmPassword` value, ensuring the mismatch message disappears once `password` and `confirmPassword` are equal.
🟡 Minor comments (7)
src/modules/onboarding/agent-network/AgentNetworkSignupForm.tsx-98-100 (1)
98-100: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winClone
referralSourceOptionsbefore shuffling.
sort()mutates the imported array in place, so this form can change option order for other onboarding consumers sharing the same module value.Proposed fix
const randomizedOptions = useMemo( - () => referralSourceOptions.sort(() => Math.random() - 0.5), + () => [...referralSourceOptions].sort(() => Math.random() - 0.5), [], );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/onboarding/agent-network/AgentNetworkSignupForm.tsx` around lines 98 - 100, The randomized option generation in AgentNetworkSignupForm mutates the shared referralSourceOptions array in place, which can affect other consumers of the module. Update the useMemo logic that builds randomizedOptions to first clone referralSourceOptions before applying the shuffle/sort, so the imported source array remains unchanged for other onboarding flows.src/modules/onboarding/agent-network/AgentNetworkSignupForm.tsx-226-249 (1)
226-249: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winKeep the hidden “Other” input out of the tab order.
When
otheris false, the input is only visually collapsed, so keyboard users can still tab into an invisible control.Proposed fix
<Checkbox checked={other} - onCheckedChange={() => { - setOther(!other); - inputRef.current?.focus(); + onCheckedChange={(checked) => { + const next = checked === true; + setOther(next); + if (next) { + window.requestAnimationFrame(() => inputRef.current?.focus()); + } }} /> @@ <Input ref={inputRef} + disabled={!other} + aria-hidden={!other} + tabIndex={other ? undefined : -1} placeholder={"e.g. Internal RAG service, MCP tools"} value={otherUseCase}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/onboarding/agent-network/AgentNetworkSignupForm.tsx` around lines 226 - 249, The hidden “Other” input in AgentNetworkSignupForm should be removed from the keyboard tab order when other is false. Update the Input rendering so that the collapsed state also makes it non-focusable and inaccessible, using the existing other, inputRef, and Input controls in AgentNetworkSignupForm rather than only changing the wrapper classes. Ensure keyboard users can only tab to the field when it is actually visible.src/modules/onboarding/agent-network/OnboardingAgentEnd.tsx-29-33 (1)
29-33: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winThe CTA label does not match the destination.
onFinishcurrently routes to Control Center insrc/modules/onboarding/OnboardingProvider.tsx, not Access Logs, so this button text sets the wrong expectation. Either relabel it to match Control Center or change the completion handler to navigate to Usage & Logs.
Based on learnings from the provided cross-file snippet:src/modules/onboarding/OnboardingProvider.tsx:127-143pushes/control-centeror/control-center?tab=networks.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/onboarding/agent-network/OnboardingAgentEnd.tsx` around lines 29 - 33, The button label in OnboardingAgentEnd does not match where onFinish actually navigates. Update the CTA text in OnboardingAgentEnd to reflect the Control Center destination, or alternatively change the onFinish handler in OnboardingProvider so it routes to Usage & Logs instead; keep the label and navigation consistent with the behavior implemented in onFinish.src/modules/setup-netbird-modal/MacOSTab.tsx-63-67 (1)
63-67: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick winAdd
rel="noopener noreferrer"to the external installer link.Line 66 opens a third-party URL in a new tab without
rel, which leaveswindow.openeravailable. WindowsTab already closes that gap on the analogous link.🔒 Proposed fix
<Link href={pkgsDownloadUrl("macos/universal")} passHref target={"_blank"} + rel="noopener noreferrer" >🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/setup-netbird-modal/MacOSTab.tsx` around lines 63 - 67, The external installer link in MacOSTab opens a new tab without a rel attribute, leaving window.opener exposed. Update the Link that uses pkgsDownloadUrl("macos/universal") to include rel="noopener noreferrer", matching the safer pattern already used in WindowsTab for the analogous external download link.build.sh-42-47 (1)
42-47: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winPreserve any pre-existing root
.dockerignore.Lines 45-47 always delete
.dockerignoreon exit. If the repo already has one, or a developer keeps a local override, this script removes it after the build. Back up the original file and restore it incleanup()instead of unconditionally deleting it.Suggested fix
-# The .dockerignore lives under docker/, but Docker reads it from the build -# context root. Stage it for the duration of the build so node_modules/.next -# don't get shipped into the build context. -cleanup() { rm -f .dockerignore; } -trap cleanup EXIT -cp docker/.dockerignore .dockerignore +# The .dockerignore lives under docker/, but Docker reads it from the build +# context root. Stage it for the duration of the build so node_modules/.next +# don't get shipped into the build context. +ORIGINAL_DOCKERIGNORE="" +if [[ -f .dockerignore ]]; then + ORIGINAL_DOCKERIGNORE="$(mktemp)" + cp .dockerignore "${ORIGINAL_DOCKERIGNORE}" +fi + +cleanup() { + if [[ -n "${ORIGINAL_DOCKERIGNORE}" ]]; then + mv "${ORIGINAL_DOCKERIGNORE}" .dockerignore + else + rm -f .dockerignore + fi +} +trap cleanup EXIT +cp docker/.dockerignore .dockerignore🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@build.sh` around lines 42 - 47, The build.sh staging logic currently overwrites and then always deletes the root .dockerignore, which can remove an existing repo file or a developer’s local override. Update the cleanup() flow to preserve any pre-existing .dockerignore by backing it up before the cp docker/.dockerignore .dockerignore step and restoring that original file in cleanup() instead of unconditionally removing it. Use the existing cleanup trap and the .dockerignore staging block as the place to implement the backup/restore behavior.src/app/(dashboard)/agent-network/configuration/page.tsx-30-36 (1)
30-36: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winValidate the
tabquery param before syncing it into state.Line 32 and Line 35 accept any
tabvalue from the URL.?tab=fooleavesVerticalTabswith no matching trigger/content, so the page renders an empty detail pane instead of falling back to a valid tab.Suggested fix
const TAB_BUDGET_SETTINGS = "budget-settings"; const TAB_LOG_SETTINGS = "log-settings"; +const VALID_TABS = new Set([TAB_BUDGET_SETTINGS, TAB_LOG_SETTINGS]); + +const normalizeTab = (value: string | null) => + value && VALID_TABS.has(value) ? value : TAB_BUDGET_SETTINGS; export default function AgentNetworkConfigurationPage() { const { permission } = usePermissions(); const queryParams = useSearchParams(); const queryTab = queryParams.get("tab"); - const [tab, setTab] = useState(queryTab ?? TAB_BUDGET_SETTINGS); + const [tab, setTab] = useState(normalizeTab(queryTab)); useEffect(() => { - if (queryTab) setTab(queryTab); + setTab(normalizeTab(queryTab)); }, [queryTab]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`(dashboard)/agent-network/configuration/page.tsx around lines 30 - 36, The query param handling in the configuration page is syncing any raw `tab` value from `useSearchParams` into state, which can leave `VerticalTabs` with no matching tab. Update the `queryTab`/`setTab` flow in `page.tsx` to validate against the allowed tab values before initializing or updating state, and fall back to `TAB_BUDGET_SETTINGS` when the URL value is missing or invalid. Use the existing `tab`, `setTab`, `queryTab`, and `TAB_BUDGET_SETTINGS` symbols to keep the tab state consistent.src/app/(dashboard)/control-center/page.tsx-612-620 (1)
612-620: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDeduplicate peer overlay edges by
sourceNodeId.
applyPeerView()calls this helper once per peer group at Line 1147, but all of those calls use the sameselect-peer-nodesource. With the currentagent-src-${groupId}-${policy.id}key, one agent policy matched through two peer groups produces duplicate overlapping edges from the same source to the same target.Suggested fix
- const sourceEdgeId = `agent-src-${groupId}-${policy.id}`; + const sourceEdgeId = `agent-src-${sourceNodeId}-${policy.id}`; if (!allEdges.some((e) => e.id === sourceEdgeId)) { allEdges.push({ id: sourceEdgeId, source: sourceNodeId, target: policyNodeId,🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`(dashboard)/control-center/page.tsx around lines 612 - 620, The peer overlay edge key in applyPeerView()/the helper that builds agent-src edges is too specific to groupId, which allows duplicate overlapping edges when the same sourceNodeId is processed through multiple peer groups. Change the deduplication logic to key off sourceNodeId and policy.id (or otherwise ensure only one edge per source-target pair is created), and keep the existing source, target, and data fields unchanged when pushing into allEdges.
🧹 Nitpick comments (2)
src/modules/agent-network/data/mockData.ts (1)
5-21: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftAvoid freezing the provider-id contract in the dashboard.
The comment says the catalog is server-owned, but this union still hard-codes the current ids locally.
AIProvidersProvider.fromAPI()already has to castprovider_idback toAIProviderIdto make it fit, so any new catalog entry can arrive from management while the dashboard types silently drift. Prefer a plain backend id type (string) for persisted provider ids and only narrow where the UI truly needs special-case handling.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/agent-network/data/mockData.ts` around lines 5 - 21, The provider-id contract is still being frozen locally by the AIProviderId union in mockData, which can drift from the server-owned catalog. Update the persisted/provider model used by AIProvidersProvider.fromAPI() and related data shapes to store provider_id as a plain backend string, then only narrow to specific AIProviderId values at UI branches that need special-case handling. Remove the need for the cast in fromAPI() by keeping the catalog-facing type flexible and reserving the union for client-side checks only.src/app/(dashboard)/peers/page.tsx (1)
70-76: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winBuild a user lookup before joining peers.
users.find(...)runs once per peer, so large accounts pay an avoidablepeers × userscost during render. AMapkeeps the join linear.⚡ Proposed refactor
const peersWithUser = useMemo(() => { if (!peers || !users) return undefined; + const usersById = new Map(users.map((user) => [user.id, user])); return peers.map((peer) => ({ ...peer, - user: users.find((u) => u.id === peer.user_id), + user: peer.user_id ? usersById.get(peer.user_id) : undefined, force_approved: peer.id ? isBypassed(peer.id) : false, })); }, [peers, users, isBypassed]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`(dashboard)/peers/page.tsx around lines 70 - 76, The peer-to-user join in `peersWithUser` is doing a repeated `users.find(...)` for every peer, which makes the render unnecessarily quadratic for large lists. Build a user lookup map once inside the `useMemo` block in `page.tsx` (near `peersWithUser`), keyed by user id, then use that map when mapping peers so each peer resolves its `user` in constant time while keeping the existing `force_approved` logic intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/`(dashboard)/agent-network/providers/page.tsx:
- Around line 169-206: The access check is applied too late because
`RestrictedAccess` only wraps `PageBody`, while `AIProvidersProvider` and
`EndpointHeader` still mount for users without `permission?.services?.read`.
Move the gate in `page.tsx` so the entire providers surface is protected before
rendering `AIProvidersProvider`, `EndpointHeader`, or any content that can fetch
agent-network state, and keep `PageBody` inside the guarded branch.
In `@src/app/`(dashboard)/agent-network/usage/page.tsx:
- Around line 53-56: The tab sync effect in the usage page only updates state
when `queryTab` is present and valid, so `tab` never resets when `?tab=` is
removed. Update the `useEffect` tied to `queryTab` so it also handles the
empty/absent case by restoring the default tab state, while still validating
values against `VALID_TABS`. Use the `tab`, `setTab`, `queryTab`, and
`VALID_TABS` logic in this component to keep deep links and back-forward
navigation in sync.
In `@src/layouts/Navigation.tsx`:
- Around line 180-229: The Agent Network sidebar items are only gated by the
feature flag, but the pages themselves require permissions, so restricted users
can still see and click entries they cannot access. Update Navigation.tsx so the
child SidebarItem entries under the Agent Network section use the same
permission checks as their corresponding pages (for example, the Providers item
should match the page’s services.read guard), and compute the parent section’s
visible state from whichever child items are actually permitted. Keep the
changes anchored around the Agent Network SidebarItem block and the
isAgentNetworkEnabled/isAgentNetworkOnly logic.
In `@src/modules/agent-network/AgentAccessLogTable.tsx`:
- Around line 145-149: Guard the provider lookup memo in AgentAccessLogTable
before iterating because providers can be null on the initial render. Update
providerByConfigId to handle a missing providers value safely, using the same
nullable pattern already used later in the component, so the map is only built
when providers is available and the access-log table does not crash.
In `@src/modules/agent-network/AgentAccountControlsCard.tsx`:
- Around line 61-70: The save flow in onSave should not clear the dirty state
when updateAgentNetworkSettings fails, since that helper handles errors
internally and may still allow execution to continue. Update the onSave logic in
AgentAccountControlsCard so updateRef(...) only runs after a confirmed
successful save, or make updateAgentNetworkSettings return a success/failure
signal that onSave can check before resetting the dirty state.
In `@src/modules/agent-network/AgentBudgetRuleModal.tsx`:
- Around line 115-148: `handleSubmit` in `AgentBudgetRuleModal` closes the modal
unconditionally, even when saving the budget rule fails; update it so
`onSuccess()` only runs after a confirmed successful `addBudgetRule` or
`updateBudgetRule` call. Make sure the submit flow checks the returned result
from `addBudgetRule` and handles errors from `updateBudgetRule` in
`AIProvidersProvider` instead of swallowing them, so failed persistence does not
dismiss the modal and lose edits.
In `@src/modules/agent-network/AgentGuardrailChecksCell.tsx`:
- Around line 49-55: The tooltip in AgentGuardrailChecksCell always shows “PII
redaction” whenever prompt capture is enabled, even when
prompt_capture.redactPii is false. Update the rendering around the prompt
capture tooltip in AgentGuardrailChecksCell to conditionally describe the actual
state using the guardrail data coming from AIProvidersProvider, so the label
only mentions PII redaction when redactPii is enabled and otherwise reflects
plain prompt capture.
In `@src/modules/agent-network/AgentGuardrailModal.tsx`:
- Around line 69-84: The submit flow in AgentGuardrailModal should not close the
modal after a failed save, since addGuardrail can return undefined and
updateGuardrail may also fail. Update handleSubmit so it only calls onSuccess
and onOpenChange(false) when a saved guardrail is actually returned, and keep
the modal open otherwise so the user can retry with their draft preserved.
In `@src/modules/agent-network/AgentOverviewPanel.tsx`:
- Around line 389-409: Normalize `period_start` to the same `YYYY-MM-DD` day key
before storing and looking up entries in `AgentOverviewPanel`’s bucket map so
the gap-filling loop matches API values even when they include timestamps.
Update the `map.set(...)` and `map.get(...)` usage in the date-fill logic to use
a normalized key consistently, and remove or replace the hard `i < 366` cap in
that same loop so valid ranges longer than a year are not truncated.
In `@src/modules/agent-network/AgentPolicyModal.tsx`:
- Around line 166-209: handleSubmit currently always calls onSuccess, so the
modal closes even when addPolicy or updatePolicy fails. Update
AgentPolicyModal’s handleSubmit flow to only invoke onSuccess after a successful
save, and keep the modal open when addPolicy returns undefined or updatePolicy
fails. Use the addPolicy/updatePolicy calls from useAIProviders and ensure any
failure path short-circuits before onSuccess so in-progress edits are preserved.
In `@src/modules/agent-network/AIProviderModal.tsx`:
- Around line 374-384: Catalog-backed providers are still allowing a blank model
row to be added and submitted, so update the model flow in AIProviderModal to
prevent incomplete entries from persisting. Fix this by stopping addModel from
appending a row with an empty id once all catalog presets are used, and also
harden handleSubmit to filter out any incomplete model rows before calling
addProvider so the payload never includes blank models. Use the existing
addModel, handleSubmit, and the provider submit path around addProvider to
locate the changes.
In `@src/modules/agent-network/AIProvidersProvider.tsx`:
- Around line 200-206: The settings mapper in settingsFromAPI is using the wrong
fallback for attributionMode. Update the APIAgentNetworkSettings to
AgentNetworkSettings conversion so that missing attribution_mode uses the
backend management default documented by the shared domain, not "priority". Keep
the change localized to settingsFromAPI in AIProvidersProvider so older rows
without attribution_mode render the correct effective mode in the dashboard.
In `@src/modules/agent-network/useProviderCatalog.ts`:
- Around line 77-80: The provider catalog request in useProviderCatalog is still
firing even when agent network is disabled, which can cause unnecessary
404s/errors in inert deployments. Update this hook to check
isAgentNetworkEnabled() before calling useFetchApi for
/agent-network/catalog/providers, and return an empty/inactive state when the
flag is false so AIProviderLogo and provider cells do not trigger the request
outside agent-network environments.
In `@src/modules/control-center/FlowSelector.tsx`:
- Around line 52-63: The Networks tab is only being hidden in FlowSelector, but
control-center page initialization still allows tab=networks to resolve to
FlowView.NETWORKS. Update the initial view logic in the control-center page
component so it clamps or remaps the selected tab when isAgentNetworkOnly() is
true, preventing old bookmarks and deep links from opening the hidden Networks
flow. Keep the trigger removal in FlowSelector and apply the same guard where
the tab query is translated into FlowView.
In `@src/modules/onboarding/agent-network/AgentNetworkOnboarding.tsx`:
- Line 47: The signup submission flow in AgentNetworkOnboarding is treating
onSignupSubmit as fire-and-forget even though OnboardingProvider persists signup
state asynchronously, so the step can advance too early. Update the
onSignupSubmit prop typing and the submit handling in
AgentNetworkOnboarding/related call sites to await the async result before
continuing the onboarding flow, ensuring signup_form_pending is persisted before
moving past the signup step.
In `@src/modules/onboarding/agent-network/AgentNetworkSignupForm.tsx`:
- Around line 103-128: The signup submit flow can currently fire before identity
data is ready, causing `submitForm` in `AgentNetworkSignupForm` to call
`onSubmit([])` and clear pending state with no payload. Update `canSubmit`
and/or `submitForm` so submission is blocked until `loggedInUser` or `user` is
available, and only build/call `onSubmit` with populated `HubspotFormField[]`
once email and form fields can be assembled. Use the existing `canSubmit`,
`submitForm`, and identity checks to keep the parent from receiving an empty
payload.
In `@src/modules/onboarding/agent-network/OnboardingAgentDevice.tsx`:
- Around line 11-14: The onboarding device-ready state is too broad because
OnboardingAgentDevice receives a deviceConnected signal that is currently driven
by account-wide peer count in AgentNetworkOnboarding. Update the readiness flow
so AgentNetworkOnboarding only marks the step complete when the current
machine/device is actually reachable, and adjust OnboardingAgentDevice to use
that device-specific signal rather than any peer from /peers. Keep the
Continue/modal behavior tied to the same device-specific check so existing peers
do not auto-complete the step.
In `@src/modules/onboarding/agent-network/useAgentNetworkFirstRunSetup.ts`:
- Around line 68-75: The deletion logic in useAgentNetworkFirstRunSetup
currently identifies the policy only by DEFAULT_POLICY_NAME, which can remove an
operator-customized policy instead of the seeded allow-all default. Update the
policy selection in the onboarding setup flow to use a stable server-provided
marker or a strict shape check via isSeededDefaultAccessPolicy before calling
policyRequest.del, and only trigger mutate("/policies") after confirming the
matched policy is the seeded default.
In `@src/modules/peers/PeersTable.tsx`:
- Around line 703-725: Reset the table selection when switching peer kind in
PeersTable so hidden rows do not remain selected after filtering changes. Update
the ButtonGroup.Button onClick handlers for the "users" and "servers" toggles to
clear selectedRows alongside setKind, keeping PeerMultiSelect and any bulk
actions aligned with the currently visible peers.
- Around line 292-299: The PeersTable state initialization only uses defaultKind
once, so the toolbar selection can get out of sync when navigating between
subset routes. Update the PeersTable component to keep kind synchronized with
defaultKind (the value derived from the ?kind= query) and reset selectedRows
whenever the subset changes so stale hidden peers do not remain selected. Use
the existing PeersTable, kind/setKind, defaultKind, and selectedRows state to
locate and adjust the sync logic.
---
Outside diff comments:
In `@src/modules/instance-setup/InstanceSetupWizard.tsx`:
- Around line 137-152: Clear the confirm-password mismatch as soon as either
password field changes. In `InstanceSetupWizard`, update the
`handleInputChange`/password handling so changing `password` also re-evaluates
and clears `confirmPassword` mismatch state when the two values match, not just
when editing `confirmPassword`. Also adjust `confirmPasswordError` so current
form state takes precedence over a stale `errors.confirmPassword` value,
ensuring the mismatch message disappears once `password` and `confirmPassword`
are equal.
---
Minor comments:
In `@build.sh`:
- Around line 42-47: The build.sh staging logic currently overwrites and then
always deletes the root .dockerignore, which can remove an existing repo file or
a developer’s local override. Update the cleanup() flow to preserve any
pre-existing .dockerignore by backing it up before the cp docker/.dockerignore
.dockerignore step and restoring that original file in cleanup() instead of
unconditionally removing it. Use the existing cleanup trap and the .dockerignore
staging block as the place to implement the backup/restore behavior.
In `@src/app/`(dashboard)/agent-network/configuration/page.tsx:
- Around line 30-36: The query param handling in the configuration page is
syncing any raw `tab` value from `useSearchParams` into state, which can leave
`VerticalTabs` with no matching tab. Update the `queryTab`/`setTab` flow in
`page.tsx` to validate against the allowed tab values before initializing or
updating state, and fall back to `TAB_BUDGET_SETTINGS` when the URL value is
missing or invalid. Use the existing `tab`, `setTab`, `queryTab`, and
`TAB_BUDGET_SETTINGS` symbols to keep the tab state consistent.
In `@src/app/`(dashboard)/control-center/page.tsx:
- Around line 612-620: The peer overlay edge key in applyPeerView()/the helper
that builds agent-src edges is too specific to groupId, which allows duplicate
overlapping edges when the same sourceNodeId is processed through multiple peer
groups. Change the deduplication logic to key off sourceNodeId and policy.id (or
otherwise ensure only one edge per source-target pair is created), and keep the
existing source, target, and data fields unchanged when pushing into allEdges.
In `@src/modules/onboarding/agent-network/AgentNetworkSignupForm.tsx`:
- Around line 98-100: The randomized option generation in AgentNetworkSignupForm
mutates the shared referralSourceOptions array in place, which can affect other
consumers of the module. Update the useMemo logic that builds randomizedOptions
to first clone referralSourceOptions before applying the shuffle/sort, so the
imported source array remains unchanged for other onboarding flows.
- Around line 226-249: The hidden “Other” input in AgentNetworkSignupForm should
be removed from the keyboard tab order when other is false. Update the Input
rendering so that the collapsed state also makes it non-focusable and
inaccessible, using the existing other, inputRef, and Input controls in
AgentNetworkSignupForm rather than only changing the wrapper classes. Ensure
keyboard users can only tab to the field when it is actually visible.
In `@src/modules/onboarding/agent-network/OnboardingAgentEnd.tsx`:
- Around line 29-33: The button label in OnboardingAgentEnd does not match where
onFinish actually navigates. Update the CTA text in OnboardingAgentEnd to
reflect the Control Center destination, or alternatively change the onFinish
handler in OnboardingProvider so it routes to Usage & Logs instead; keep the
label and navigation consistent with the behavior implemented in onFinish.
In `@src/modules/setup-netbird-modal/MacOSTab.tsx`:
- Around line 63-67: The external installer link in MacOSTab opens a new tab
without a rel attribute, leaving window.opener exposed. Update the Link that
uses pkgsDownloadUrl("macos/universal") to include rel="noopener noreferrer",
matching the safer pattern already used in WindowsTab for the analogous external
download link.
---
Nitpick comments:
In `@src/app/`(dashboard)/peers/page.tsx:
- Around line 70-76: The peer-to-user join in `peersWithUser` is doing a
repeated `users.find(...)` for every peer, which makes the render unnecessarily
quadratic for large lists. Build a user lookup map once inside the `useMemo`
block in `page.tsx` (near `peersWithUser`), keyed by user id, then use that map
when mapping peers so each peer resolves its `user` in constant time while
keeping the existing `force_approved` logic intact.
In `@src/modules/agent-network/data/mockData.ts`:
- Around line 5-21: The provider-id contract is still being frozen locally by
the AIProviderId union in mockData, which can drift from the server-owned
catalog. Update the persisted/provider model used by
AIProvidersProvider.fromAPI() and related data shapes to store provider_id as a
plain backend string, then only narrow to specific AIProviderId values at UI
branches that need special-case handling. Remove the need for the cast in
fromAPI() by keeping the catalog-facing type flexible and reserving the union
for client-side checks only.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 86508138-bd9f-47df-9129-e1256860e74c
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (66)
build.shconfig.jsondocker/.dockerignoredocker/init_react_envs.shsrc/app/(dashboard)/access-control/page.tsxsrc/app/(dashboard)/agent-network/configuration/page.tsxsrc/app/(dashboard)/agent-network/layout.tsxsrc/app/(dashboard)/agent-network/policies/page.tsxsrc/app/(dashboard)/agent-network/providers/page.tsxsrc/app/(dashboard)/agent-network/usage/page.tsxsrc/app/(dashboard)/control-center/page.tsxsrc/app/(dashboard)/peers/page.tsxsrc/app/(dashboard)/peers/servers/page.tsxsrc/app/(dashboard)/peers/users/page.tsxsrc/assets/icons/AgentNetworkIcon.tsxsrc/cloud/analytics/Hubspot.tsxsrc/components/DatePickerWithRange.tsxsrc/components/select/SelectDropdown.tsxsrc/components/table/DataTable.tsxsrc/components/ui/AddPeerDropdown.tsxsrc/layouts/Navigation.tsxsrc/modules/access-control/table/AccessControlTable.tsxsrc/modules/agent-network/AIProviderLogo.tsxsrc/modules/agent-network/AIProviderModal.tsxsrc/modules/agent-network/AIProvidersProvider.tsxsrc/modules/agent-network/AccessLogFilters.tsxsrc/modules/agent-network/AgentAccessLogExpandedRow.tsxsrc/modules/agent-network/AgentAccessLogTable.tsxsrc/modules/agent-network/AgentAccountControlsCard.tsxsrc/modules/agent-network/AgentBudgetRuleModal.tsxsrc/modules/agent-network/AgentBudgetRulesTable.tsxsrc/modules/agent-network/AgentConnectModal.tsxsrc/modules/agent-network/AgentGuardrailBrowseModal.tsxsrc/modules/agent-network/AgentGuardrailChecksCell.tsxsrc/modules/agent-network/AgentGuardrailModal.tsxsrc/modules/agent-network/AgentOverviewPanel.tsxsrc/modules/agent-network/AgentPoliciesTable.tsxsrc/modules/agent-network/AgentPolicyGuardrailsTab.tsxsrc/modules/agent-network/AgentPolicyLimitsTab.tsxsrc/modules/agent-network/AgentPolicyModal.tsxsrc/modules/agent-network/agentAccessLogApi.tssrc/modules/agent-network/data/mockData.tssrc/modules/agent-network/table/AgentProviderActionCell.tsxsrc/modules/agent-network/table/AgentProvidersTable.tsxsrc/modules/agent-network/useProviderCatalog.tssrc/modules/control-center/FlowSelector.tsxsrc/modules/control-center/nodes/AgentPolicyNode.tsxsrc/modules/control-center/nodes/ProviderNode.tsxsrc/modules/control-center/utils/layouts.tssrc/modules/control-center/utils/nodes.tssrc/modules/instance-setup/InstanceSetupWizard.tsxsrc/modules/onboarding/OnboardingProvider.tsxsrc/modules/onboarding/agent-network/AgentNetworkOnboarding.tsxsrc/modules/onboarding/agent-network/AgentNetworkSignupForm.tsxsrc/modules/onboarding/agent-network/OnboardingAgentConfigure.tsxsrc/modules/onboarding/agent-network/OnboardingAgentDevice.tsxsrc/modules/onboarding/agent-network/OnboardingAgentEnd.tsxsrc/modules/onboarding/agent-network/OnboardingAgentPolicy.tsxsrc/modules/onboarding/agent-network/OnboardingAgentProvider.tsxsrc/modules/onboarding/agent-network/OnboardingAgentWelcome.tsxsrc/modules/onboarding/agent-network/useAgentNetworkFirstRunSetup.tssrc/modules/peers/PeersTable.tsxsrc/modules/setup-netbird-modal/MacOSTab.tsxsrc/modules/setup-netbird-modal/WindowsTab.tsxsrc/utils/config.tssrc/utils/netbird.ts
💤 Files with no reviewable changes (1)
- src/modules/access-control/table/AccessControlTable.tsx
This PR contains the following updates: | Package | Update | Change | |---|---|---| | [netbirdio/dashboard](https://github.com/netbirdio/dashboard) | minor | `v2.39.0` → `v2.90.3` | | netbirdio/netbird | minor | `v0.73.2-rootless` → `v0.74.1-rootless` | | netbirdio/netbird-server | minor | `0.73.2` → `0.74.1` | | netbirdio/reverse-proxy | minor | `0.73.2` → `0.74.1` | --- >⚠️ **Warning** > > Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/12) for more information. --- ### Release Notes <details> <summary>netbirdio/dashboard (netbirdio/dashboard)</summary> ### [`v2.90.3`](https://github.com/netbirdio/dashboard/releases/tag/v2.90.3) [Compare Source](netbirdio/dashboard@v2.90.2...v2.90.3) #### What's Changed - Show reason for peer login expiration events by [@​bcmmbaga](https://github.com/bcmmbaga) in [#​694](netbirdio/dashboard#694) - Reload nginx after patching CSP header by [@​pappz](https://github.com/pappz) in [#​687](netbirdio/dashboard#687) - Fix peer table page reset when switching kind by [@​braginini](https://github.com/braginini) in [#​696](netbirdio/dashboard#696) - Feature/add provider session by [@​braginini](https://github.com/braginini) in [#​695](netbirdio/dashboard#695) - Add Metrics settings tab with metrics push toggle by [@​pappz](https://github.com/pappz) in [#​613](netbirdio/dashboard#613) - Feature/add skip tls verification by [@​braginini](https://github.com/braginini) in [#​697](netbirdio/dashboard#697) **Full Changelog**: <netbirdio/dashboard@v2.90.2...v2.90.3> ### [`v2.90.2`](https://github.com/netbirdio/dashboard/releases/tag/v2.90.2) [Compare Source](netbirdio/dashboard@v2.90.1...v2.90.2) #### What's Changed - Add Claude provider selector and Bedrock by [@​braginini](https://github.com/braginini) in [#​691](netbirdio/dashboard#691) - Prevent gated useFetchApi hooks from overwriting shared cache entries by [@​bcmmbaga](https://github.com/bcmmbaga) in [#​692](netbirdio/dashboard#692) **Full Changelog**: <netbirdio/dashboard@v2.90.1...v2.90.2> ### [`v2.90.1`](https://github.com/netbirdio/dashboard/releases/tag/v2.90.1) [Compare Source](netbirdio/dashboard@v2.90.0...v2.90.1) #### What's Changed - The empty-state peer card now renders AddPeerDropdown by [@​braginini](https://github.com/braginini) in [#​686](netbirdio/dashboard#686) - Support Vertex keyfile upload and agent config by [@​braginini](https://github.com/braginini) in [#​688](netbirdio/dashboard#688) - Prefill Vertex endpoint by [@​braginini](https://github.com/braginini) in [#​689](netbirdio/dashboard#689) **Full Changelog**: <netbirdio/dashboard@v2.90.0...v2.90.1> ### [`v2.90.0`](https://github.com/netbirdio/dashboard/releases/tag/v2.90.0) [Compare Source](netbirdio/dashboard@v2.80.0...v2.90.0) #### What's Changed - Fix CSP blocking OIDC token endpoint by [@​maxbrc](https://github.com/maxbrc) in [#​680](netbirdio/dashboard#680) - Agent Network by [@​braginini](https://github.com/braginini) in [#​684](netbirdio/dashboard#684) #### New Contributors - [@​maxbrc](https://github.com/maxbrc) made their first contribution in [#​680](netbirdio/dashboard#680) **Full Changelog**: <netbirdio/dashboard@v2.80.0...v2.90.0> ### [`v2.80.0`](https://github.com/netbirdio/dashboard/releases/tag/v2.80.0) [Compare Source](netbirdio/dashboard@v2.39.0...v2.80.0) #### What's Changed - Add Logout URL to the Identity Provider dialog by [@​TechHutTV](https://github.com/TechHutTV) in [#​657](netbirdio/dashboard#657) - Edit banner to IPv6 kh link by [@​TechHutTV](https://github.com/TechHutTV) in [#​662](netbirdio/dashboard#662) - Insert link to remote jobs documentation by [@​semp26](https://github.com/semp26) in [#​664](netbirdio/dashboard#664) - DNS Zones & Setup modal improvements by [@​braginini](https://github.com/braginini) in [#​669](netbirdio/dashboard#669) - Update banner by [@​heisbrot](https://github.com/heisbrot) in [#​672](netbirdio/dashboard#672) - Update announcements.json by [@​mlsmaycon](https://github.com/mlsmaycon) in [#​673](netbirdio/dashboard#673) - Merge NetBird cloud edition into the dashboard by [@​mlsmaycon](https://github.com/mlsmaycon) in [#​674](netbirdio/dashboard#674) - Restrict cloud/licensed-only API calls in open-source mode by [@​mlsmaycon](https://github.com/mlsmaycon) in [#​675](netbirdio/dashboard#675) - Preserve inactivity expiration on partial peer updates by [@​bcmmbaga](https://github.com/bcmmbaga) in [#​676](netbirdio/dashboard#676) #### New Contributors - [@​TechHutTV](https://github.com/TechHutTV) made their first contribution in [#​657](netbirdio/dashboard#657) - [@​semp26](https://github.com/semp26) made their first contribution in [#​664](netbirdio/dashboard#664) **Full Changelog**: <netbirdio/dashboard@v2.39.0...v2.80.0> </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNTAuMSIsInVwZGF0ZWRJblZlciI6IjQzLjE1MC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> Reviewed-on: https://git.jfreudenberger.de/JuliusFreudenberger/nix-config/pulls/10 Co-authored-by: Renovate Bot <renovate@jfreudenberger.de> Co-committed-by: Renovate Bot <renovate@jfreudenberger.de>
Upstream features preserved: - Agent Network (netbirdio#684, netbirdio#708) - Lazy Connections (netbirdio#706) - New Traffic Filters (netbirdio#704) - Cluster one-click deploy (netbirdio#707) - etc. i18n preserved: - All zh.ts/en.ts keys intact - Control-center, VersionInfo, Navigation translations - Translation framework (next-intl) retained Resolved: Navigation t() definition, PeersTable types
Upstream features preserved: - Agent Network (netbirdio#684, netbirdio#708) - Lazy Connections (netbirdio#706) - New Traffic Filters (netbirdio#704) - Cluster one-click deploy (netbirdio#707) - etc. i18n preserved: - All zh.ts/en.ts keys intact - Control-center, VersionInfo, Navigation translations - Translation framework (next-intl) retained Resolved: Navigation t() definition, PeersTable types
Upstream features preserved: - Agent Network (netbirdio#684, netbirdio#708) - Lazy Connections (netbirdio#706) - New Traffic Filters (netbirdio#704) - Cluster one-click deploy (netbirdio#707) - etc. i18n preserved: - All zh.ts/en.ts keys intact - Control-center, VersionInfo, Navigation translations - Translation framework (next-intl) retained Resolved: Navigation t() definition, PeersTable types
Upstream features preserved: - Agent Network (netbirdio#684, netbirdio#708) - Lazy Connections (netbirdio#706) - New Traffic Filters (netbirdio#704) - Cluster one-click deploy (netbirdio#707) - etc. i18n preserved: - All zh.ts/en.ts keys intact - Control-center, VersionInfo, Navigation translations - Translation framework (next-intl) retained Resolved: Navigation t() definition, PeersTable types
Issue ticket number and link
Documentation
Select exactly one:
Docs PR URL (required if "docs added" is checked)
Paste the PR link from https://github.com/netbirdio/docs here:
netbirdio/docs#813
E2E tests
Optional: override the image tags used by the Playwright e2e workflow.
Defaults to
mainwhen omitted.management-cloud-tag: main
reverse-proxy-tag: main
Summary by CodeRabbit
?kind=redirects and adding a dedicated blocked view.