Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add region and public ip to peer table and detailed peer view #340

Merged
merged 53 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
7c8cb65
Init Dashboard V2
heisbrot Jan 29, 2024
0695d44
Update README.md
heisbrot Jan 29, 2024
ea4a207
use dedicated var and prevent push on PRs
mlsmaycon Jan 29, 2024
dbd3feb
Fix redirect link to event streaming docs
heisbrot Feb 1, 2024
54e66d4
Add iOS operating system icon
heisbrot Feb 2, 2024
90d80c3
Refactor
heisbrot Feb 2, 2024
879d24d
Add autocomplete input
heisbrot Feb 2, 2024
dda557c
Use idtoken source for token
heisbrot Feb 2, 2024
877c0d1
Add posture check modal with checks
heisbrot Feb 2, 2024
707ada6
Fix peer last seen in detail view
heisbrot Feb 6, 2024
b6a777a
Fix last seen date of user
heisbrot Feb 6, 2024
b980047
Add sliding tabs ui component
heisbrot Feb 6, 2024
a819510
Add posture check ui cards
heisbrot Feb 6, 2024
7b27112
Add draft for operating system check ui
heisbrot Feb 8, 2024
9c3b0cb
Add better ui for locations
heisbrot Feb 9, 2024
7169d52
Add better ui for os check
heisbrot Feb 12, 2024
117057d
Merge branch 'main' into feature/posture-checks
heisbrot Feb 12, 2024
22e94a4
Add create posture checks, add select posture check (draft)
heisbrot Feb 13, 2024
6a634fe
Add posture check selection
heisbrot Feb 13, 2024
153a37c
Update posture checks selection modal
heisbrot Feb 13, 2024
a22e800
Add radix radio group
heisbrot Feb 13, 2024
7639f56
Add edit and browse posture checks
heisbrot Feb 14, 2024
ef4f08a
Add posture check cell to access control
heisbrot Feb 14, 2024
0ead53e
Optimize select dropdown performance
heisbrot Feb 14, 2024
e7cb586
Add posture check page
heisbrot Feb 16, 2024
00ff4a9
Update workflow
heisbrot Feb 16, 2024
fe40a5e
Merge branch 'main' into feature/posture-checks
heisbrot Feb 16, 2024
2b79496
Return no results if source_posture_checks is undefined
heisbrot Feb 16, 2024
433bae0
Add flag icons
heisbrot Feb 16, 2024
f1cd664
Add loading indicator and fix some ui issues
heisbrot Feb 16, 2024
085662c
Add loading indicator for country and cities
heisbrot Feb 16, 2024
d70e873
Disable select dropdown while loading
heisbrot Feb 16, 2024
c5564c3
Disable select dropdown while loading, add tooltip for description
heisbrot Feb 16, 2024
3a5799b
Merge branch 'main' into feature/posture-checks
heisbrot Feb 16, 2024
9392e32
Add MaxMind licence information and refactor code
heisbrot Feb 19, 2024
eae8249
Add tooltips for checks, refactor posture check modal
heisbrot Feb 20, 2024
67896ca
Remove unused state
heisbrot Feb 20, 2024
f1b84e6
Disable delete button when posture check is assigned to policies
heisbrot Feb 21, 2024
97e6bac
Add semantic version input validation for operating-system and netbir…
heisbrot Feb 21, 2024
40b6f89
Restore build_and_push.yml
heisbrot Feb 21, 2024
d7fe14f
Fix group badge icon size
heisbrot Feb 22, 2024
cb1d6ce
Fix copy icon size
heisbrot Feb 22, 2024
771dd27
Add region information to peer table and single peer view
heisbrot Feb 22, 2024
d059b77
Merge branch 'main' into feature/peer-region
heisbrot Feb 22, 2024
a2308be
Push to docker
heisbrot Feb 22, 2024
303d2d6
Change login expired icon size
heisbrot Feb 23, 2024
5b114b9
Fix country flag in single peer view
heisbrot Feb 23, 2024
8d74504
Change country flag size in peer table
heisbrot Feb 23, 2024
a6ca799
Disable revalidation for countries
heisbrot Feb 23, 2024
ac6e9b9
Fix icon size on peer detail view
heisbrot Feb 23, 2024
ad5630c
Rollback workflow
heisbrot Feb 23, 2024
d581127
Merge branch 'main' into feature/peer-region
heisbrot Feb 23, 2024
98ba1c6
Revert login expiration
heisbrot Feb 23, 2024
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
54 changes: 52 additions & 2 deletions src/app/(dashboard)/peer/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,28 @@ import TextWithTooltip from "@components/ui/TextWithTooltip";
import { IconCloudLock, IconInfoCircle } from "@tabler/icons-react";
import useFetchApi from "@utils/api";
import dayjs from "dayjs";
import { trim } from "lodash";
import { isEmpty, trim } from "lodash";
import {
Cpu,
FlagIcon,
Globe,
History,
MapPin,
MonitorSmartphoneIcon,
NetworkIcon,
PencilIcon,
TerminalSquare,
} from "lucide-react";
import { useRouter, useSearchParams } from "next/navigation";
import { toASCII } from "punycode";
import React, { useMemo, useState } from "react";
import Skeleton from "react-loading-skeleton";
import { useSWRConfig } from "swr";
import RoundedFlag from "@/assets/countries/RoundedFlag";
import CircleIcon from "@/assets/icons/CircleIcon";
import NetBirdIcon from "@/assets/icons/NetBirdIcon";
import PeerIcon from "@/assets/icons/PeerIcon";
import { useCountries } from "@/contexts/CountryProvider";
import PeerProvider, { usePeer } from "@/contexts/PeerProvider";
import RoutesProvider from "@/contexts/RoutesProvider";
import { useHasChanges } from "@/hooks/useHasChanges";
Expand Down Expand Up @@ -139,7 +144,7 @@ function PeerOverview() {
<CircleIcon
active={peer.connected}
size={12}
className={"mb-[3px]"}
className={"mb-[3px] shrink-0"}
/>
<TextWithTooltip text={name} maxChars={30} />

Expand Down Expand Up @@ -291,6 +296,12 @@ function PeerOverview() {
}

function PeerInformationCard({ peer }: { peer: Peer }) {
const { isLoading, getRegionByPeer } = useCountries();

const countryText = useMemo(() => {
return getRegionByPeer(peer);
}, [getRegionByPeer, peer]);

return (
<Card>
<Card.List>
Expand All @@ -304,6 +315,44 @@ function PeerInformationCard({ peer }: { peer: Peer }) {
value={peer.ip}
/>

<Card.ListItem
label={
<>
<NetworkIcon size={16} />
Public IP-Address
</>
}
value={peer.connection_ip}
/>

<Card.ListItem
label={
<>
<FlagIcon size={16} />
Region
</>
}
tooltip={false}
value={
isEmpty(peer.country_code) ? (
"Unknown"
) : (
<>
{isLoading ? (
<Skeleton width={140} />
) : (
<div className={"flex gap-2 items-center"}>
<div className={"border-0 border-nb-gray-800 rounded-full"}>
<RoundedFlag country={peer.country_code} size={12} />
</div>
{countryText}
</div>
)}
</>
)
}
/>

<Card.ListItem
label={
<>
Expand Down Expand Up @@ -347,6 +396,7 @@ function PeerInformationCard({ peer }: { peer: Peer }) {
")"
}
/>

<Card.ListItem
label={
<>
Expand Down
8 changes: 7 additions & 1 deletion src/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ type CardListItemProps = {
value: React.ReactNode;
className?: string;
copy?: boolean;
tooltip?: boolean;
};

function CardListItem({
label,
value,
className,
copy = false,
tooltip = true,
}: CardListItemProps) {
const [, copyToClipBoard] = useCopyToClipboard(value as string);

Expand All @@ -57,7 +59,11 @@ function CardListItem({
copy && copyToClipBoard(`${label} has been copied to clipboard.`)
}
>
<TextWithTooltip text={value as string} maxChars={40} />
{tooltip ? (
<TextWithTooltip text={value as string} maxChars={40} />
) : (
value
)}
{copy && <Copy size={13} />}
</div>
</li>
Expand Down
8 changes: 6 additions & 2 deletions src/components/CopyToClipboardText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ export default function CopyToClipboardText({ children, message }: Props) {

{copied ? (
<CheckIcon
className={"text-nb-gray-100 opacity-0 group-hover:opacity-100"}
className={
"text-nb-gray-100 opacity-0 group-hover:opacity-100 shrink-0"
}
size={12}
/>
) : (
<CopyIcon
className={"text-nb-gray-100 opacity-0 group-hover:opacity-100"}
className={
"text-nb-gray-100 opacity-0 group-hover:opacity-100 shrink-0"
}
size={12}
/>
)}
Expand Down
1 change: 1 addition & 0 deletions src/components/FullTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export default function FullTooltip({
className={cn(
isAction ? "cursor-pointer" : "cursor-default",
"inline-flex items-center gap-2 dark:text-neutral-300 text-neutral-500 hover:text-neutral-100 transition-all hover:bg-nb-gray-800/60 py-2 px-3 rounded-md",
className,
)}
>
{children}
Expand Down
7 changes: 2 additions & 5 deletions src/components/ui/CountrySelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ import {
SelectDropdown,
SelectOption,
} from "@components/select/SelectDropdown";
import useFetchApi from "@utils/api";
import { createElement, useMemo } from "react";
import RoundedFlag from "@/assets/countries/RoundedFlag";
import { Country } from "@/interfaces/Country";
import { useCountries } from "@/contexts/CountryProvider";

type Props = {
value: string;
onChange: (value: string) => void;
};
export const CountrySelector = ({ value, onChange }: Props) => {
const { data: countries, isLoading } = useFetchApi<Country[]>(
"/locations/countries",
);
const { countries, isLoading } = useCountries();

const countryList = useMemo(() => {
return countries?.map((country) => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/GroupBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function GroupBadge({
className={cn("transition-all group whitespace-nowrap", className)}
onClick={onClick}
>
<FolderGit2 size={12} />
<FolderGit2 size={12} className={"shrink-0"} />
<TextWithTooltip text={group.name} maxChars={20} />
{children}
{showX && (
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/LoginExpiredBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function LoginExpiredBadge({ loginExpired }: Props) {
<Tooltip delayDuration={1}>
<TooltipTrigger>
<Badge variant={"red"} className={"px-3"}>
<AlertTriangle size={14} className={"mr-1"} />
<AlertTriangle size={13} className={"mr-1"} />
Login required
</Badge>
</TooltipTrigger>
Expand Down
3 changes: 2 additions & 1 deletion src/components/ui/TextWithTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ export default function TextWithTooltip({
<FullTooltip
disabled={charCount <= maxChars || hideTooltip}
interactive={false}
className={"truncate w-full"}
content={
<div className={"max-w-xs break-all whitespace-normal"}>{text}</div>
}
>
<span className={cn(className)}>
<span className={cn(className, "truncate")}>
{charCount > maxChars ? text && `${text.slice(0, maxChars)}...` : text}
</span>
</FullTooltip>
Expand Down
47 changes: 47 additions & 0 deletions src/contexts/CountryProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import useFetchApi from "@utils/api";
import React, { useCallback } from "react";
import { Country } from "@/interfaces/Country";
import { Peer } from "@/interfaces/Peer";

type Props = {
children: React.ReactNode;
};

const CountryContext = React.createContext(
{} as {
countries: Country[] | undefined;
isLoading: boolean;
getRegionByPeer: (peer: Peer) => string;
},
);

export default function CountryProvider({ children }: Props) {
const { data: countries, isLoading } = useFetchApi<Country[]>(
"/locations/countries",
false,
false,
);

const getRegionByPeer = useCallback(
(peer: Peer) => {
if (!countries) return "Unknown";
const country = countries.find(
(c) => c.country_code === peer.country_code,
);
if (!country) return "Unknown";
if (!peer.city_name) return country.country_name;
return `${country.country_name}, ${peer.city_name}`;
},
[countries],
);

return (
<CountryContext.Provider value={{ countries, isLoading, getRegionByPeer }}>
{children}
</CountryContext.Provider>
);
}

export const useCountries = () => {
return React.useContext(CountryContext);
};
3 changes: 3 additions & 0 deletions src/interfaces/Peer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ export interface Peer {
login_expired: boolean;
login_expiration_enabled: boolean;
approval_required: boolean;
city_name: string;
country_code: string;
connection_ip: string;
}
5 changes: 4 additions & 1 deletion src/layouts/DashboardLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import React from "react";
import ApplicationProvider, {
useApplicationContext,
} from "@/contexts/ApplicationProvider";
import CountryProvider from "@/contexts/CountryProvider";
import GroupsProvider from "@/contexts/GroupsProvider";
import UsersProvider from "@/contexts/UsersProvider";
import Navigation from "@/layouts/Navigation";
Expand All @@ -26,7 +27,9 @@ export default function DashboardLayout({
<ApplicationProvider>
<UsersProvider>
<GroupsProvider>
<DashboardPageContent>{children}</DashboardPageContent>
<CountryProvider>
<DashboardPageContent>{children}</DashboardPageContent>
</CountryProvider>
</GroupsProvider>
</UsersProvider>
</ApplicationProvider>
Expand Down
72 changes: 45 additions & 27 deletions src/modules/peers/PeerAddressCell.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,61 @@
import CopyToClipboardText from "@components/CopyToClipboardText";
import TextWithTooltip from "@components/ui/TextWithTooltip";
import FullTooltip from "@components/FullTooltip";
import { cn } from "@utils/helpers";
import { isEmpty } from "lodash";
import { GlobeIcon } from "lucide-react";
import React from "react";
import RoundedFlag from "@/assets/countries/RoundedFlag";
import { Peer } from "@/interfaces/Peer";
import { PeerAddressTooltipContent } from "@/modules/peers/PeerAddressTooltipContent";

type Props = {
peer: Peer;
};
export default function PeerAddressCell({ peer }: Props) {
return (
<div className={"flex gap-4 items-center min-w-[320px] max-w-[320px]"}>
<FullTooltip
side={"top"}
interactive={false}
contentClassName={"p-0"}
content={<PeerAddressTooltipContent peer={peer} />}
>
<div
className={cn(
"flex items-center justify-center rounded-md h-8 w-8 shrink-0",
peer.connected ? "bg-green-600" : "bg-nb-gray-800 opacity-50",
)}
className={
"flex gap-4 items-center min-w-[320px] max-w-[320px] group/cell transition-all hover:bg-nb-gray-800/10 py-2 px-3 rounded-md cursor-default"
}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
}}
>
<GlobeIcon size={14} className={"shrink-0"} />
</div>
<div className="flex flex-col gap-0 dark:text-neutral-300 text-neutral-500 font-light">
<CopyToClipboardText
message={"DNS label has been copied to your clipboard"}
>
<span className={"font-normal"}>
<TextWithTooltip
text={peer.dns_label}
maxChars={40}
className={"whitespace-nowrap"}
/>
</span>
</CopyToClipboardText>
<CopyToClipboardText
message={"IP address has been copied to your clipboard"}
<div
className={cn(
"flex items-center justify-center rounded-full h-8 w-8 shrink-0 bg-nb-gray-920/80 transition-all",
)}
>
<span className={"dark:text-nb-gray-400 font-mono font-thin text-xs"}>
{peer.ip}
</span>
</CopyToClipboardText>
{isEmpty(peer.country_code) ? (
<GlobeIcon size={16} className={"text-nb-gray-300"} />
) : (
<RoundedFlag country={peer.country_code} size={20} />
)}
</div>
<div className="flex flex-col gap-0 dark:text-neutral-300 text-neutral-500 font-light truncate">
<CopyToClipboardText
message={"DNS label has been copied to your clipboard"}
>
<span className={"font-normal truncate"}>{peer.dns_label}</span>
</CopyToClipboardText>
<CopyToClipboardText
message={"IP address has been copied to your clipboard"}
>
<span
className={"dark:text-nb-gray-400 font-mono font-thin text-xs"}
>
{peer.ip}
</span>
</CopyToClipboardText>
</div>
</div>
</div>
</FullTooltip>
);
}
Loading
Loading