Skip to content

Commit

Permalink
Apply recent cloud changes (#447)
Browse files Browse the repository at this point in the history
* Add resource description, add single resource for acl, add icons for group badges, add inactivity expiration

* Add extra dns labels, remove routing restriction
  • Loading branch information
heisbrot authored Feb 21, 2025
1 parent c8e3b50 commit 61e11d3
Show file tree
Hide file tree
Showing 78 changed files with 1,994 additions and 653 deletions.
136 changes: 73 additions & 63 deletions src/app/(dashboard)/peer/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ import Separator from "@components/Separator";
import FullScreenLoading from "@components/ui/FullScreenLoading";
import LoginExpiredBadge from "@components/ui/LoginExpiredBadge";
import TextWithTooltip from "@components/ui/TextWithTooltip";
import { getOperatingSystem } from "@hooks/useOperatingSystem";
import useRedirect from "@hooks/useRedirect";
import { IconCloudLock, IconInfoCircle } from "@tabler/icons-react";
import useFetchApi from "@utils/api";
import { cn } from "@utils/helpers";
import dayjs from "dayjs";
import { isEmpty, trim } from "lodash";
import {
Expand All @@ -41,6 +40,7 @@ import {
NetworkIcon,
PencilIcon,
TerminalSquare,
TimerResetIcon,
} from "lucide-react";
import { useRouter, useSearchParams } from "next/navigation";
import { toASCII } from "punycode";
Expand All @@ -56,11 +56,11 @@ import PeerProvider, { usePeer } from "@/contexts/PeerProvider";
import RoutesProvider from "@/contexts/RoutesProvider";
import { useLoggedInUser } from "@/contexts/UsersProvider";
import { useHasChanges } from "@/hooks/useHasChanges";
import { OperatingSystem } from "@/interfaces/OperatingSystem";
import type { Peer } from "@/interfaces/Peer";
import PageContainer from "@/layouts/PageContainer";
import useGroupHelper from "@/modules/groups/useGroupHelper";
import { AccessiblePeersSection } from "@/modules/peer/AccessiblePeersSection";
import { PeerExpirationToggle } from "@/modules/peer/PeerExpirationToggle";
import { PeerNetworkRoutesSection } from "@/modules/peer/PeerNetworkRoutesSection";

export default function PeerPage() {
Expand All @@ -70,9 +70,16 @@ export default function PeerPage() {

useRedirect("/peers", false, !peerId);

const peerKey = useMemo(() => {
let id = peer?.id ?? "";
let ssh = peer?.ssh_enabled ? "1" : "0";
let expiration = peer?.login_expiration_enabled ? "1" : "0";
return `${id}-${ssh}-${expiration}`;
}, [peer]);

return peer && !isLoading ? (
<PeerProvider peer={peer} key={peerId}>
<PeerOverview />
<PeerOverview key={peerKey} />
</PeerProvider>
) : (
<FullScreenLoading />
Expand All @@ -89,20 +96,15 @@ function PeerOverview() {
const [loginExpiration, setLoginExpiration] = useState(
peer.login_expiration_enabled,
);
const [inactivityExpiration, setInactivityExpiration] = useState(
peer.inactivity_expiration_enabled,
);
const [selectedGroups, setSelectedGroups, { getAllGroupCalls }] =
useGroupHelper({
initial: peerGroups,
peer,
});

/**
* Check the operating system of the peer, if it is linux, then show the routes table, otherwise hide it.
*/
const isLinux = useMemo(() => {
const operatingSystem = getOperatingSystem(peer.os);
return operatingSystem == OperatingSystem.LINUX;
}, [peer.os]);

/**
* Detect if there are changes in the peer information, if there are changes, then enable the save button.
*/
Expand All @@ -111,10 +113,16 @@ function PeerOverview() {
ssh,
selectedGroups,
loginExpiration,
inactivityExpiration,
]);

const updatePeer = async () => {
const updateRequest = update(name, ssh, loginExpiration);
const updateRequest = update({
name,
ssh,
loginExpiration,
inactivityExpiration,
});
const groupCalls = getAllGroupCalls();
const batchCall = groupCalls
? [...groupCalls, updateRequest]
Expand All @@ -125,13 +133,19 @@ function PeerOverview() {
promise: Promise.all(batchCall).then(() => {
mutate("/peers/" + peer.id);
mutate("/groups");
updateHasChangedRef([name, ssh, selectedGroups, loginExpiration]);
updateHasChangedRef([
name,
ssh,
selectedGroups,
loginExpiration,
inactivityExpiration,
]);
}),
loadingMessage: "Saving the peer...",
});
};

const { isUser } = useLoggedInUser();
const { isUser, isOwnerOrAdmin } = useLoggedInUser();

return (
<PageContainer>
Expand Down Expand Up @@ -213,53 +227,43 @@ function PeerOverview() {
<div className={"flex gap-10 w-full mt-5 max-w-6xl"}>
<PeerInformationCard peer={peer} />

<div className={"flex flex-col gap-6 w-1/2"}>
<FullTooltip
content={
<div className={"flex flex-col gap-6 w-1/2 transition-all"}>
<div>
<PeerExpirationToggle
peer={peer}
value={loginExpiration}
icon={<TimerResetIcon size={16} />}
onChange={(state) => {
setLoginExpiration(state);
!state && setInactivityExpiration(false);
}}
/>
{isOwnerOrAdmin && !!peer?.user_id && (
<div
className={
"flex gap-2 items-center !text-nb-gray-300 text-xs"
}
>
{!peer.user_id ? (
<>
<>
<IconInfoCircle size={14} />
<span>
Login expiration is disabled for all peers added
with an setup-key.
</span>
</>
</>
) : (
<>
<LockIcon size={14} />
<span>
{`You don't have the required permissions to update this
setting.`}
</span>
</>
className={cn(
"border border-nb-gray-900 border-t-0 rounded-b-md bg-nb-gray-940 px-[1.28rem] pt-3 pb-5 flex flex-col gap-4 mx-[0.25rem]",
!loginExpiration
? "opacity-50 pointer-events-none"
: "bg-nb-gray-930/80",
)}
>
<PeerExpirationToggle
peer={peer}
variant={"blank"}
value={inactivityExpiration}
onChange={setInactivityExpiration}
title={"Require login after disconnect"}
description={
"Enable to require authentication after users disconnect from management for 10 minutes."
}
className={
!loginExpiration ? "opacity-40 pointer-events-none" : ""
}
/>
</div>
}
className={"w-full block"}
disabled={!!peer.user_id && !isUser}
>
<FancyToggleSwitch
disabled={!peer.user_id || isUser}
value={loginExpiration}
onChange={setLoginExpiration}
label={
<>
<IconCloudLock size={16} />
Login Expiration
</>
}
helpText={
"Enable to require SSO login peers to re-authenticate when their login expires."
}
/>
</FullTooltip>
)}
</div>

<FullTooltip
content={
<div
Expand Down Expand Up @@ -317,7 +321,7 @@ function PeerOverview() {
</div>
</div>

{isLinux && !isUser ? (
{!isUser ? (
<>
<Separator />
<PeerNetworkRoutesSection peer={peer} />
Expand All @@ -335,7 +339,7 @@ function PeerOverview() {
);
}

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

const countryText = useMemo(() => {
Expand Down Expand Up @@ -371,14 +375,20 @@ function PeerInformationCard({ peer }: { peer: Peer }) {

<Card.ListItem
copy
copyText={"Domain name"}
copyText={"DNS label"}
label={
<>
<Globe size={16} />
Domain Name
</>
}
className={
peer?.extra_dns_labels && peer.extra_dns_labels.length > 0
? "items-start"
: ""
}
value={peer.dns_label}
extraText={peer?.extra_dns_labels}
/>

<Card.ListItem
Expand Down Expand Up @@ -489,7 +499,7 @@ interface ModalProps {
peer: Peer;
initialName: string;
}
function EditNameModal({ onSuccess, peer, initialName }: ModalProps) {
function EditNameModal({ onSuccess, peer, initialName }: Readonly<ModalProps>) {
const [name, setName] = useState(initialName);

const isDisabled = useMemo(() => {
Expand Down
17 changes: 11 additions & 6 deletions src/app/(dashboard)/team/user/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default function UserPage() {
const { data: users, isLoading } = useFetchApi<User[]>(
`/users?service_user=${isServiceUser}`,
);
const { isOwnerOrAdmin } = useLoggedInUser();

const user = useMemo(() => {
return users?.find((u) => u.id === userId);
Expand All @@ -49,11 +50,15 @@ export default function UserPage() {

const userGroups = useGroupIdsToGroups(user?.auto_groups);

return !isLoading && user && userGroups !== undefined ? (
<UserOverview user={user} initialGroups={userGroups} />
) : (
<FullScreenLoading />
);
if (!isOwnerOrAdmin && user && !isLoading) {
return <UserOverview user={user} initialGroups={[]} />;
}

if (isOwnerOrAdmin && user && !isLoading && userGroups) {
return <UserOverview user={user} initialGroups={userGroups} />;
}

return <FullScreenLoading />;
}

type Props = {
Expand Down Expand Up @@ -195,7 +200,7 @@ function UserOverview({ user, initialGroups }: Readonly<Props>) {
<div className={"flex gap-10 w-full mt-8 max-w-6xl items-start"}>
<UserInformationCard user={user} />
<div className={"flex flex-col gap-8 w-1/2 "}>
{!user.is_service_user && (
{!user.is_service_user && isOwnerOrAdmin && (
<div>
<Label>Auto-assigned groups</Label>
<HelpText>
Expand Down
2 changes: 1 addition & 1 deletion src/assets/icons/CircleIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function CircleIcon({
size = 11,
inactiveDot = "gray",
className,
}: Props) {
}: Readonly<Props>) {
return (
<span
style={{ width: size + "px", height: size + "px" }}
Expand Down
39 changes: 39 additions & 0 deletions src/assets/icons/EntraIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { iconProperties, IconProps } from "@/assets/icons/IconProperties";

export default function EntraIcon(props: Readonly<IconProps>) {
return (
<svg
width="231"
height="231"
viewBox="0 0 231 231"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...iconProperties(props)}
>
<path
d="M48.7923 180.077C53.7717 183.183 62.0492 186.635 70.8015 186.635C78.771 186.635 86.1758 184.325 92.3102 180.385C92.3102 180.385 92.323 180.385 92.3358 180.373L115.5 165.896V218.167C111.83 218.167 108.134 217.166 104.925 215.164L48.7923 180.077Z"
fill="#225086"
/>
<path
d="M100.78 19.3398L4.53017 127.91C-2.90033 136.303 -0.962501 148.982 8.67533 155.001C8.67533 155.001 44.3007 177.267 48.7923 180.077C53.7717 183.183 62.0492 186.635 70.8015 186.635C78.771 186.635 86.1758 184.325 92.3102 180.385C92.3102 180.385 92.323 180.385 92.3358 180.373L115.5 165.896L59.4953 130.887L115.513 67.6958V12.8333C110.072 12.8333 104.63 15.0022 100.78 19.3398Z"
fill="#66DDFF"
/>
<path
d="M59.4953 130.887L60.1627 131.298L115.5 165.896H115.513V67.7087L115.5 67.6958L59.4953 130.887Z"
fill="#CBF8FF"
/>
<path
d="M222.325 155.001C231.963 148.982 233.9 136.303 226.47 127.91L163.317 56.672C158.222 54.2978 152.511 52.9375 146.467 52.9375C134.596 52.9375 123.983 58.058 116.925 66.1045L115.526 67.683L171.53 130.874L115.513 165.884V218.154C119.196 218.154 122.866 217.153 126.075 215.151L222.325 154.988V155.001Z"
fill="#074793"
/>
<path
d="M115.513 12.8333V67.6958L116.912 66.1173C123.97 58.0708 134.583 52.9503 146.454 52.9503C152.511 52.9503 158.209 54.3235 163.304 56.6848L130.207 19.3527C126.37 15.015 120.929 12.8462 115.5 12.8462L115.513 12.8333Z"
fill="#0294E4"
/>
<path
d="M171.518 130.887L115.513 67.7087V165.884L171.518 130.887Z"
fill="#96BCC2"
/>
</svg>
);
}
31 changes: 31 additions & 0 deletions src/assets/icons/GoogleIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { iconProperties, IconProps } from "@/assets/icons/IconProperties";

export default function GoogleIcon(props: Readonly<IconProps>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
height="24"
viewBox="0 0 24 24"
width="24"
{...iconProperties(props)}
>
<path
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
fill="#4285F4"
/>
<path
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
fill="#34A853"
/>
<path
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
fill="#FBBC05"
/>
<path
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
fill="#EA4335"
/>
<path d="M1 1h22v22H1z" fill="none" />
</svg>
);
}
Loading

0 comments on commit 61e11d3

Please sign in to comment.