mirror of
https://github.com/netbirdio/dashboard.git
synced 2026-01-26 01:21:04 +00:00
Add changes from cloud repo to public one (#377)
* Remove unused files * Update activity descriptions * Update SelectDropdown * Update redirect logic for / page * Update HelpText.tsx * Update wording for exit nodes
This commit is contained in:
@@ -1,9 +1,41 @@
|
||||
"use client";
|
||||
|
||||
import FullScreenLoading from "@components/ui/FullScreenLoading";
|
||||
import { useLocalStorage } from "@hooks/useLocalStorage";
|
||||
import { useRedirect } from "@hooks/useRedirect";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
type Props = {
|
||||
url: string;
|
||||
queryParams?: string;
|
||||
};
|
||||
|
||||
export default function Home() {
|
||||
useRedirect("/peers");
|
||||
return <FullScreenLoading />;
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const [tempQueryParams, setTempQueryParams] = useLocalStorage(
|
||||
"netbird-query-params",
|
||||
"",
|
||||
);
|
||||
const [queryParams, setQueryParams] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
setQueryParams(tempQueryParams);
|
||||
setTempQueryParams("");
|
||||
setMounted(true);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return mounted ? (
|
||||
<Redirect
|
||||
url={window?.location?.pathname || "/"}
|
||||
queryParams={queryParams}
|
||||
/>
|
||||
) : (
|
||||
<FullScreenLoading />
|
||||
);
|
||||
}
|
||||
|
||||
const Redirect = ({ url, queryParams }: Props) => {
|
||||
useRedirect(url == "/" ? "/peers" : url + (queryParams && `?${queryParams}`));
|
||||
return <FullScreenLoading />;
|
||||
};
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import Image from "next/image";
|
||||
import * as React from "react";
|
||||
import deIcon from "@/assets/countries/de.svg";
|
||||
|
||||
export const CountryDERounded = () => {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
"w-5 h-5 overflow-hidden rounded-full relative shadow-2xl border border-nb-gray-600 flex items-center justify-center"
|
||||
}
|
||||
>
|
||||
<Image
|
||||
src={deIcon}
|
||||
alt={"de"}
|
||||
fill={true}
|
||||
className={"object-cover object-center"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import Image from "next/image";
|
||||
import * as React from "react";
|
||||
import euIcon from "@/assets/countries/eu.svg";
|
||||
|
||||
export const CountryEURounded = () => {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
"w-5 h-5 overflow-hidden rounded-full relative shadow-2xl border border-nb-gray-600 flex items-center justify-center"
|
||||
}
|
||||
>
|
||||
<Image
|
||||
src={euIcon}
|
||||
alt={"eu"}
|
||||
fill={true}
|
||||
className={"object-cover object-center shrink-0"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import Image from "next/image";
|
||||
import * as React from "react";
|
||||
import jpIcon from "@/assets/countries/jp.svg";
|
||||
|
||||
export const CountryJPRounded = () => {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
"w-5 h-5 overflow-hidden rounded-full relative shadow-2xl border border-nb-gray-600 flex items-center justify-center"
|
||||
}
|
||||
>
|
||||
<Image
|
||||
src={jpIcon}
|
||||
alt={"eu"}
|
||||
fill={true}
|
||||
className={"object-cover object-center"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import Image from "next/image";
|
||||
import * as React from "react";
|
||||
import usIcon from "@/assets/countries/us.svg";
|
||||
|
||||
export const CountryUSRounded = () => {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
"w-5 h-5 overflow-hidden rounded-full relative shadow-2xl border border-nb-gray-600 flex items-center justify-center"
|
||||
}
|
||||
>
|
||||
<Image
|
||||
src={usIcon}
|
||||
alt={"us"}
|
||||
fill={true}
|
||||
className={"object-cover object-center"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="600" viewBox="0 0 5 3">
|
||||
<desc>Flag of Germany</desc>
|
||||
<rect id="black_stripe" width="5" height="3" y="0" x="0" fill="#000"/>
|
||||
<rect id="red_stripe" width="5" height="2" y="1" x="0" fill="#D00"/>
|
||||
<rect id="gold_stripe" width="5" height="1" y="2" x="0" fill="#FFCE00"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 493 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 810 540"><defs><g id="d"><g id="b"><path id="a" d="M0 0v1h.5z" transform="rotate(18 3.157 -.5)"/><use xlink:href="#a" transform="scale(-1 1)"/></g><g id="c"><use xlink:href="#b" transform="rotate(72)"/><use xlink:href="#b" transform="rotate(144)"/></g><use xlink:href="#c" transform="scale(-1 1)"/></g></defs><path fill="#039" d="M0 0h810v540H0z"/><g fill="#fc0" transform="matrix(30 0 0 30 405 270)"><use xlink:href="#d" y="-6"/><use xlink:href="#d" y="6"/><g id="e"><use xlink:href="#d" x="-6"/><use xlink:href="#d" transform="rotate(-144 -2.344 -2.11)"/><use xlink:href="#d" transform="rotate(144 -2.11 -2.344)"/><use xlink:href="#d" transform="rotate(72 -4.663 -2.076)"/><use xlink:href="#d" transform="rotate(72 -5.076 .534)"/></g><use xlink:href="#e" transform="scale(-1 1)"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 888 B |
@@ -1,4 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 600">
|
||||
<rect fill="#fff" height="600" width="900"/>
|
||||
<circle fill="#bc002d" cx="450" cy="300" r="180"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 166 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 7410 3900"><path fill="#b22234" d="M0 0h7410v3900H0z"/><path d="M0 450h7410m0 600H0m0 600h7410m0 600H0m0 600h7410m0 600H0" stroke="#fff" stroke-width="300"/><path fill="#3c3b6e" d="M0 0h2964v2100H0z"/><g fill="#fff"><g id="d"><g id="c"><g id="e"><g id="b"><path id="a" d="M247 90l70.534 217.082-184.66-134.164h228.253L176.466 307.082z"/><use xlink:href="#a" y="420"/><use xlink:href="#a" y="840"/><use xlink:href="#a" y="1260"/></g><use xlink:href="#a" y="1680"/></g><use xlink:href="#b" x="247" y="210"/></g><use xlink:href="#c" x="494"/></g><use xlink:href="#d" x="988"/><use xlink:href="#c" x="1976"/><use xlink:href="#e" x="2470"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 741 B |
@@ -2,7 +2,7 @@ import { useOidc, useOidcUser } from "@axa-fr/react-oidc";
|
||||
import Button from "@components/Button";
|
||||
import Paragraph from "@components/Paragraph";
|
||||
import loadConfig from "@utils/config";
|
||||
import { ArrowRightIcon, LogOut } from "lucide-react";
|
||||
import { ArrowRightIcon } from "lucide-react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import * as React from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
@@ -55,7 +55,7 @@ export const OIDCError = () => {
|
||||
variant={"primary"}
|
||||
size={"sm"}
|
||||
className={"mt-5"}
|
||||
onClick={() => login("/", { client_id: config.clientId })}
|
||||
onClick={() => logout("/", { client_id: config.clientId })}
|
||||
>
|
||||
Continue
|
||||
<ArrowRightIcon size={16} />
|
||||
@@ -83,7 +83,6 @@ export const OIDCError = () => {
|
||||
onClick={() => logout("/", { client_id: config.clientId })}
|
||||
>
|
||||
Logout
|
||||
<LogOut size={16} />
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
OidcConfiguration,
|
||||
} from "@axa-fr/react-oidc/dist/vanilla/oidc";
|
||||
import FullScreenLoading from "@components/ui/FullScreenLoading";
|
||||
import { useLocalStorage } from "@hooks/useLocalStorage";
|
||||
import { useRedirect } from "@hooks/useRedirect";
|
||||
import loadConfig, { buildExtras } from "@utils/config";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
@@ -43,6 +44,19 @@ export default function OIDCProvider({ children }: Props) {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
const router = useRouter();
|
||||
const path = usePathname();
|
||||
const params = useSearchParams()?.toString();
|
||||
const [, setQueryParams] = useLocalStorage("netbird-query-params", params);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
params?.includes("tab") ||
|
||||
params?.includes("search") ||
|
||||
params?.includes("id")
|
||||
) {
|
||||
setQueryParams(params);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const withCustomHistory = () => {
|
||||
return {
|
||||
|
||||
@@ -12,14 +12,14 @@ export default function HelpText({
|
||||
className,
|
||||
}: Props) {
|
||||
return (
|
||||
<p
|
||||
<span
|
||||
className={cn(
|
||||
"text-[.8rem] dark:text-nb-gray-300",
|
||||
"text-[.8rem] dark:text-nb-gray-300 block font-light tracking-wide",
|
||||
margin && "mb-2",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Button from "@components/Button";
|
||||
import { CommandItem } from "@components/Command";
|
||||
import Paragraph from "@components/Paragraph";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@components/Popover";
|
||||
import { ScrollArea } from "@components/ScrollArea";
|
||||
import { SelectDropdownSearchInput } from "@components/select/SelectDropdownSearchInput";
|
||||
@@ -31,6 +32,7 @@ interface SelectDropdownProps {
|
||||
popoverWidth?: "auto" | number;
|
||||
options: SelectOption[];
|
||||
showSearch?: boolean;
|
||||
showValues?: boolean;
|
||||
placeholder?: string;
|
||||
searchPlaceholder?: string;
|
||||
isLoading?: boolean;
|
||||
@@ -43,6 +45,7 @@ export function SelectDropdown({
|
||||
popoverWidth = "auto",
|
||||
options,
|
||||
showSearch = false,
|
||||
showValues = false,
|
||||
placeholder = "Select...",
|
||||
searchPlaceholder = "Search...",
|
||||
isLoading = false,
|
||||
@@ -186,6 +189,7 @@ export function SelectDropdown({
|
||||
option={option}
|
||||
toggle={toggle}
|
||||
key={option.value}
|
||||
showValue={showValues}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -201,9 +205,11 @@ export function SelectDropdown({
|
||||
const SelectDropdownItem = ({
|
||||
option,
|
||||
toggle,
|
||||
showValue = false,
|
||||
}: {
|
||||
option: SelectOption;
|
||||
toggle: (value: string) => void;
|
||||
showValue?: boolean;
|
||||
}) => {
|
||||
const value = option.value || "" + option.label || "";
|
||||
const elementRef = useRef<HTMLDivElement>(null);
|
||||
@@ -233,6 +239,13 @@ const SelectDropdownItem = ({
|
||||
<span className={"text-nb-gray-200"}>{option.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
{showValue && (
|
||||
<div className={"flex items-center gap-2.5 p-1"}>
|
||||
<Paragraph className={cn("text-sm text-right")}>
|
||||
{option.value}
|
||||
</Paragraph>
|
||||
</div>
|
||||
)}
|
||||
</CommandItem>
|
||||
) : (
|
||||
<div className={"h-[35px] py-1 px-2"}></div>
|
||||
|
||||
@@ -477,15 +477,46 @@ export default function ActivityDescription({ event }: Props) {
|
||||
</div>
|
||||
);
|
||||
|
||||
// TODO add activity texts
|
||||
// rule.add
|
||||
// rule.update
|
||||
// rule.delete
|
||||
// setupkey.update
|
||||
// setupkey.overuse
|
||||
// group.update
|
||||
// group.delete
|
||||
// user.peer.login
|
||||
if (event.activity_code == "transferred.owner.role")
|
||||
return <div className={"inline"}>Owner role was transferred</div>;
|
||||
|
||||
/**
|
||||
* EDR
|
||||
*/
|
||||
if (event.activity_code == "integrated-validator.api.created")
|
||||
return (
|
||||
<div className={"inline"}>
|
||||
<Value>{m?.platform}</Value> integration created
|
||||
</div>
|
||||
);
|
||||
|
||||
if (event.activity_code == "integrated-validator.api.updated")
|
||||
return (
|
||||
<div className={"inline"}>
|
||||
<Value>{m?.platform}</Value> integration updated
|
||||
</div>
|
||||
);
|
||||
|
||||
if (event.activity_code == "integrated-validator.api.deleted")
|
||||
return (
|
||||
<div className={"inline"}>
|
||||
<Value>{m?.platform}</Value> integration deleted
|
||||
</div>
|
||||
);
|
||||
|
||||
if (event.activity_code == "integrated-validator.host-check.approved")
|
||||
return (
|
||||
<div className={"inline"}>
|
||||
Peer approved by <Value>{m?.platform}</Value> integration
|
||||
</div>
|
||||
);
|
||||
|
||||
if (event.activity_code == "integrated-validator.host-check.denied")
|
||||
return (
|
||||
<div className={"inline"}>
|
||||
Peer rejected by <Value>{m?.platform}</Value> integration
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={"flex gap-2.5 items-center"}>
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
ArrowLeftRight,
|
||||
Blocks,
|
||||
Cog,
|
||||
CreditCardIcon,
|
||||
FolderGit2,
|
||||
Globe,
|
||||
HelpCircleIcon,
|
||||
@@ -10,6 +11,7 @@ import {
|
||||
LogIn,
|
||||
MonitorSmartphoneIcon,
|
||||
NetworkIcon,
|
||||
RefreshCcw,
|
||||
Server,
|
||||
Shield,
|
||||
ShieldCheck,
|
||||
@@ -71,10 +73,22 @@ export default function ActivityTypeIcon({
|
||||
return <User size={size} className={cn(DEFAULT_CLASSES, className)} />;
|
||||
} else if (code.startsWith("service")) {
|
||||
return <Cog size={size} className={cn(DEFAULT_CLASSES, className)} />;
|
||||
} else if (code.startsWith("billing")) {
|
||||
return (
|
||||
<CreditCardIcon size={size} className={cn(DEFAULT_CLASSES, className)} />
|
||||
);
|
||||
} else if (code.startsWith("integrated")) {
|
||||
return (
|
||||
<ShieldCheck size={size} className={cn(DEFAULT_CLASSES, className)} />
|
||||
);
|
||||
} else if (code.startsWith("posture")) {
|
||||
return (
|
||||
<ShieldCheck size={size} className={cn(DEFAULT_CLASSES, className)} />
|
||||
);
|
||||
} else if (code.startsWith("transferred")) {
|
||||
return (
|
||||
<RefreshCcw size={size} className={cn(DEFAULT_CLASSES, className)} />
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<HelpCircleIcon size={size} className={cn(DEFAULT_CLASSES, className)} />
|
||||
|
||||
@@ -12,30 +12,36 @@ export const ExitNodeHelpTooltip = ({
|
||||
hoverButton = false,
|
||||
}: Props) => {
|
||||
return (
|
||||
<FullTooltip
|
||||
hoverButton={hoverButton}
|
||||
content={
|
||||
<div className={"text-xs max-w-xs"}>
|
||||
An exit node is a network route that routes all your internet traffic
|
||||
through one of your peers.
|
||||
<div className={"mt-2"}>
|
||||
Learn more about{" "}
|
||||
<InlineLink
|
||||
href={
|
||||
"https://docs.netbird.io/how-to/configuring-default-routes-for-internet-traffic"
|
||||
}
|
||||
target={"_blank"}
|
||||
className={"mr-1"}
|
||||
>
|
||||
Exit Nodes
|
||||
<ExternalLinkIcon size={10} />
|
||||
</InlineLink>
|
||||
in our documentation.
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</FullTooltip>
|
||||
<FullTooltip
|
||||
hoverButton={hoverButton}
|
||||
content={
|
||||
<div className={"text-xs max-w-xs"}>
|
||||
An exit node is a network route that routes all your internet
|
||||
traffic through one of your peers.
|
||||
<div className={"mt-2"}>
|
||||
Learn more about{" "}
|
||||
<InlineLink
|
||||
href={
|
||||
"https://docs.netbird.io/how-to/configuring-default-routes-for-internet-traffic"
|
||||
}
|
||||
target={"_blank"}
|
||||
className={"mr-1"}
|
||||
>
|
||||
Exit Nodes
|
||||
<ExternalLinkIcon size={10} />
|
||||
</InlineLink>
|
||||
in our documentation.
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</FullTooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ export const ExitNodePeerIndicator = ({ peer }: Props) => {
|
||||
<FullTooltip
|
||||
content={
|
||||
<div className={"text-xs max-w-xs"}>
|
||||
This peer has an exit node. Traffic from the configured distribution
|
||||
This peer is an exit node. Traffic from the configured distribution
|
||||
groups will be routed through this peer.
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ import { cn } from "@utils/helpers";
|
||||
import Image from "next/image";
|
||||
import * as React from "react";
|
||||
import { FaWindows } from "react-icons/fa6";
|
||||
import { CountryDERounded } from "@/assets/countries/CountryDERounded";
|
||||
import { CountryUSRounded } from "@/assets/countries/CountryUSRounded";
|
||||
import RoundedFlag from "@/assets/countries/RoundedFlag";
|
||||
import NetBirdIcon from "@/assets/icons/NetBirdIcon";
|
||||
import AppleLogo from "@/assets/os-icons/apple.svg";
|
||||
|
||||
@@ -24,7 +23,7 @@ export const PostureCheckIcons = () => {
|
||||
"h-6 w-6 overflow-hidden rounded-full flex items-center justify-center"
|
||||
}
|
||||
>
|
||||
<CountryDERounded />
|
||||
<RoundedFlag country="de" />
|
||||
</div>
|
||||
</Circle>
|
||||
<Circle className={"z-[3]"}>
|
||||
@@ -36,7 +35,7 @@ export const PostureCheckIcons = () => {
|
||||
"h-6 w-6 overflow-hidden rounded-full flex items-center justify-center"
|
||||
}
|
||||
>
|
||||
<CountryUSRounded />
|
||||
<RoundedFlag country="us" />
|
||||
</div>
|
||||
</Circle>
|
||||
<Circle className={"z-[1] top-2 "}>
|
||||
|
||||
@@ -317,7 +317,7 @@ export function RouteModalContent({
|
||||
<div>
|
||||
<HelpText>
|
||||
Assign a single peer as a routing peer for the
|
||||
{exitNode ? " Exit Node" : " Network CIDR"}
|
||||
{exitNode ? " exit node." : " Network CIDR."}
|
||||
</HelpText>
|
||||
<PeerSelector
|
||||
onChange={setRoutingPeer}
|
||||
@@ -329,8 +329,8 @@ export function RouteModalContent({
|
||||
<SegmentedTabs.Content value={"peer-group"}>
|
||||
<div>
|
||||
<HelpText>
|
||||
Assign peer group with Linux machines to be used as
|
||||
routing peers.
|
||||
Assign a peer group with Linux machines to be used as
|
||||
{exitNode ? " exit nodes." : "routing peers."}
|
||||
</HelpText>
|
||||
<PeerGroupSelector
|
||||
max={1}
|
||||
|
||||
Reference in New Issue
Block a user