Conversation
📝 WalkthroughWalkthroughThis PR introduces comprehensive DNS zone management functionality, including new DNS zone and record CRUD operations via a provider context, zone/record management tables and modals, integration of zones into group pages, and refactored DNS module paths. It also adds a help and support button, enhances peer expiration handling, and updates various UI components and styling. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant DNSZonesTable as DNS Zones Table
participant DNSZonesProvider as DNS Zones Provider
participant API as API
participant Cache as SWR Cache
participant Dialog as Dialog Context
participant Toast as Toast Notification
User->>DNSZonesTable: Click "Add Zone" or "Edit"
DNSZonesTable->>DNSZonesProvider: openZoneModal(zone?)
DNSZonesProvider->>DNSZonesProvider: Set modal open state
DNSZonesProvider->>User: Render DNSZoneModal
User->>User: Fill zone form<br/>(domain, groups, toggles)
User->>DNSZonesProvider: Submit (Create or Update)
alt Create Zone
DNSZonesProvider->>API: POST /dns/zones
else Update Zone
DNSZonesProvider->>API: PUT /dns/zones/{id}
end
API-->>DNSZonesProvider: Success response
DNSZonesProvider->>Cache: Trigger SWR mutation
Cache-->>DNSZonesProvider: Refetch zones
DNSZonesProvider->>Dialog: Close modal
DNSZonesProvider->>Toast: Show success notification
Toast-->>User: Display notification
DNSZonesTable-->>User: Update table with new zones
User->>DNSZonesTable: Expand zone (view records)
DNSZonesTable->>DNSZonesTable: Render DNSRecordsTable
User->>DNSZonesTable: Click "Add Record"
DNSZonesTable->>DNSZonesProvider: openRecordModal(zone, record?)
DNSZonesProvider->>User: Render DNSRecordModal
User->>User: Fill record form<br/>(name, type, content, TTL)
User->>DNSZonesProvider: Submit (Add or Update)
DNSZonesProvider->>API: POST/PUT /dns/zones/{zoneId}/records
API-->>DNSZonesProvider: Success response
DNSZonesProvider->>Cache: Trigger zone cache mutation
DNSZonesProvider->>Toast: Show success notification
DNSZonesTable-->>User: Update records table
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/components/Input.tsx (1)
20-168: Handle the new"bottom"position in layout + tooltip props.
errorTooltipPositionnow allows"bottom", but the positioning classes andFullTooltipprops still only support"top"/"top-right". This will likely render incorrectly or not at all for"bottom".✅ Suggested fix
<div className={cn( errorTooltipPosition == "top" && "absolute right-0 top-2 h-[0px] w-full flex items-center pr-3 justify-center", errorTooltipPosition == "top-right" && "absolute -right-6 top-2 h-[0px] w-full flex items-center pr-3 justify-end", + errorTooltipPosition == "bottom" && + "absolute right-0 bottom-2 h-[0px] w-full flex items-center pr-3 justify-center", )} > <FullTooltip content={ <div className={"text-xs text-red-500 inline-flex"}> <AlertCircle size={13} className={"top-[1px] relative mr-2"} /> {error} </div> } interactive={false} - align={errorTooltipPosition == "top" ? "center" : "end"} - side={"top"} + align={ + errorTooltipPosition == "top" || errorTooltipPosition == "bottom" + ? "center" + : "end" + } + side={errorTooltipPosition == "bottom" ? "bottom" : "top"} keepOpen={true} > </FullTooltip> </div>src/modules/peer/PeerExpirationToggle.tsx (1)
58-60: Grammar fix: "an setup-key" should be "a setup-key".Proposed fix
<span> - This setting is disabled for all peers added with an setup-key. + This setting is disabled for all peers added with a setup-key. </span>
🤖 Fix all issues with AI agents
In `@config.json`:
- Around line 1-9: This file contains hardcoded Auth0 credentials (fields like
"auth0Auth", "authAuthority", "authClientId", "authScopesSupported",
"authAudience", "apiOrigin", "grpcApiOrigin", "latestVersion"); replace the
committed secret config by either removing it and adding it to .gitignore (e.g.,
keep a .local-config.json out of repo) or rename it to config.example.json and
strip values into placeholders, then update README or local dev docs to instruct
developers to set AUTH0_CLIENT_ID, AUTH0_DOMAIN and other env vars (used by
docker/init_react_envs.sh) for local runs.
In `@src/components/ui/HelpAndSupportButton.tsx`:
- Around line 57-141: The DropdownMenuItem usages with external hrefs are
incorrectly using asChild which causes Radix to merge href into the first child
<div> (breaking links and excluding DropdownMenuShortcut); update each affected
instance of DropdownMenuItem (the ones that currently include asChild and
explicit target/rel: the blocks rendering Documentation, Troubleshooting,
NetBird Forum, NetBird Slack, and Feedback) by removing the asChild prop and the
manual target/rel attributes so the custom DropdownMenuItem can render its
internal <a> wrapper and handle target/rel correctly; keep the
DropdownMenuShortcut and internal <div> content unchanged and follow the same
pattern used by the support@netbird.io item and the existing correct example.
In `@src/modules/dns/zones/records/DNSRecordActionCell.tsx`:
- Around line 20-33: The action buttons in DNSRecordActionCell are causing
parent row click handlers to fire; update both button onClick handlers (the one
calling openRecordModal(zone, record) and the one calling deleteRecord(zone,
record)) to stop event propagation first (e.g., receive the click event, call
event.stopPropagation()) before invoking openRecordModal or deleteRecord so
row-level click-to-expand/selection isn’t triggered by the buttons.
In `@src/modules/dns/zones/records/DNSRecordContentCell.tsx`:
- Around line 11-16: The CopyToClipboardText wrapper isn't receiving the content
to copy; pass record.content into CopyToClipboardText so its internal
copyToClipboard(message) receives the record value—for example, provide
message={record.content} (or the prop name CopyToClipboardText expects) on the
CopyToClipboardText component that currently wraps the span displaying
{record.content}.
In `@src/modules/dns/zones/records/DNSRecordNameCell.tsx`:
- Around line 11-14: The CopyToClipboardText component is being rendered without
the required message prop in DNSRecordNameCell.tsx, which can cause the copied
value to be undefined; update the JSX where CopyToClipboardText is used (in
DNSRecordNameCell) to pass the record.name explicitly as the message prop (e.g.,
message={record.name}) so the component receives the text to copy.
In `@src/modules/dns/zones/records/DNSRecordsTable.tsx`:
- Around line 59-75: The DataTable is passed zone.records which is optional on
DNSZone; update the DNSRecordsTable component to guard by defaulting
zone.records to an empty array before passing into DataTable (e.g., use
zone.records ?? [] or Array.isArray check) so the DataTable's data prop always
receives an array; locate the DataTable usage in DNSRecordsTable and replace
data={zone.records} with a safe expression like data={zone.records ?? []} (or
validate and map if needed) and ensure any downstream uses of sorting/pagination
handle the empty array case.
In `@src/modules/dns/zones/table/DNSZonesGroupCell.tsx`:
- Line 44: The current check in DNSZonesGroupCell (where the code inspects
zone?.distribution_groups) only treats falsy values as empty, so an empty array
still proceeds to render GroupsRow; change the guard to treat an empty array as
empty by checking that distribution_groups is either falsy or has length === 0
and return EmptyRow in that case (update the conditional that references
zone?.distribution_groups to include a length check), ensuring GroupsRow only
renders when distribution_groups is a non-empty array.
In `@src/modules/dns/zones/table/DNSZonesRecordsCell.tsx`:
- Around line 22-27: In DNSZonesRecordsCell.tsx the Badge component is given a
pointer cursor, useHover and an onClick that does nothing which creates a
misleading interactive affordance; either remove the interactivity by deleting
the onClick handler and remove useHover and the "cursor-pointer" class from the
Badge, or wire the Badge to a real action (e.g., call an
openRecords/openZoneRecords function or router navigation) and implement that
handler instead so the visual affordance matches behavior.
In `@src/modules/dns/zones/table/DNSZonesTable.tsx`:
- Around line 125-135: zonesWithGroups useMemo can crash when groups is
undefined; update the mapping that builds groups_search to guard groups (and
distribution_groups) by defaulting to empty arrays. For example, in the useMemo
that defines zonesWithGroups, change the groups?.map(...) to (groups ??
[]).map(...) and ensure zone?.distribution_groups?.includes(...) is safe (e.g.,
(zone?.distribution_groups ?? []).includes(...)) so groups_search is produced
without throwing and still typed as DNSZone.
- Around line 76-85: The accessorFn for id "searchString" can crash when
row.records is undefined because calling .map(...).join("") on undefined throws;
update the accessorFn to default records to an empty array or guard before
mapping (e.g., use row?.records ?? [] or check if Array.isArray(row.records)) so
each records-based expression uses a safe array before .map(...).join("") and
returns an empty string when records are missing.
In `@src/modules/peer/PeerSSHToggle.tsx`:
- Around line 313-337: The modal/provider rendering is currently gated by
permission?.policies.create which prevents users with only policies.update from
opening AccessControlModalContent for edits; change the condition to check
either create or update (e.g., permission?.policies.create ||
permission?.policies.update) so PoliciesProvider, Modal,
AccessControlModalContent (with policy={currentPolicy} and onSuccess that calls
setPolicyModal and setCurrentPolicy) and PeerSSHPolicyModal render for users
with update permission as well.
🧹 Nitpick comments (14)
src/components/ui/UserAvatar.tsx (3)
15-20: Consider using an integer for the "medium" size.The value
35.2may cause subpixel rendering inconsistencies in some browsers. Consider rounding to35or36for cleaner rendering, unless the exact 2.2rem match with the fallback div is intentional.💡 Suggested change
const getAvatarSize = () => { if (size === "small") return 32; if (size === "default") return 40; if (size === "large") return 48; - return 35.2; + return 35; };
22-30: Improve accessibility with a meaningfulaltattribute.The empty
alt=""marks the image as decorative, but a user avatar is meaningful content. Consider using a descriptive alt text.♿ Suggested improvement
<Image src={user?.picture} - alt={""} + alt={user?.name ? `${user.name}'s avatar` : "User avatar"} onError={() => setPictureLoaded(false)} width={getAvatarSize()} height={getAvatarSize()} className={"rounded-full"} />
24-24: Minor: Redundant optional chaining.
user?.pictureis already verified on line 22, so the optional chaining onsrc={user?.picture}is unnecessary. Consider usinguser.picturefor consistency.src/modules/peer/PeerExpirationSettings.tsx (3)
18-23: Local state may become stale if peer data changes externally.The local state is initialized from
peerprops but won't update if the peer data is refetched/mutated elsewhere. Consider resetting state whenpeer.idchanges, or derive state directly frompeerprops.Option: Sync state with peer changes
+ import { useEffect } from "react"; const [peerLoginExpiration, setPeerLoginExpiration] = useState( peer.login_expiration_enabled, ); const [peerInactivityExpiration, setPeerInactivityExpiration] = useState( peer.inactivity_expiration_enabled, ); + useEffect(() => { + setPeerLoginExpiration(peer.login_expiration_enabled); + setPeerInactivityExpiration(peer.inactivity_expiration_enabled); + }, [peer.id, peer.login_expiration_enabled, peer.inactivity_expiration_enabled]);
25-49: Consider handling update failures to keep UI state consistent.If
update()fails, the local state (peerLoginExpiration,peerInactivityExpiration) will be out of sync with the server. Thenotifyshows a loading message but doesn't revert state on error.Proposed fix: Revert state on failure
const updateExpiration = async ({ loginExpiration, inactivityExpiration, }: { loginExpiration?: boolean; inactivityExpiration?: boolean; }) => { if (!permission?.peers.update) return; + const previousLogin = peerLoginExpiration; + const previousInactivity = peerInactivityExpiration; const promise = update({ loginExpiration, inactivityExpiration, }).then(() => { mutate("/peers/" + peer.id); + }).catch((error) => { + setPeerLoginExpiration(previousLogin); + setPeerInactivityExpiration(previousInactivity); + throw error; }); notify({ title: peer.name, description: "Expiration was successfully updated", promise, loadingMessage: "Updating setting...", }); return promise; };
71-101: Minor: Redundant disabled styling applied in multiple places.The disabled styling (
opacity-50 pointer-events-none) is applied both on the container div (lines 75-76) and on the innerPeerExpirationToggleviaclassName(lines 97-98) when!peerLoginExpiration. This duplication is harmless but could be simplified.src/components/DropdownMenu.tsx (2)
132-138: Anchor element doesn't fill the full clickable area.The
<a>element is rendered inline within the menu item, which means only the text portion is clickable for navigation—not the full padded area. Users clicking the padding around the text will trigger the Radix item behavior but won't navigate.Consider applying styles to make the anchor fill the entire item area.
♻️ Proposed fix
{href ? ( - <a href={href} target={target} rel={rel}> + <a + href={href} + target={target} + rel={rel} + className="flex items-center gap-2 w-full h-full" + > {props.children} </a> ) : ( props.children )}
124-129: Consider passing the original onClick through for href items.Currently,
onClickis completely ignored whenhrefis set. This prevents consumers from performing side effects (e.g., analytics tracking, closing modals) alongside navigation.♻️ Proposed enhancement
onClick={(e) => { - if (href) return; - e.preventDefault(); - e.stopPropagation(); - onClick && onClick(e); + if (href) { + onClick?.(e); + return; + } + e.preventDefault(); + e.stopPropagation(); + onClick?.(e); }}src/interfaces/DNS.ts (1)
12-20: Consider referencing DNSRecordType in DNSRecord interface.The
typefield inDNSRecordduplicates the literal union that's already defined asDNSRecordType. Using the type alias improves maintainability.♻️ Proposed fix
+export type DNSRecordType = "A" | "AAAA" | "CNAME"; + export interface DNSRecord { id?: string; name: string; - type: "A" | "AAAA" | "CNAME"; + type: DNSRecordType; content: string; ttl: number; } - -export type DNSRecordType = "A" | "AAAA" | "CNAME";src/modules/dns/zones/records/DNSRecordTypeCell.tsx (1)
2-2: Unused React import.With modern JSX transform (React 17+), explicit React import isn't required for JSX. This import can be removed.
♻️ Proposed fix
import Badge from "@components/Badge"; -import * as React from "react"; import { DNSRecord } from "@/interfaces/DNS";src/modules/dns/zones/records/DNSRecordTimeToLiveCell.tsx (1)
1-5: MovegetTTLLabelto a shared DNS util.Importing it from
DNSRecordModal.tsxcouples this cell to a modal and can bloat bundles or create circular dependencies. Consider relocating it (e.g.,src/modules/dns/zones/utils.ts) and importing from there.src/modules/groups/details/useGroupDetails.ts (1)
36-76: Consider server-side filtering for zones fetch.Fetching all zones and filtering client-side may become costly at scale. If the API supports it, consider a group-scoped query (e.g.,
/dns/zones?group_id=...) or a dedicated endpoint to reduce payload and latency.src/modules/dns/zones/table/DNSZonesActionCell.tsx (1)
32-34: Add an accessible label to the icon-only actions button.
Screen readers need a label for the kebab button.♿ Suggested tweak
- <Button variant={"secondary"} className={"!px-3"}> + <Button + variant={"secondary"} + className={"!px-3"} + aria-label="Zone actions" + >src/components/ui/HelpAndSupportButton.tsx (1)
36-46: Add an accessible label to the help button.
Icon-only controls should expose an aria-label.♿ Suggested tweak
- <Button - size={"xs"} - variant={"default-outline"} - className={cn( - "!rounded-full h-[38px] w-[38px] !p-0", - dropdownOpen && "text-white", - )} - > + <Button + size={"xs"} + variant={"default-outline"} + className={cn( + "!rounded-full h-[38px] w-[38px] !p-0", + dropdownOpen && "text-white", + )} + aria-label="Help and support" + >
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (59)
config.jsonpackage.jsonsrc/app/(dashboard)/dns/nameservers/page.tsxsrc/app/(dashboard)/dns/zones/layout.tsxsrc/app/(dashboard)/dns/zones/page.tsxsrc/app/(dashboard)/group/page.tsxsrc/app/(dashboard)/peer/page.tsxsrc/assets/icons/DNSZoneIcon.tsxsrc/assets/icons/SlackIcon.tsxsrc/components/Button.tsxsrc/components/DropdownMenu.tsxsrc/components/Input.tsxsrc/components/table/Table.tsxsrc/components/ui/HelpAndSupportButton.tsxsrc/components/ui/NoResults.tsxsrc/components/ui/PeerCountBadge.tsxsrc/components/ui/UserAvatar.tsxsrc/components/ui/UserDropdown.tsxsrc/contexts/AnnouncementProvider.tsxsrc/contexts/DialogProvider.tsxsrc/interfaces/DNS.tssrc/layouts/Header.tsxsrc/layouts/Navigation.tsxsrc/modules/dns/nameservers/NameserverModal.tsxsrc/modules/dns/nameservers/NameserverTemplateModal.tsxsrc/modules/dns/nameservers/table/NameserverActionCell.tsxsrc/modules/dns/nameservers/table/NameserverActiveCell.tsxsrc/modules/dns/nameservers/table/NameserverDistributionGroupsCell.tsxsrc/modules/dns/nameservers/table/NameserverGroupTable.tsxsrc/modules/dns/nameservers/table/NameserverMatchDomainsCell.tsxsrc/modules/dns/nameservers/table/NameserverNameCell.tsxsrc/modules/dns/nameservers/table/NameserverNameserversCell.tsxsrc/modules/dns/zones/DNSRecordModal.tsxsrc/modules/dns/zones/DNSZoneModal.tsxsrc/modules/dns/zones/DNSZonesProvider.tsxsrc/modules/dns/zones/records/DNSRecordActionCell.tsxsrc/modules/dns/zones/records/DNSRecordContentCell.tsxsrc/modules/dns/zones/records/DNSRecordNameCell.tsxsrc/modules/dns/zones/records/DNSRecordTimeToLiveCell.tsxsrc/modules/dns/zones/records/DNSRecordTypeCell.tsxsrc/modules/dns/zones/records/DNSRecordsTable.tsxsrc/modules/dns/zones/table/DNSZonesActionCell.tsxsrc/modules/dns/zones/table/DNSZonesActiveCell.tsxsrc/modules/dns/zones/table/DNSZonesGroupCell.tsxsrc/modules/dns/zones/table/DNSZonesNameCell.tsxsrc/modules/dns/zones/table/DNSZonesRecordsCell.tsxsrc/modules/dns/zones/table/DNSZonesSearchDomainCell.tsxsrc/modules/dns/zones/table/DNSZonesTable.tsxsrc/modules/groups/details/GroupDNSZonesSection.tsxsrc/modules/groups/details/GroupNameserversSection.tsxsrc/modules/groups/details/useGroupDetails.tssrc/modules/groups/table/GroupsTable.tsxsrc/modules/groups/useGroupsUsage.tsxsrc/modules/peer/PeerExpirationSettings.tsxsrc/modules/peer/PeerExpirationToggle.tsxsrc/modules/peer/PeerSSHToggle.tsxsrc/modules/routes/RouteTable.tsxsrc/modules/settings/AuthenticationTab.tsxtailwind.config.ts
💤 Files with no reviewable changes (1)
- src/modules/settings/AuthenticationTab.tsx
🧰 Additional context used
🧬 Code graph analysis (32)
src/components/ui/HelpAndSupportButton.tsx (3)
src/utils/helpers.ts (1)
cn(6-8)src/utils/netbird.ts (1)
isNetBirdHosted(18-22)src/assets/icons/SlackIcon.tsx (1)
SlackIcon(3-30)
src/modules/dns/zones/records/DNSRecordTypeCell.tsx (2)
src/interfaces/DNS.ts (1)
DNSRecord(12-18)src/components/Badge.tsx (1)
Badge(56-78)
src/modules/dns/zones/table/DNSZonesGroupCell.tsx (7)
src/interfaces/DNS.ts (1)
DNSZone(1-10)src/contexts/GroupsProvider.tsx (1)
useGroups(163-163)src/modules/dns/zones/DNSZonesProvider.tsx (1)
useDNSZones(264-264)src/contexts/PermissionsProvider.tsx (1)
usePermissions(39-39)src/interfaces/Group.ts (1)
Group(1-12)src/modules/common-table-rows/EmptyRow.tsx (1)
EmptyRow(7-9)src/modules/common-table-rows/GroupsRow.tsx (1)
GroupsRow(40-101)
src/modules/dns/zones/records/DNSRecordActionCell.tsx (4)
src/interfaces/DNS.ts (1)
DNSRecord(12-18)src/contexts/PermissionsProvider.tsx (1)
usePermissions(39-39)src/modules/dns/zones/DNSZonesProvider.tsx (1)
useDNSZones(264-264)src/modules/dns/zones/records/DNSRecordsTable.tsx (1)
useDNSZone(80-80)
src/components/ui/PeerCountBadge.tsx (1)
src/contexts/GroupsProvider.tsx (1)
useGroups(163-163)
src/modules/dns/zones/table/DNSZonesNameCell.tsx (3)
src/interfaces/DNS.ts (1)
DNSZone(1-10)src/utils/helpers.ts (1)
cn(6-8)src/modules/common-table-rows/ActiveInactiveRow.tsx (1)
ActiveInactiveRow(17-57)
src/modules/dns/zones/table/DNSZonesSearchDomainCell.tsx (4)
src/interfaces/DNS.ts (1)
DNSZone(1-10)src/contexts/PermissionsProvider.tsx (1)
usePermissions(39-39)src/modules/dns/zones/DNSZonesProvider.tsx (1)
useDNSZones(264-264)src/components/ToggleSwitch.tsx (1)
ToggleSwitch(71-71)
src/layouts/Navigation.tsx (1)
src/components/SidebarItem.tsx (1)
SidebarItem(26-142)
src/app/(dashboard)/dns/nameservers/page.tsx (1)
src/modules/dns/nameservers/table/NameserverGroupTable.tsx (1)
NameserverGroupTable(101-298)
src/components/ui/NoResults.tsx (1)
src/utils/helpers.ts (1)
cn(6-8)
src/modules/peer/PeerSSHToggle.tsx (4)
src/utils/api.tsx (1)
useFetchApi(120-167)src/interfaces/Policy.ts (1)
Policy(4-12)src/contexts/PoliciesProvider.tsx (1)
PoliciesProvider(25-95)src/modules/peer/PeerSSHPolicyModal.tsx (1)
PeerSSHPolicyModal(13-34)
src/modules/dns/zones/DNSRecordModal.tsx (5)
src/interfaces/DNS.ts (4)
DNSZone(1-10)DNSRecord(12-18)DNSRecordType(20-20)DNS_RECORDS_DOCS_LINK(23-23)src/modules/dns/zones/DNSZonesProvider.tsx (1)
useDNSZones(264-264)src/components/Separator.tsx (1)
Separator(1-3)src/components/HelpText.tsx (1)
HelpText(9-25)src/components/InlineLink.tsx (1)
InlineLink(37-43)
src/assets/icons/SlackIcon.tsx (1)
src/assets/icons/IconProperties.tsx (2)
IconProps(1-5)iconProperties(14-26)
src/app/(dashboard)/dns/zones/page.tsx (5)
src/contexts/PermissionsProvider.tsx (1)
usePermissions(39-39)src/interfaces/DNS.ts (2)
DNSZone(1-10)DNS_ZONE_DOCS_LINK(22-22)src/hooks/usePortalElement.tsx (1)
usePortalElement(3-12)src/layouts/PageContainer.tsx (1)
PageContainer(9-25)src/modules/dns/zones/DNSZonesProvider.tsx (1)
DNSZonesProvider(33-262)
src/components/ui/UserAvatar.tsx (1)
src/utils/helpers.ts (1)
cn(6-8)
src/modules/dns/zones/records/DNSRecordTimeToLiveCell.tsx (2)
src/interfaces/DNS.ts (1)
DNSRecord(12-18)src/modules/dns/zones/DNSRecordModal.tsx (1)
getTTLLabel(347-359)
src/modules/groups/details/useGroupDetails.ts (2)
src/interfaces/DNS.ts (1)
DNSZone(1-10)src/utils/api.tsx (1)
useFetchApi(120-167)
src/assets/icons/DNSZoneIcon.tsx (1)
src/assets/icons/IconProperties.tsx (2)
IconProps(1-5)iconProperties(14-26)
src/modules/peer/PeerExpirationSettings.tsx (6)
src/contexts/PeerProvider.tsx (1)
usePeer(193-193)src/contexts/PermissionsProvider.tsx (1)
usePermissions(39-39)src/modules/account/useAccount.tsx (1)
useAccount(6-21)src/components/Notification.tsx (1)
notify(151-155)src/modules/peer/PeerExpirationToggle.tsx (1)
PeerExpirationToggle(25-114)src/utils/helpers.ts (1)
cn(6-8)
src/components/DropdownMenu.tsx (1)
src/utils/helpers.ts (1)
cn(6-8)
src/modules/groups/details/GroupDNSZonesSection.tsx (5)
src/interfaces/DNS.ts (1)
DNSZone(1-10)src/contexts/GroupProvider.tsx (1)
useGroupContext(329-335)src/modules/groups/details/GroupDetailsTableContainer.tsx (1)
GroupDetailsTableContainer(14-47)src/modules/dns/zones/DNSZonesProvider.tsx (1)
DNSZonesProvider(33-262)src/modules/dns/zones/table/DNSZonesTable.tsx (1)
DNSZonesTable(98-282)
src/modules/dns/zones/records/DNSRecordContentCell.tsx (2)
src/interfaces/DNS.ts (1)
DNSRecord(12-18)src/components/CopyToClipboardText.tsx (1)
CopyToClipboardText(14-60)
src/app/(dashboard)/group/page.tsx (3)
src/assets/icons/DNSZoneIcon.tsx (1)
DNSZoneIcon(3-19)src/utils/helpers.ts (1)
singularize(247-259)src/modules/groups/details/GroupDNSZonesSection.tsx (1)
GroupDNSZonesSection(8-29)
src/modules/dns/zones/records/DNSRecordNameCell.tsx (2)
src/interfaces/DNS.ts (1)
DNSRecord(12-18)src/components/CopyToClipboardText.tsx (1)
CopyToClipboardText(14-60)
src/layouts/Header.tsx (1)
src/components/ui/HelpAndSupportButton.tsx (1)
HelpAndSupportButton(27-145)
src/modules/peer/PeerExpirationToggle.tsx (5)
src/contexts/PermissionsProvider.tsx (1)
usePermissions(39-39)src/modules/account/useAccount.tsx (1)
useAccount(6-21)src/components/InlineLink.tsx (1)
InlineLink(37-43)src/components/FullTooltip.tsx (1)
FullTooltip(33-108)src/components/FancyToggleSwitch.tsx (1)
FancyToggleSwitch(50-105)
src/modules/dns/zones/table/DNSZonesTable.tsx (13)
src/interfaces/DNS.ts (2)
DNSZone(1-10)DNS_ZONE_DOCS_LINK(22-22)src/modules/dns/zones/table/DNSZonesNameCell.tsx (1)
DNSZonesNameCell(11-38)src/modules/dns/zones/table/DNSZonesActiveCell.tsx (1)
DNSZonesActiveCell(11-32)src/modules/dns/zones/table/DNSZonesGroupCell.tsx (1)
DNSZonesGroupCell(15-60)src/modules/dns/zones/table/DNSZonesSearchDomainCell.tsx (1)
DNSZonesSearchDomainCell(11-32)src/modules/dns/zones/table/DNSZonesActionCell.tsx (1)
DNSZonesActionCell(18-58)src/contexts/GroupsProvider.tsx (1)
useGroups(163-163)src/hooks/useLocalStorage.tsx (1)
useLocalStorage(20-124)src/components/table/DataTable.tsx (1)
DataTable(184-635)src/modules/dns/zones/records/DNSRecordsTable.tsx (1)
DNSRecordsTable(54-78)src/assets/icons/DNSZoneIcon.tsx (1)
DNSZoneIcon(3-19)src/components/ui/GetStartedTest.tsx (1)
GetStartedTest(16-79)src/contexts/PermissionsProvider.tsx (1)
usePermissions(39-39)
src/modules/dns/zones/table/DNSZonesActiveCell.tsx (4)
src/interfaces/DNS.ts (1)
DNSZone(1-10)src/contexts/PermissionsProvider.tsx (1)
usePermissions(39-39)src/modules/dns/zones/DNSZonesProvider.tsx (1)
useDNSZones(264-264)src/components/ToggleSwitch.tsx (1)
ToggleSwitch(71-71)
src/modules/dns/zones/DNSZonesProvider.tsx (7)
src/interfaces/DNS.ts (2)
DNSZone(1-10)DNSRecord(12-18)src/interfaces/Group.ts (1)
Group(1-12)src/utils/api.tsx (1)
useApiCall(169-212)src/contexts/DialogProvider.tsx (1)
useDialog(134-134)src/components/Notification.tsx (1)
notify(151-155)src/modules/dns/zones/DNSZoneModal.tsx (1)
DNSZoneModal(37-65)src/modules/dns/zones/DNSRecordModal.tsx (1)
DNSRecordModal(43-74)
src/app/(dashboard)/peer/page.tsx (1)
src/modules/peer/PeerExpirationSettings.tsx (1)
PeerExpirationSettings(12-105)
src/modules/groups/useGroupsUsage.tsx (2)
src/utils/api.tsx (1)
useFetchApi(120-167)src/interfaces/DNS.ts (1)
DNSZone(1-10)
src/modules/groups/table/GroupsTable.tsx (2)
src/assets/icons/DNSZoneIcon.tsx (1)
DNSZoneIcon(3-19)src/modules/groups/table/GroupsCountCell.tsx (1)
GroupsCountCell(15-59)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build_n_push
🔇 Additional comments (61)
src/components/table/Table.tsx (1)
106-108: LGTM!The hover background color adjustment for minimal table rows (from
nb-gray-900/10tonb-gray-910/[15%]) is a valid styling refinement. The Tailwind arbitrary value syntax is correct.src/components/ui/UserAvatar.tsx (1)
31-46: LGTM!The fallback UI correctly displays the user's initial with appropriate sizing that aligns with the Image component dimensions.
src/app/(dashboard)/peer/page.tsx (4)
67-67: LGTM!The import of
PeerExpirationSettingsis correctly added to support the refactored expiration management.
100-102: LGTM!Using
peer?.idas the React key is appropriate here. The parentPeerProvideralready useskey={peerId}, ensuring proper remounting when the peer changes.
146-149: LGTM!The
hasChangestracking now correctly excludes expiration states since they are managed independently byPeerExpirationSettings. This separation of concerns keeps the save flow focused on group changes only.Also applies to: 169-169
265-265: LGTM!Clean delegation to
PeerExpirationSettingscomponent. This encapsulates expiration-related logic and UI, improving maintainability.src/modules/peer/PeerExpirationSettings.tsx (2)
1-10: LGTM!Imports are clean and appropriately organized, using the project's established alias patterns.
61-69: LGTM!Good UX: when login expiration is disabled, inactivity expiration is automatically turned off as well, maintaining logical consistency between the two related settings.
src/modules/peer/PeerExpirationToggle.tsx (5)
6-12: LGTM!New imports are appropriate for the enhanced functionality:
ArrowUpRightIconfor the settings link,useMemofor memoized tooltip content,InlineLinkfor navigation, anduseAccountfor account-level settings.
22-22: LGTM!The new
typeprop with a sensible default value enables this component to be reused for both login expiration and inactivity expiration scenarios.Also applies to: 34-34
37-49: LGTM!Account-level global setting checks are properly implemented, correctly mapping the
typeprop to the corresponding account setting. This ensures the toggle respects admin-configured global policies.
51-90: LGTM!The
useMemofor tooltip content is well-structured with correct dependencies. The conditional rendering provides clear, actionable feedback to users about why the toggle may be disabled.
92-113: LGTM!The render logic correctly:
- Disables the tooltip when no content is needed
- Disables the toggle when global settings are off or user lacks permission
- Forces value to
falsewhen global setting is disabled, preventing misleading UI statepackage.json (1)
64-64: Theip-address@10.1.0package is legitimate, maintained, and the latest version. No security vulnerabilities or audit issues were detected. This dependency is appropriate for IP address parsing in the DNS zone management functionality.src/modules/peer/PeerSSHToggle.tsx (2)
40-45: Permission-gated fetch looks good.Tying the policies fetch to
permission?.policies.readis a clean, permission-aware optimization.
209-213: Button permission gating looks solid.Disabling creation when
policies.createis false matches expected access control.src/modules/dns/nameservers/NameserverTemplateModal.tsx (1)
12-12: Import path update looks good.
Aligns with the refactor without affecting behavior.src/components/ui/NoResults.tsx (1)
9-29: Nice, flexible styling hook for content.
This keeps defaults while enabling targeted overrides.Also applies to: 71-73
tailwind.config.ts (1)
32-34: Palette update is straightforward.
Token update/addition is clear and low risk.src/contexts/DialogProvider.tsx (1)
66-71: Confirm intended dismissal behavior.
Blocking outside interactions changes how users can exit the dialog; please confirm this is desired for all confirmation dialogs (including whether ESC should still close).src/modules/routes/RouteTable.tsx (1)
146-151: Styling update is clean and consistent.
Switching to the new nb-gray-960 token looks good.src/contexts/AnnouncementProvider.tsx (1)
10-11: Release note copy/link update looks good.Content-only change with no functional impact.
src/layouts/Navigation.tsx (1)
146-151: DNS “Zones” nav entry is wired correctly.Permission-gated child link integrates cleanly with the DNS group.
src/modules/dns/nameservers/table/NameserverGroupTable.tsx (1)
22-29: Import path flattening is consistent.Looks clean and aligns with the new module structure.
src/app/(dashboard)/dns/nameservers/page.tsx (1)
10-19: Icon swap and lazy import path update look good.No behavioral change; consistent with the new DNS module paths.
Also applies to: 43-43
src/assets/icons/DNSZoneIcon.tsx (1)
1-19: New DNSZoneIcon implementation looks solid.Follows existing icon conventions and integrates with iconProperties.
src/modules/groups/details/GroupNameserversSection.tsx (1)
6-8: Lazy import path update looks good.No issues spotted with the new module path.
src/assets/icons/SlackIcon.tsx (1)
1-29: Slack icon component looks consistent with existing icon pattern.No concerns with the SVG composition or prop usage.
src/app/(dashboard)/dns/zones/layout.tsx (1)
1-8: Layout + metadata wiring is clean.No issues found.
src/modules/dns/zones/table/DNSZonesSearchDomainCell.tsx (1)
11-28: Toggle cell behavior looks solid.Permissions and update logic are applied consistently.
src/components/ui/UserDropdown.tsx (1)
44-44: LGTM!Minor spacing adjustment for tighter vertical rhythm in the user label area.
src/components/ui/PeerCountBadge.tsx (1)
24-27: LGTM - fallback lookup improves robustness.The fallback from
dropdownOptionstogroupsensures the component can resolve group data even when the dropdown options are filtered differently. The dependency array is correctly updated.Minor note: matching by
nameassumes group names are unique. If that invariant could break, consider matching byidinstead.src/interfaces/DNS.ts (1)
22-23: Both documentation links point to the same URL.
DNS_ZONE_DOCS_LINKandDNS_RECORDS_DOCS_LINKare identical. If there's a separate documentation page for DNS records, updateDNS_RECORDS_DOCS_LINKaccordingly. Otherwise, consider consolidating to a single constant.src/modules/dns/zones/records/DNSRecordTypeCell.tsx (1)
9-19: LGTM!Clean, focused component for rendering DNS record types. The uppercase styling with tracking provides good visual distinction for the record type labels.
src/components/Button.tsx (1)
76-80: Open-state styling fordefault-outlinelooks good.src/app/(dashboard)/group/page.tsx (1)
134-331: Zones tab integration matches existing tab patterns.src/layouts/Header.tsx (1)
14-69: Header updates integrate Help & Support cleanly.src/modules/dns/zones/table/DNSZonesActiveCell.tsx (1)
11-29: LGTM: permission-aware toggle wiring.Clean and readable toggle behavior with permission gating and safe click handling.
src/modules/groups/details/useGroupDetails.ts (1)
17-21: Good addition to GroupDetails.Exposing
zoneson the group details object keeps the group view cohesive.src/modules/dns/zones/table/DNSZonesNameCell.tsx (1)
11-35: LGTM: clear accordion/active-state presentation.The conditional chevrons and ActiveInactiveRow integration look solid.
src/modules/dns/zones/DNSZoneModal.tsx (2)
37-63: Clean modal wiring.The open/close and success callbacks are composed cleanly.
86-88: No changes needed — the hook correctly handles string IDs.The
useGroupHelperhook explicitly accepts bothGroup[]andstring[]for itsinitialprop (see lines 20–28 ofsrc/modules/groups/useGroupHelper.tsx). When given string IDs, it automatically resolves them toGroupobjects by looking them up in the groups context. The current code at lines 86–88 is correct: passingzone?.distribution_groups(which isstring[]) is the intended use case and requires no changes.src/modules/dns/zones/records/DNSRecordsTable.tsx (1)
16-50: Column definitions look consistent and well-factored.src/app/(dashboard)/dns/zones/page.tsx (1)
23-67: Page composition is clean and well-scoped.src/modules/groups/details/GroupDNSZonesSection.tsx (1)
8-27: Nice, compact section wiring for group-level zones.src/modules/dns/zones/table/DNSZonesActionCell.tsx (1)
22-55: DNS zone action wiring looks solid.
Edit/delete hooks and permission gating are clear and consistent.src/components/ui/HelpAndSupportButton.tsx (1)
1-35: Controlled dropdown state is wired correctly.
The open state and onOpenChange handling are straightforward.src/modules/groups/table/GroupsTable.tsx (3)
1-23: Import updates align with the new Zones column.
Looks consistent with the new icon usage.
182-203: Zones column integration looks good.
The header, icon, and link target are consistent with other count columns.
234-244: In-use calculation update is correct.
Including zones in the “in use” signal is consistent with the new column.src/modules/groups/useGroupsUsage.tsx (3)
1-20: Type updates for zones_count look good.
Imports and GroupUsage shape align with the new zones data.
29-70: Zones fetch and loading integration are consistent.
The new zones request and loading flag are wired into the memo flow as expected.Also applies to: 88-106
121-170: zones_count aggregation is correctly added to GroupUsage.
The count computation and dependency list look solid.src/modules/dns/zones/DNSZonesProvider.tsx (4)
1-31: Context surface and setup look clean.
The provider API is clearly defined.
45-105: Zone CRUD flow with notifications looks solid.
Mutations and success toasts are consistently wired.
107-190: Record CRUD flow is well-structured.
Confirmations and SWR revalidation are handled consistently.
192-259: Modal orchestration and cleanup look good.
State resets on close are handled cleanly.src/modules/dns/zones/DNSRecordModal.tsx (3)
43-73: Nice modal orchestration and post-add UX.
Clean open/close handling and the auto-expand + scroll behavior is a good touch.
83-345: Solid validation + type-specific inputs.
The state/validation wiring and conditional inputs look robust and easy to follow.
347-359: Clear TTL labeling helper.
Readable and well-scoped utility for display labels.src/modules/dns/zones/table/DNSZonesTable.tsx (1)
288-301: Permission-gated Add Zone button looks good.
Simple and consistent with the rest of the permission model.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
Summary by CodeRabbit
New Features
Improvements
UI/Style
Chores
✏️ Tip: You can customize this high-level summary in your review settings.