Update NextJS to 16.1.6 (#547)
Some checks failed
build and push / build_n_push (push) Has been cancelled

* Update NextJS to 16.1.6

* Update Node in workflow

* Fix rabbit comments

* Fix types

* Add engines field
This commit is contained in:
Eduard Gert
2026-02-02 15:34:23 +01:00
committed by GitHub
parent ea148545e8
commit 750f660bcc
25 changed files with 2430 additions and 2645 deletions

View File

@@ -19,7 +19,7 @@ jobs:
- name: setup-node - name: setup-node
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: '18' node-version: '20'
cache: 'npm' cache: 'npm'
- name: Install dependencies - name: Install dependencies

4401
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,9 @@
"name": "netbird-dashboard", "name": "netbird-dashboard",
"version": "2.0.0", "version": "2.0.0",
"private": true, "private": true,
"engines": {
"node": ">=20.9.0"
},
"scripts": { "scripts": {
"copy": "copyfiles -f ./node_modules/@axa-fr/react-oidc/dist/OidcServiceWorker.js ./public", "copy": "copyfiles -f ./node_modules/@axa-fr/react-oidc/dist/OidcServiceWorker.js ./public",
"copytrusted": "copyfiles -f ./public/local/OidcTrustedDomains.js ./public", "copytrusted": "copyfiles -f ./public/local/OidcTrustedDomains.js ./public",
@@ -13,34 +16,34 @@
"cypress:open": "cypress open" "cypress:open": "cypress open"
}, },
"dependencies": { "dependencies": {
"@axa-fr/react-oidc": "^7.22.18", "@axa-fr/react-oidc": "^7.26.3",
"@dagrejs/dagre": "^1.1.5", "@dagrejs/dagre": "^1.1.5",
"@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-hover-card": "^1.1.4", "@radix-ui/react-hover-card": "^1.1.15",
"@radix-ui/react-label": "^2.0.2", "@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-popover": "^1.1.15",
"@radix-ui/react-radio-group": "^1.1.3", "@radix-ui/react-radio-group": "^1.3.8",
"@radix-ui/react-scroll-area": "^1.1.0", "@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "^2.0.0", "@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-slider": "^1.3.6",
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-toast": "^1.2.15",
"@radix-ui/react-tooltip": "^1.0.7", "@radix-ui/react-tooltip": "^1.2.8",
"@tabler/icons-react": "^2.39.0", "@tabler/icons-react": "^3.36.1",
"@tanstack/match-sorter-utils": "^8.8.4", "@tanstack/match-sorter-utils": "^8.8.4",
"@tanstack/react-table": "^8.10.7", "@tanstack/react-table": "^8.10.7",
"@types/crypto-js": "^4.2.2", "@types/crypto-js": "^4.2.2",
"@types/d3": "^7.4.3", "@types/d3": "^7.4.3",
"@types/lodash": "^4.14.200", "@types/lodash": "^4.14.200",
"@types/node": "20.10.6", "@types/node": "20.10.6",
"@types/react": "^18", "@types/react": "^19",
"@types/react-dom": "^18", "@types/react-dom": "^19",
"@types/react-window": "^1.8.8", "@types/react-window": "^1.8.8",
"@xterm/addon-fit": "^0.10.0", "@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0", "@xterm/xterm": "^5.5.0",
@@ -49,8 +52,9 @@
"chart.js": "^4.4.8", "chart.js": "^4.4.8",
"chroma-js": "^3.1.2", "chroma-js": "^3.1.2",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"classnames": "^2.5.1",
"clsx": "^2.0.0", "clsx": "^2.0.0",
"cmdk": "^0.2.0", "cmdk": "^1.1.1",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"d3": "^7.9.0", "d3": "^7.9.0",
"date-fns": "^2.30.0", "date-fns": "^2.30.0",
@@ -58,24 +62,23 @@
"elkjs": "^0.10.0", "elkjs": "^0.10.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-simple-import-sort": "^10.0.0",
"flowbite": "^1.8.1", "framer-motion": "^12.29.2",
"flowbite-react": "^0.6.4",
"framer-motion": "^10.16.4",
"ip-address": "^10.1.0", "ip-address": "^10.1.0",
"ip-cidr": "^3.1.0", "ip-cidr": "^3.1.0",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lodash": "^4.17.23", "lodash": "^4.17.23",
"lucide-react": "^0.539.0", "lucide-react": "^0.539.0",
"next": "^14.2.35", "next": "^16.1.6",
"next-themes": "^0.2.1", "next-themes": "^0.2.1",
"punycode": "^2.3.1", "punycode": "^2.3.1",
"react": "^18.3.1", "react": "^19.2.4",
"react-day-picker": "^8.9.1", "react-day-picker": "^9.13.0",
"react-dom": "^18.3.1", "react-dom": "^19.2.4",
"react-ga4": "^2.1.0", "react-ga4": "^2.1.0",
"react-hot-toast": "^2.4.1", "react-hot-toast": "^2.4.1",
"react-hotjar": "^6.2.0", "react-hotjar": "^6.3.1",
"react-hotkeys-hook": "^4.4.1", "react-hotkeys-hook": "^4.4.1",
"react-icons": "^5.5.0",
"react-jwt": "^1.2.0", "react-jwt": "^1.2.0",
"react-loading-skeleton": "^3.3.1", "react-loading-skeleton": "^3.3.1",
"react-responsive": "^9.0.2", "react-responsive": "^9.0.2",
@@ -91,7 +94,7 @@
"@types/chroma-js": "^3.1.1", "@types/chroma-js": "^3.1.1",
"@types/js-cookie": "^3.0.6", "@types/js-cookie": "^3.0.6",
"eslint": "^9.39.1", "eslint": "^9.39.1",
"eslint-config-next": "^16.0.5", "eslint-config-next": "^16.1.6",
"postcss": "^8", "postcss": "^8",
"prettier": "3.0.3", "prettier": "3.0.3",
"tailwindcss": "^3.4.17" "tailwindcss": "^3.4.17"

View File

@@ -2,7 +2,9 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
html{
@apply bg-nb-gray;
}
h1 { h1 {
@apply text-2xl font-medium text-gray-700 dark:text-nb-gray-100 my-1; @apply text-2xl font-medium text-gray-700 dark:text-nb-gray-100 my-1;

View File

@@ -1,90 +0,0 @@
import { Checkbox } from "@components/Checkbox";
import { Input } from "@components/Input";
import { Popover, PopoverContent } from "@components/Popover";
import { useElementSize } from "@hooks/useElementSize";
import { Anchor } from "@radix-ui/react-popover";
import * as React from "react";
import { useEffect, useRef, useState } from "react";
import { FaWindows } from "react-icons/fa6";
type Props = {};
export const AutoCompleteInput = ({}: Props) => {
const [open, setOpen] = useState<boolean>(false);
const inputRef = useRef<HTMLInputElement>(null);
const [elementWidth, { width }] = useElementSize<HTMLDivElement>();
useEffect(() => {
const input = inputRef.current;
const onFocus = () => {
setOpen(true);
};
if (input) {
inputRef.current.addEventListener("focus", onFocus);
}
return () => {
if (input) {
inputRef.current.removeEventListener("focus", onFocus);
}
};
}, []);
return (
<div className={"z-10 relative"}>
<Popover modal={false} open={open} onOpenChange={setOpen}>
<Anchor ref={elementWidth}>
<Input
placeholder={"11"}
ref={inputRef}
maxWidthClass={"max-w-[200px]"}
customPrefix={
<div className={"flex items-center gap-2"}>
<Checkbox></Checkbox>
<div
className={"flex gap-2 items-center text-sm text-nb-gray-200"}
>
<FaWindows className={"text-sky-600 text-lg"} />
Windows
</div>
</div>
}
/>
</Anchor>
<PopoverContent
hideWhenDetached={false}
className="w-full p-0 shadow-sm shadow-nb-gray-950"
style={{
width: width,
}}
forceMount={true}
align="start"
side={"bottom"}
sideOffset={10}
onOpenAutoFocus={(event) => event.preventDefault()}
onCloseAutoFocus={(event) => event.preventDefault()}
onInteractOutside={(event) => {
event.preventDefault();
if (event.target !== inputRef.current) {
setOpen(false);
}
}}
onPointerDownOutside={(event) => {
event.preventDefault();
if (event.target !== inputRef.current) {
setOpen(false);
}
}}
onFocusOutside={(event) => {
event.preventDefault();
if (event.target !== inputRef.current) {
setOpen(false);
}
}}
></PopoverContent>
</Popover>
</div>
);
};

View File

@@ -53,13 +53,10 @@ const TooltipContent = React.forwardRef<
<TooltipPrimitive.Portal> <TooltipPrimitive.Portal>
<TooltipPrimitive.Content <TooltipPrimitive.Content
ref={ref} ref={ref}
asChild={true}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn(tooltipVariants({ variant }), className)} className={cn(tooltipVariants({ variant }), className)}
{...props} {...props}
> />
<div>{props.children}</div>
</TooltipPrimitive.Content>
</TooltipPrimitive.Portal> </TooltipPrimitive.Portal>
), ),
); );

