Reduce information visible to regular users (non-adminstrators) (#353)

reducing visibility to display only add peer information
This commit is contained in:
Eduard Gert
2024-03-15 13:25:40 +01:00
committed by GitHub
parent bf34c55110
commit 99f1bcc375
11 changed files with 187 additions and 67 deletions

View File

@@ -8,13 +8,24 @@ import useFetchApi from "@utils/api";
import { ExternalLinkIcon } from "lucide-react";
import React, { lazy, Suspense } from "react";
import PeerIcon from "@/assets/icons/PeerIcon";
import { useUsers } from "@/contexts/UsersProvider";
import { useLoggedInUser, useUsers } from "@/contexts/UsersProvider";
import { Peer } from "@/interfaces/Peer";
import PageContainer from "@/layouts/PageContainer";
import { SetupModalContent } from "@/modules/setup-netbird-modal/SetupModal";
const PeersTable = lazy(() => import("@/modules/peers/PeersTable"));
export default function Peers() {
const { isUser } = useLoggedInUser();
return (
<PageContainer>
{isUser ? <PeersDefaultView /> : <PeersView />}
</PageContainer>
);
}
function PeersView() {
const { data: peers, isLoading } = useFetchApi<Peer[]>("/peers");
const { users } = useUsers();
@@ -27,7 +38,7 @@ export default function Peers() {
});
return (
<PageContainer>
<>
<div className={"p-default py-6"}>
<Breadcrumbs>
<Breadcrumbs.Item
@@ -56,6 +67,37 @@ export default function Peers() {
<Suspense fallback={<SkeletonTable />}>
<PeersTable isLoading={isLoading} peers={peersWithUser} />
</Suspense>
</PageContainer>
</>
);
}
function PeersDefaultView() {
return (
<div className={"flex items-center justify-center flex-col"}>
<div className={"p-default py-6 max-w-3xl text-center"}>
<h1>Add new peer to your network</h1>
<Paragraph className={"inline"}>
To get started, install NetBird and log in using your email account.
After that you should be connected. If you have further questions
check out our{" "}
<InlineLink
href={"https://docs.netbird.io/how-to/getting-started#installation"}
target={"_blank"}
>
Installation Guide
<ExternalLinkIcon size={12} />
</InlineLink>
</Paragraph>
</div>
<div className={"px-3 pt-1 pb-8 max-w-3xl w-full"}>
<div
className={
"rounded-md border border-nb-gray-900/70 grid w-full bg-nb-gray-930/40 stepper-bg-variant"
}
>
<SetupModalContent header={false} footer={false} />
</div>
</div>
</div>
);
}

View File

@@ -57,7 +57,7 @@ function UserOverview({ user }: Props) {
const router = useRouter();
const userRequest = useApiCall<User>("/users");
const { mutate } = useSWRConfig();
const { loggedInUser, isOwnerOrAdmin } = useLoggedInUser();
const { loggedInUser, isOwnerOrAdmin, isUser } = useLoggedInUser();
const isLoggedInUser = loggedInUser ? loggedInUser?.id === user.id : false;
const initialGroups = user.auto_groups;
@@ -104,6 +104,7 @@ function UserOverview({ user }: Props) {
<Breadcrumbs.Item
href={"/team"}
label={"Team"}
disabled={isUser}
icon={<TeamIcon size={13} />}
/>
@@ -117,6 +118,7 @@ function UserOverview({ user }: Props) {
<Breadcrumbs.Item
href={"/team/users"}
label={"Users"}
disabled={isUser}
icon={<User2 size={16} />}
/>
)}
@@ -156,6 +158,7 @@ function UserOverview({ user }: Props) {
</h1>
</div>
</div>
{!isUser && (
<div className={"flex gap-4"}>
<Button
variant={"default"}
@@ -178,6 +181,7 @@ function UserOverview({ user }: Props) {
Save Changes
</Button>
</div>
)}
</div>
<div className={"flex gap-10 w-full mt-8 max-w-6xl"}>
@@ -190,6 +194,7 @@ function UserOverview({ user }: Props) {
Groups will be assigned to peers added by this user.
</HelpText>
<PeerGroupSelector
disabled={isUser}
onChange={setSelectedGroups}
values={selectedGroups}
/>

View File

@@ -65,3 +65,7 @@ p {
position: relative;
width: 100%;
}
.stepper-bg-variant .step-circle {
@apply !border-[#1d2024];
}

View File

@@ -15,13 +15,25 @@ type ItemProps = {
label: string;
icon?: React.ReactNode;
active?: boolean;
disabled?: boolean;
};
export const Item = ({ href, label, icon, active }: ItemProps) => {
export const Item = ({
href,
label,
icon,
active,
disabled = false,
}: ItemProps) => {
const router = useRouter();
return (
<div className={"flex items-center gap-2 group"}>
<div
className={cn(
"flex items-center gap-2 group",
disabled && "pointer-events-none",
)}
>
<ChevronRightIcon
size={16}
className={"text-nb-gray-400 group-first:hidden"}

View File

@@ -145,6 +145,7 @@ export function PeerGroupSelector({
"min-h-[46px] w-full relative items-center",
"border border-neutral-200 dark:border-nb-gray-700 justify-between py-2 px-3",
"rounded-md bg-white text-sm dark:bg-nb-gray-900/40 flex dark:text-neutral-400/70 text-neutral-500 cursor-pointer hover:dark:bg-nb-gray-900/50",
"disabled:pointer-events-none disabled:opacity-30",
)}
disabled={disabled}
ref={inputRef}

View File

@@ -36,7 +36,7 @@ const Step = ({ children, step, line = true, center = false }: StepProps) => {
className={cn(
"h-[34px] w-[34px] shrink-0 rounded-full flex items-center justify-center font-medium text-xs relative z-0 border-4 transition-all",
"dark:bg-nb-gray-900 dark:text-nb-gray-400 dark:border-nb-gray dark:group-hover:bg-nb-gray-800",
"bg-nb-gray-100 text-nb-gray-400 border-white group-hover:bg-nb-gray-200",
"bg-nb-gray-100 text-nb-gray-400 border-white group-hover:bg-nb-gray-200 step-circle",
)}
>
{step}

View File

@@ -1,5 +1,6 @@
import useFetchApi from "@utils/api";
import React, { useCallback } from "react";
import { useLoggedInUser } from "@/contexts/UsersProvider";
import { Country } from "@/interfaces/Country";
import { Peer } from "@/interfaces/Peer";
@@ -16,6 +17,16 @@ const CountryContext = React.createContext(
);
export default function CountryProvider({ children }: Props) {
const { isUser } = useLoggedInUser();
return isUser ? (
children
) : (
<CountryProviderContent>{children}</CountryProviderContent>
);
}
function CountryProviderContent({ children }: Props) {
const { data: countries, isLoading } = useFetchApi<Country[]>(
"/locations/countries",
false,

View File

@@ -1,5 +1,7 @@
import useFetchApi from "@utils/api";
import { usePathname } from "next/navigation";
import React, { useState } from "react";
import { useLoggedInUser } from "@/contexts/UsersProvider";
import { Group } from "@/interfaces/Group";
type Props = {
@@ -17,6 +19,17 @@ const GroupContext = React.createContext(
);
export default function GroupsProvider({ children }: Props) {
const path = usePathname();
const { isUser } = useLoggedInUser();
return isUser && path == "/peers" ? (
children
) : (
<GroupsProviderContent>{children}</GroupsProviderContent>
);
}
export function GroupsProviderContent({ children }: Props) {
const { data: groups, mutate, isLoading } = useFetchApi<Group[]>("/groups");
const [dropdownOptions, setDropdownOptions] = useState<Group[]>([]);

View File

@@ -15,7 +15,7 @@ import ApplicationProvider, {
} from "@/contexts/ApplicationProvider";
import CountryProvider from "@/contexts/CountryProvider";
import GroupsProvider from "@/contexts/GroupsProvider";
import UsersProvider from "@/contexts/UsersProvider";
import UsersProvider, { useLoggedInUser } from "@/contexts/UsersProvider";
import Navigation from "@/layouts/Navigation";
import Navbar, { headerHeight } from "./Header";
@@ -42,6 +42,7 @@ function DashboardPageContent({ children }: { children: React.ReactNode }) {
const { mobileNavOpen, toggleMobileNav } = useApplicationContext();
const isSm = useIsSm();
const isXs = useIsXs();
const { isUser } = useLoggedInUser();
const navOpenPageWidth = isSm ? "50%" : isXs ? "65%" : "80%";
const { bannerHeight } = useAnnouncement();
@@ -146,13 +147,14 @@ function DashboardPageContent({ children }: { children: React.ReactNode }) {
}}
>
<Navbar />
<div
className={"flex flex-row flex-grow"}
style={{
height: `calc(100vh - ${headerHeight + bannerHeight}px)`,
}}
>
<Navigation hideOnMobile />
{!isUser && <Navigation hideOnMobile />}
{children}
</div>
</motion.div>

View File

@@ -13,6 +13,7 @@ import NetBirdLogo from "@/assets/netbird.svg";
import NetBirdLogoFull from "@/assets/netbird-full.svg";
import { useAnnouncement } from "@/contexts/AnnouncementProvider";
import { useApplicationContext } from "@/contexts/ApplicationProvider";
import { useLoggedInUser } from "@/contexts/UsersProvider";
export const headerHeight = 75;
@@ -39,6 +40,8 @@ export default function NavbarWithDropdown() {
const { toggleMobileNav } = useApplicationContext();
const { bannerHeight } = useAnnouncement();
const { isUser } = useLoggedInUser();
return (
<>
<div
@@ -57,7 +60,10 @@ export default function NavbarWithDropdown() {
>
<div className={"flex items-center gap-4 md:hidden"}>
<Button
className={"!px-3 md:hidden"}
className={cn(
"!px-3 md:hidden",
isUser && "opacity-0 pointer-events-none",
)}
variant={"default-outline"}
onClick={toggleMobileNav}
>

View File

@@ -5,6 +5,7 @@ import { ModalContent, ModalFooter } from "@components/modal/Modal";
import Paragraph from "@components/Paragraph";
import SmallParagraph from "@components/SmallParagraph";
import { Tabs, TabsList, TabsTrigger } from "@components/Tabs";
import { ExternalLinkIcon } from "lucide-react";
import React from "react";
import AndroidIcon from "@/assets/icons/AndroidIcon";
import AppleIcon from "@/assets/icons/AppleIcon";
@@ -32,12 +33,30 @@ type Props = {
};
export default function SetupModal({ showClose = true, user }: Props) {
const os = useOperatingSystem();
return (
<ModalContent showClose={showClose}>
<SetupModalContent user={user} />
</ModalContent>
);
}
export function SetupModalContent({
user,
header = true,
footer = true,
tabAlignment = "center",
}: {
user?: OidcUserInfo;
header?: boolean;
footer?: boolean;
tabAlignment?: "center" | "start" | "end";
}) {
const os = useOperatingSystem();
const [isFirstRun] = useLocalStorage<boolean>("netbird-first-run", true);
return (
<ModalContent showClose={showClose}>
<>
{header && (
<div className={"text-center pb-8 pt-4 px-8"}>
<h2 className={"text-3xl max-w-lg mx-auto"}>
{isFirstRun ? (
@@ -53,8 +72,10 @@ export default function SetupModal({ showClose = true, user }: Props) {
To get started, install NetBird and log in using your email account.
</Paragraph>
</div>
)}
<Tabs defaultValue={String(os)}>
<TabsList>
<TabsList justify={tabAlignment} className={"pt-2 px-3"}>
<TabsTrigger value={String(OperatingSystem.LINUX)}>
<ShellIcon
className={
@@ -111,23 +132,26 @@ export default function SetupModal({ showClose = true, user }: Props) {
<IOSTab />
<DockerTab />
</Tabs>
{footer && (
<ModalFooter variant={"setup"}>
<div>
<SmallParagraph>
After that you should be connected. Add more devices to your network
or manage your existing devices in the admin panel. If you have
further questions check out our{" "}
After that you should be connected. Add more devices to your
network or manage your existing devices in the admin panel. If you
have further questions check out our{" "}
<InlineLink
href={
"https://docs.netbird.io/how-to/getting-started#installation"
}
target={"_blank"}
>
installation guide.
Installation Guide
<ExternalLinkIcon size={12} />
</InlineLink>
</SmallParagraph>
</div>
</ModalFooter>
</ModalContent>
)}
</>
);
}