View File

@@ -1,12 +1,25 @@
import { import {
MemoizedScrollArea, MemoizedScrollArea,
MemoizedScrollAreaViewport, ScrollAreaViewport,
} from "@components/ScrollArea"; } from "@components/ScrollArea";
import { cn } from "@utils/helpers"; import { cn } from "@utils/helpers";
import * as React from "react"; import * as React from "react";
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; import {
forwardRef,
memo,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { Virtuoso, VirtuosoHandle } from "react-virtuoso"; import { Virtuoso, VirtuosoHandle } from "react-virtuoso";
const VirtuosoScroller = forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>((props, ref) => <ScrollAreaViewport ref={ref} {...props} />);
type Props<T extends { id?: string }> = { type Props<T extends { id?: string }> = {
items: T[]; items: T[];
onSelect: (item: T) => void; onSelect: (item: T) => void;
@@ -183,7 +196,7 @@ export function VirtualScrollAreaList<T extends { id?: string }>({
}} }}
style={virtuosoHeight} style={virtuosoHeight}
components={{ components={{
Scroller: MemoizedScrollAreaViewport, Scroller: VirtuosoScroller,
}} }}
/> />
</MemoizedScrollArea> </MemoizedScrollArea>

View File

@@ -2,6 +2,7 @@
import * as DialogPrimitive from "@radix-ui/react-dialog"; import * as DialogPrimitive from "@radix-ui/react-dialog";
import { DialogTriggerProps } from "@radix-ui/react-dialog"; import { DialogTriggerProps } from "@radix-ui/react-dialog";
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
import { cn } from "@utils/helpers"; import { cn } from "@utils/helpers";
import { X } from "lucide-react"; import { X } from "lucide-react";
import * as React from "react"; import * as React from "react";
@@ -74,18 +75,19 @@ const ModalContent = React.forwardRef<
{...props} {...props}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<> <VisuallyHidden asChild>
{children} <DialogPrimitive.Title>Dialog</DialogPrimitive.Title>
{showClose && ( </VisuallyHidden>
<DialogPrimitive.Close {children}
data-cy={"modal-close"} {showClose && (
className="absolute right-4 z-10 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-neutral-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 dark:ring-offset-neutral-950 dark:focus:ring-neutral-300 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-400" <DialogPrimitive.Close
> data-cy={"modal-close"}
<X className="h-4 w-4" /> className="absolute right-4 z-10 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-neutral-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 dark:ring-offset-neutral-950 dark:focus:ring-neutral-300 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-400"
<span className="sr-only">Close</span> >
</DialogPrimitive.Close> <X className="h-4 w-4" />
)} <span className="sr-only">Close</span>
</> </DialogPrimitive.Close>
)}
</DialogPrimitive.Content> </DialogPrimitive.Content>
</ModalOverlay> </ModalOverlay>
</ModalPortal> </ModalPortal>
@@ -129,18 +131,19 @@ const SidebarModalContent = React.forwardRef<
}} }}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<> <VisuallyHidden asChild>
{children} <DialogPrimitive.Title>Dialog</DialogPrimitive.Title>
{showClose && ( </VisuallyHidden>
<DialogPrimitive.Close {children}
data-cy={"modal-close"} {showClose && (
className="absolute right-4 z-10 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-neutral-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 dark:ring-offset-neutral-950 dark:focus:ring-neutral-300 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-400" <DialogPrimitive.Close
> data-cy={"modal-close"}
<X className="h-4 w-4" /> className="absolute right-4 z-10 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-neutral-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 dark:ring-offset-neutral-950 dark:focus:ring-neutral-300 dark:data-[state=open]:bg-neutral-800 dark:data-[state=open]:text-neutral-400"
<span className="sr-only">Close</span> >
</DialogPrimitive.Close> <X className="h-4 w-4" />
)} <span className="sr-only">Close</span>
</> </DialogPrimitive.Close>
)}
</DialogPrimitive.Content> </DialogPrimitive.Content>
</div> </div>
</ModalPortal> </ModalPortal>

View File

@@ -14,11 +14,6 @@ import {
TableWrapper, TableWrapper,
} from "@components/table/Table"; } from "@components/table/Table";
import NoResults from "@components/ui/NoResults"; import NoResults from "@components/ui/NoResults";
import {
Accordion,
AccordionContent,
AccordionItem,
} from "@radix-ui/react-accordion";
import { RankingInfo } from "@tanstack/match-sorter-utils"; import { RankingInfo } from "@tanstack/match-sorter-utils";
import { import {
ColumnDef, ColumnDef,
@@ -493,117 +488,97 @@ export function DataTable<TData, TValue>({
</TableHeaderComponent> </TableHeaderComponent>
)} )}
<Accordion <TableBodyComponent
asChild={true} className={cn(
type={"multiple"} "relative",
value={accordion} data == undefined && "blur-sm",
onValueChange={setAccordion} wrapperClassName,
)}
> >
<TableBodyComponent {table.getRowModel().rows?.length ? (
className={cn( table.getRowModel().rows.map((row) => {
"relative", const expandedRow = renderExpandedRow?.(row.original);
data == undefined && "blur-sm", const rowId = row.original.id ?? row.id;
wrapperClassName, const isExpanded = accordion?.includes(rowId);
)} const rowContent = (
> <React.Fragment key={row.id}>
{table.getRowModel().rows?.length ? ( <TableRowComponent
table.getRowModel().rows.map((row) => { minimal={minimal}
const expandedRow = renderExpandedRow?.(row.original); data-row-id={rowId}
const rowContent = ( className={cn(
<AccordionItem (onRowClick || renderExpandedRow) &&
value={row.original.id} "relative group/accordion",
asChild={true} (onRowClick || expandedRow) && "cursor-pointer",
key={row.id} rowClassName,
> )}
<> data-state={row.getIsSelected() && "selected"}
<TableRowComponent data-accordion={isExpanded ? "opened" : "closed"}
minimal={minimal} onClick={(e) => {
data-row-id={row.original.id} if (expandedRow) {
className={cn( e.preventDefault();
(onRowClick || renderExpandedRow) && e.stopPropagation();
"relative group/accordion", setAccordion((prev) => {
(onRowClick || expandedRow) && "cursor-pointer", if (prev?.includes(rowId)) {
rowClassName, return prev.filter(
)} (item) => item !== rowId,
data-state={row.getIsSelected() && "selected"} );
data-accordion={ } else {
accordion?.includes(row.original.id) return [...(prev ?? []), rowId];
? "opened"
: "closed"
}
onClick={(e) => {
if (expandedRow) {
e.preventDefault();
e.stopPropagation();
setAccordion((prev) => {
if (prev?.includes(row.original.id)) {
return prev.filter(
(item) => item !== row.original.id,
);
} else {
return [...(prev ?? []), row.original.id];
}
});
} }
});
}
}}
>
{row.getVisibleCells().map((cell) => (
<TableCellComponent
key={cell.id}
className={cn("relative", tableCellClassName)}
minimal={minimal}
inset={inset}
onClick={() => {
onRowClick && onRowClick(row, cell.column.id);
}} }}
> >
<> <div
{row.getVisibleCells().map((cell) => ( className={
<TableCellComponent "absolute left-0 top-0 w-full h-full z-0"
key={cell.id} }
className={cn("relative", tableCellClassName)} ></div>
minimal={minimal} <div className={"relative z-[1]"}>
inset={inset} {flexRender(
onClick={() => { cell.column.columnDef.cell,
onRowClick && cell.getContext(),
onRowClick(row, cell.column.id); )}
}} </div>
> </TableCellComponent>
<div ))}
className={ </TableRowComponent>
"absolute left-0 top-0 w-full h-full z-0"
}
></div>
<div className={"relative z-[1]"}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</div>
</TableCellComponent>
))}
</>
</TableRowComponent>
{expandedRow && ( {expandedRow && isExpanded && (
<AccordionContent asChild={true}> <TableRowComponent
<TableRowComponent data-row-id={row.id + "-expanded-row"}
data-row-id={row.id + "-expanded-row"} minimal={minimal}
key={row.id + "-expanded-row"} className={cn(
minimal={minimal} onRowClick && "cursor-pointer relative",
className={cn( rowClassName,
onRowClick && "cursor-pointer relative",
rowClassName,
)}
data-state={row.getIsSelected() && "selected"}
>
<TableDataUnstyledComponent
className={"w-full"}
colSpan={row.getVisibleCells().length}
>
{expandedRow}
</TableDataUnstyledComponent>
</TableRowComponent>
</AccordionContent>
)} )}
</> data-state={row.getIsSelected() && "selected"}
</AccordionItem> >
); <TableDataUnstyledComponent
className={"w-full"}
colSpan={row.getVisibleCells().length}
>
{expandedRow}
</TableDataUnstyledComponent>
</TableRowComponent>
)}
</React.Fragment>
);
return renderRow return renderRow
? renderRow(row.original, rowContent) ? renderRow(row.original, rowContent)
: rowContent; : rowContent;
}) })
) : ( ) : (
<TableRowUnstyledComponent> <TableRowUnstyledComponent>
<TableCellComponent <TableCellComponent
@@ -614,8 +589,7 @@ export function DataTable<TData, TValue>({
</TableCellComponent> </TableCellComponent>
</TableRowUnstyledComponent> </TableRowUnstyledComponent>
)} )}
</TableBodyComponent> </TableBodyComponent>
</Accordion>
</TableComponent> </TableComponent>
)} )}
</TableWrapper> </TableWrapper>

View File

@@ -64,8 +64,16 @@ const Time = ({
} }
}, [value]); }, [value]);
const { ref, ...rootProps } = getRootProps();
return ( return (
<div className={"timescape w-full"} {...getRootProps()}> <div
className={"timescape w-full"}
ref={(element) => {
ref(element);
}}
{...rootProps}
>
<div> <div>
<input {...getInputProps("years")} /> <input {...getInputProps("years")} />
<span className={"separator"}>/</span> <span className={"separator"}>/</span>

View File

@@ -19,40 +19,46 @@ function Calendar({
showOutsideDays={showOutsideDays} showOutsideDays={showOutsideDays}
className={cn("p-3", className)} className={cn("p-3", className)}
classNames={{ classNames={{
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0", months: "flex flex-col sm:flex-row space-y-4 sm:space-y-0 relative",
month: "space-y-4", month: "space-y-4 pr-4 last:pr-0",
caption: "flex justify-center pt-1 relative items-center", month_caption: "flex justify-center pt-1 relative items-center",
caption_label: "text-sm font-medium", caption_label: "text-sm font-medium",
nav: "space-x-1 flex items-center", nav: "space-x-1 flex items-center",
nav_button: cn( button_previous: cn(
buttonVariants({ variant: "outline" }), buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100", "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 absolute left-0 top-0 z-10",
), ),
nav_button_previous: "absolute left-1", button_next: cn(
nav_button_next: "absolute right-1", buttonVariants({ variant: "outline" }),
table: "w-full border-collapse space-y-1", "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 absolute right-0 top-0 z-10",
head_row: "flex", ),
head_cell: month_grid: "w-full border-collapse space-y-1",
weekdays: "flex",
weekday:
"text-neutral-500 rounded-md w-9 font-normal text-[0.8rem] dark:text-neutral-400", "text-neutral-500 rounded-md w-9 font-normal text-[0.8rem] dark:text-neutral-400",
row: "flex w-full mt-2", week: "flex w-full mt-2",
cell: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-neutral-100/50 [&:has([aria-selected])]:bg-neutral-100 first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20 dark:[&:has([aria-selected].day-outside)]:bg-neutral-800/50 dark:[&:has([aria-selected])]:bg-neutral-800", day: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-neutral-100/50 [&:has([aria-selected])]:bg-neutral-100 first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20 dark:[&:has([aria-selected].day-outside)]:bg-neutral-800/50 dark:[&:has([aria-selected])]:bg-neutral-800",
day: cn("h-9 w-9 p-0 font-normal aria-selected:opacity-100"), day_button: cn("h-9 w-9 p-0 font-normal aria-selected:opacity-100"),
day_range_end: "day-range-end rounded-r-md", range_end: "day-range-end rounded-r-md",
day_range_start: "day-range-start rounded-l-md", range_start: "day-range-start rounded-l-md",
day_selected: selected:
"bg-neutral-900 text-neutral-50 hover:bg-neutral-900 hover:text-neutral-50 focus:bg-neutral-900 focus:text-neutral-50 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50 dark:hover:text-neutral-900 dark:focus:bg-neutral-50 dark:focus:text-neutral-900", "bg-neutral-900 text-neutral-50 hover:bg-neutral-900 hover:text-neutral-50 focus:bg-neutral-900 focus:text-neutral-50 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50 dark:hover:text-neutral-900 dark:focus:bg-neutral-50 dark:focus:text-neutral-900",
day_today: "text-neutral-900 dark:text-red-500", today: "text-neutral-900 dark:text-red-500",
day_outside: outside:
"day-outside text-neutral-500 opacity-50 aria-selected:bg-neutral-100/50 aria-selected:text-neutral-500 aria-selected:opacity-30 dark:text-neutral-400 dark:aria-selected:bg-neutral-800/50 dark:aria-selected:text-neutral-400", "day-outside text-neutral-500 opacity-50 aria-selected:bg-neutral-100/50 aria-selected:text-neutral-500 aria-selected:opacity-30 dark:text-neutral-400 dark:aria-selected:bg-neutral-800/50 dark:aria-selected:text-neutral-400",
day_disabled: "text-neutral-500 opacity-50 dark:text-neutral-400", disabled: "text-neutral-500 opacity-50 dark:text-neutral-400",
day_range_middle: range_middle:
"aria-selected:bg-neutral-100 aria-selected:text-neutral-900 dark:aria-selected:bg-nb-gray-800 dark:aria-selected:text-neutral-50 rounded-none", "aria-selected:bg-neutral-100 aria-selected:text-neutral-900 dark:aria-selected:bg-nb-gray-800 dark:aria-selected:text-neutral-50 rounded-none",
day_hidden: "invisible", hidden: "invisible",
...classNames, ...classNames,
}} }}
components={{ components={{
IconLeft: () => <ChevronLeft className="h-4 w-4" />, Chevron: ({ orientation }) =>
IconRight: () => <ChevronRight className="h-4 w-4" />, orientation === "left" ? (
<ChevronLeft className="h-4 w-4" />
) : (
<ChevronRight className="h-4 w-4" />
),
}} }}
{...props} {...props}
/> />

View File

@@ -56,7 +56,7 @@ export default function AnalyticsProvider({ children }: Readonly<Props>) {
}); });
} }
if (hjid && window._DATADOG_SYNTHETICS_BROWSER === undefined) { if (hjid && window._DATADOG_SYNTHETICS_BROWSER === undefined) {
hotjar.initialize(hjid, 6); hotjar.initialize({ id: hjid, sv: 6 });
} }
setInitialized(true); setInitialized(true);
}, []); }, []);

View File

@@ -34,7 +34,7 @@ export default function DialogProvider({ children }: Props) {
isOpen: false, isOpen: false,
}); });
const [dialogOptions, setDialogOptions] = useState<DialogOptions>(); const [dialogOptions, setDialogOptions] = useState<DialogOptions>();
const fn = useRef<Function>(); const fn = useRef<Function>(undefined);
const confirm = useCallback((data: DialogOptions): Promise<boolean> => { const confirm = useCallback((data: DialogOptions): Promise<boolean> => {
return new Promise((resolve) => { return new Promise((resolve) => {

View File

@@ -1,8 +1,6 @@
"use client"; "use client";
import "react-loading-skeleton/dist/skeleton.css"; import "react-loading-skeleton/dist/skeleton.css";
import { netbirdTheme } from "@utils/theme";
import { Flowbite } from "flowbite-react";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { type ThemeProviderProps } from "next-themes/dist/types"; import { type ThemeProviderProps } from "next-themes/dist/types";
import * as React from "react"; import * as React from "react";
@@ -26,11 +24,9 @@ export function GlobalThemeProvider({
disableTransitionOnChange disableTransitionOnChange
{...props} {...props}
> >
<Flowbite theme={{ theme: netbirdTheme }}> <SkeletonTheme baseColor={"#25282d"} highlightColor={"#33373e"}>
<SkeletonTheme baseColor={"#25282d"} highlightColor={"#33373e"}> {children}
{children} </SkeletonTheme>
</SkeletonTheme>
</Flowbite>
</NextThemesProvider> </NextThemesProvider>
); );
} }

View File

@@ -1,6 +1,6 @@
import { RefObject, useEffect, useRef, useState } from "react"; import { RefObject, useEffect, useRef, useState } from "react";
export default function useIsVisible(ref: RefObject<HTMLElement>) { export default function useIsVisible(ref: RefObject<HTMLElement | null>) {
const observerRef = useRef<IntersectionObserver | null>(null); const observerRef = useRef<IntersectionObserver | null>(null);
const [isOnScreen, setIsOnScreen] = useState(false); const [isOnScreen, setIsOnScreen] = useState(false);

View File

@@ -1,7 +1,7 @@
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
const usePrevious = <T>(value: T): T | undefined => { const usePrevious = <T>(value: T): T | undefined => {
const ref = useRef<T>(); const ref = useRef<T>(undefined);
useEffect(() => { useEffect(() => {
ref.current = value; ref.current = value;

View File

@@ -42,7 +42,7 @@ export default function AppLayout({
<head> <head>
<GoogleTagManagerHeadScript /> <GoogleTagManagerHeadScript />
</head> </head>
<body className={cn(inter.className, "dark:bg-nb-gray bg-gray-50")}> <body className={cn(inter.className)}>
<Suspense fallback={<FullScreenLoading />}> <Suspense fallback={<FullScreenLoading />}>
<AnalyticsProvider> <AnalyticsProvider>
<DialogProvider> <DialogProvider>

View File

@@ -7,7 +7,7 @@ type Props = {
version?: string; version?: string;
versionText?: string; versionText?: string;
versionList?: SelectOption[]; versionList?: SelectOption[];
icon: React.FunctionComponent<{ size: number }>; icon: (props: { size: number }) => React.ReactElement;
os: string; os: string;
}; };
export const PostureCheckOperatingSystemInfo = ({ export const PostureCheckOperatingSystemInfo = ({

View File

@@ -91,7 +91,7 @@ export class RDPCertificateHandler implements CertificateHandler {
* Calculate SHA-256 fingerprint of certificate * Calculate SHA-256 fingerprint of certificate
*/ */
async calculateFingerprint(certBytes: Uint8Array): Promise<string> { async calculateFingerprint(certBytes: Uint8Array): Promise<string> {
const hashBuffer = await crypto.subtle.digest('SHA-256', certBytes); const hashBuffer = await crypto.subtle.digest('SHA-256', certBytes as Uint8Array<ArrayBuffer>);
const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray return hashArray
.map(b => b.toString(16).padStart(2, '0')) .map(b => b.toString(16).padStart(2, '0'))

View File

@@ -46,7 +46,7 @@ export const useRDPCertificateHandler = () => {
const calculateFingerprint = useCallback( const calculateFingerprint = useCallback(
async (certBytes: Uint8Array): Promise<string> => { async (certBytes: Uint8Array): Promise<string> => {
try { try {
const hashBuffer = await crypto.subtle.digest("SHA-256", certBytes); const hashBuffer = await crypto.subtle.digest("SHA-256", certBytes as Uint8Array<ArrayBuffer>);
const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashArray = Array.from(new Uint8Array(hashBuffer));
const fingerprint = hashArray const fingerprint = hashArray
.map((b) => b.toString(16).padStart(2, "0")) .map((b) => b.toString(16).padStart(2, "0"))

View File

@@ -191,16 +191,6 @@ export default function GroupsSettings({ account }: Props) {
disabled={!permission.settings.update} disabled={!permission.settings.update}
/> />
)} )}
<Callout variant={"info"} className={""}>
Looking to view and manage your groups? You can find group
management under{" "}
<InlineButtonLink
onClick={() => router.push("/groups")}
variant={"dashed"}
>
{`Access Control Groups`}
</InlineButtonLink>
</Callout>
</div> </div>
{(!isNetBirdHosted() || isLocalDev()) && ( {(!isNetBirdHosted() || isLocalDev()) && (
@@ -323,6 +313,17 @@ export default function GroupsSettings({ account }: Props) {
)} )}
</AnimatePresence> </AnimatePresence>
)} )}
<Callout variant={"info"} className={"mt-6"}>
Looking to view and manage your groups? You can find group management
under{" "}
<InlineButtonLink
onClick={() => router.push("/groups")}
variant={"dashed"}
>
{`Access Control Groups`}
</InlineButtonLink>
</Callout>
</div> </div>
</Tabs.Content> </Tabs.Content>
); );

View File

@@ -80,7 +80,7 @@ export function useNetBirdFetch(ignoreError: boolean = false): {
const handleErrors = useApiErrorHandling(ignoreError); const handleErrors = useApiErrorHandling(ignoreError);
const isTokenExpired = async () => { const isTokenExpired = async () => {
let attempts = 20; let attempts = 4;
while (isExpired(token) && attempts > 0) { while (isExpired(token) && attempts > 0) {
await sleep(500); await sleep(500);
attempts = attempts - 1; attempts = attempts - 1;

View File

@@ -1,20 +0,0 @@
import { CustomFlowbiteTheme } from "flowbite-react";
export const netbirdTheme: CustomFlowbiteTheme = {
navbar: {
root: {
base: "bg-white px-2 py-4 dark:border-gray-700 dark:bg-nb-gray/50 backdrop-blur-lg bg-gray-50 sm:px-6",
},
},
dropdown: {
floating: {
divider: "my-1 h-px bg-gray-100 dark:bg-zinc-800",
item: {
base: "flex items-center justify-start py-2 px-4 text-sm text-gray-700 cursor-pointer w-full hover:bg-gray-100 focus:bg-gray-100 dark:text-gray-200 dark:hover:bg-zinc-800 focus:outline-none dark:hover:text-white dark:focus:bg-zinc-800 dark:focus:text-white",
},
style: {
auto: "border border-gray-200 bg-white text-gray-900 dark:border-zinc-800/50 dark:bg-zinc-900 dark:text-white",
},
},
},
};

View File

@@ -1,14 +1,107 @@
import type { Config } from "tailwindcss"; import type { Config } from "tailwindcss";
const config: Config = { const config: Config = {
content: [ content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"],
"./node_modules/flowbite-react/**/*.js",
"./src/**/*.{js,ts,jsx,tsx,mdx}",
],
darkMode: "class", darkMode: "class",
theme: { theme: {
extend: { extend: {
colors: { colors: {
gray: {
50: "#F9FAFB",
100: "#F3F4F6",
200: "#E5E7EB",
300: "#D1D5DB",
400: "#9CA3AF",
500: "#6B7280",
600: "#4B5563",
700: "#374151",
800: "#1F2937",
900: "#111827",
},
red: {
50: "#FDF2F2",
100: "#FDE8E8",
200: "#FBD5D5",
300: "#F8B4B4",
400: "#F98080",
500: "#F05252",
600: "#E02424",
700: "#C81E1E",
800: "#9B1C1C",
900: "#771D1D",
},
yellow: {
50: "#FDFDEA",
100: "#FDF6B2",
200: "#FCE96A",
300: "#FACA15",
400: "#E3A008",
500: "#C27803",
600: "#9F580A",
700: "#8E4B10",
800: "#723B13",
900: "#633112",
},
green: {
50: "#F3FAF7",
100: "#DEF7EC",
200: "#BCF0DA",
300: "#84E1BC",
400: "#31C48D",
500: "#0E9F6E",
600: "#057A55",
700: "#046C4E",
800: "#03543F",
900: "#014737",
},
blue: {
50: "#EBF5FF",
100: "#E1EFFE",
200: "#C3DDFD",
300: "#A4CAFE",
400: "#76A9FA",
500: "#3F83F8",
600: "#1C64F2",
700: "#1A56DB",
800: "#1E429F",
900: "#233876",
},
indigo: {
50: "#F0F5FF",
100: "#E5EDFF",
200: "#CDDBFE",
300: "#B4C6FC",
400: "#8DA2FB",
500: "#6875F5",
600: "#5850EC",
700: "#5145CD",
800: "#42389D",
900: "#362F78",
},
purple: {
50: "#F6F5FF",
100: "#EDEBFE",
200: "#DCD7FE",
300: "#CABFFD",
400: "#AC94FA",
500: "#9061F9",
600: "#7E3AF2",
700: "#6C2BD9",
800: "#5521B5",
900: "#4A1D96",
},
pink: {
50: "#FDF2F8",
100: "#FCE8F3",
200: "#FAD1E8",
300: "#F8B4D9",
400: "#F17EB8",
500: "#E74694",
600: "#D61F69",
700: "#BF125D",
800: "#99154B",
900: "#751A3D",
},
"nb-gray": { "nb-gray": {
DEFAULT: "#181A1D", DEFAULT: "#181A1D",
"50": "#f4f6f7", "50": "#f4f6f7",
@@ -33,6 +126,7 @@ const config: Config = {
"950": "#181a1d", "950": "#181a1d",
"960": "#15171a", "960": "#15171a",
}, },
netbird: { netbird: {
DEFAULT: "#f68330", DEFAULT: "#f68330",
"50": "#fff6ed", "50": "#fff6ed",
@@ -82,6 +176,6 @@ const config: Config = {
}, },
}, },
}, },
plugins: [require("flowbite/plugin"), require("tailwindcss-animate")], plugins: [require("tailwindcss-animate")],
}; };
export default config; export default config;

View File

@@ -17,7 +17,7 @@
"moduleResolution": "node", "moduleResolution": "node",
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"jsx": "preserve", "jsx": "react-jsx",
"incremental": true, "incremental": true,
"plugins": [ "plugins": [
{ {
@@ -52,10 +52,11 @@
"next-env.d.ts", "next-env.d.ts",
"src/**/*.ts", "src/**/*.ts",
"src/**/*.tsx", "src/**/*.tsx",
".next/types/**/*.ts" ".next/types/**/*.ts",
".next/dev/types/**/*.ts"
], ],
"exclude": [ "exclude": [
"node_modules", "node_modules",
"node_modules/@axa-fr/**/*", "node_modules/@axa-fr/**/*"
] ]
} }