From a98d6d9ce1267236d9b5b2f43ed6edf159ed5fff Mon Sep 17 00:00:00 2001 From: Misha Bragin Date: Mon, 26 Sep 2022 18:40:06 +0200 Subject: [PATCH] Display additional peer info (#84) --- src/components/PeerUpdate.tsx | 149 ++++++++++++++++++++++++++++++---- src/store/peer/types.ts | 14 ++++ src/views/AccessControl.tsx | 2 +- src/views/Peers.tsx | 49 +++++++---- src/views/Routes.tsx | 4 +- src/views/SetupKeys.tsx | 6 +- src/views/Users.tsx | 5 +- 7 files changed, 193 insertions(+), 36 deletions(-) diff --git a/src/components/PeerUpdate.tsx b/src/components/PeerUpdate.tsx index 130f907..bb460c5 100644 --- a/src/components/PeerUpdate.tsx +++ b/src/components/PeerUpdate.tsx @@ -2,24 +2,27 @@ import React, {useEffect, useRef, useState} from 'react'; import {useDispatch, useSelector} from "react-redux"; import {RootState} from "typesafe-actions"; import {actions as peerActions} from '../store/peer'; -import {Button, Col, Divider, Drawer, Form, Input, Row, Select, Space, Tag, Typography} from "antd"; +import {Button, Col, Collapse, Divider, Drawer, Form, Input, Row, Select, Space, Tag, Typography} from "antd"; import {Header} from "antd/es/layout/layout"; import type {CustomTagProps} from 'rc-select/lib/BaseSelect' -import {Peer, PeerGroupsToSave} from "../store/peer/types"; +import {FormPeer, Peer, PeerGroupsToSave} from "../store/peer/types"; import {Group, GroupPeer} from "../store/group/types"; -import {CloseOutlined, EditOutlined, FlagFilled} from "@ant-design/icons"; +import {CloseOutlined, EditOutlined} from "@ant-design/icons"; import {RuleObject} from 'antd/lib/form'; import {useGetAccessTokenSilently} from "../utils/token"; +import {timeAgo} from "../utils/common"; const {Paragraph} = Typography; const {Option} = Select; +const {Panel} = Collapse; const PeerUpdate = () => { const {getAccessTokenSilently} = useGetAccessTokenSilently() const dispatch = useDispatch() const groups = useSelector((state: RootState) => state.group.data) - const peer = useSelector((state: RootState) => state.peer.peer) - const [formPeer, setFormPeer] = useState({} as Peer) + const users = useSelector((state: RootState) => state.user.data) + const peer: Peer = useSelector((state: RootState) => state.peer.peer) + const [formPeer, setFormPeer] = useState({} as FormPeer) const updateGroupsVisible = useSelector((state: RootState) => state.peer.updateGroupsVisible) const savedGroups = useSelector((state: RootState) => state.peer.savedGroups) const updatedPeers = useSelector((state: RootState) => state.peer.updatedPeer) @@ -75,17 +78,25 @@ const PeerUpdate = () => { const gs_name = gs?.map(g => g.name) as string[] setPeerGroups(gs) setSelectedTagGroups(gs_name) - setFormPeer(peer) - form.setFieldsValue({ + const fPeer = { + ...peer, name: formPeer.name ? formPeer.name : peer.name, - groups: gs_name - }) + groupsNames: gs_name, + userEmail: users?.find(u => u.id === peer.user_id)?.email, + last_seen: peer.connected ? "just now" : String(timeAgo(peer.last_seen)), + ui_version: peer.ui_version ? peer.ui_version.replace("netbird-desktop-ui/", "") : "" + } as FormPeer + setFormPeer(fPeer) + form.setFieldsValue(fPeer) }, [peer]) useEffect(() => { setTagGroups(groups?.map(g => g.name) || []) }, [groups]) + useEffect(() => { + }, [users]) + const toggleEditName = (status: boolean) => { setEditName(status) } @@ -173,7 +184,7 @@ const PeerUpdate = () => { setUpdateGroupsVisible(false) setEditName(false) // setSaveBtnDisabled(true) - setFormPeer({} as Peer) + setFormPeer({} as FormPeer) setCallingPeerAPI(false) setCallingPeerAPI(false) setSubmitRunning(false) @@ -268,7 +279,7 @@ const PeerUpdate = () => { { } > -
+
@@ -328,10 +339,55 @@ const PeerUpdate = () => { - + + + NetBird IP + {formPeer.connected ? "online" : "offline"} + } + > + + + + + + + + + + + {formPeer.user_id && ( + + + + + + )} { - + {/* @@ -363,6 +419,69 @@ const PeerUpdate = () => { + */} + {/* + + System Info + + */} + + + + + + + + + + + + + + + + + + + + {formPeer.ui_version && ( + + + + + )} + + + diff --git a/src/store/peer/types.ts b/src/store/peer/types.ts index b47fb11..373fa60 100644 --- a/src/store/peer/types.ts +++ b/src/store/peer/types.ts @@ -10,6 +10,14 @@ export interface Peer { version: string, groups?: Group[] ssh_enabled: boolean, + hostname: string, + user_id?: string, + ui_version?: string, +} + +export interface FormPeer extends Peer { + groupsNames: string[], + userEmail?: string } export interface PeerToSave extends Peer { @@ -30,3 +38,9 @@ export interface PeerNameToIP { export interface PeerIPToName { [key: string]: string; } + +export interface PeerDataTable extends Peer { + key: string; + groups: Group[]; + groupsCount: number; +} diff --git a/src/views/AccessControl.tsx b/src/views/AccessControl.tsx index 82345dd..b3060ea 100644 --- a/src/views/AccessControl.tsx +++ b/src/views/AccessControl.tsx @@ -415,7 +415,7 @@ export const AccessControl = () => { return setRuleAndView(record as RuleDataTable)} - className="tooltip-label">{text} + className="tooltip-label">{text} }} /> diff --git a/src/views/Peers.tsx b/src/views/Peers.tsx index ec69584..0a3165e 100644 --- a/src/views/Peers.tsx +++ b/src/views/Peers.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React, {useEffect, useState} from 'react'; import {Link} from 'react-router-dom'; import {useDispatch, useSelector} from "react-redux"; import {RootState} from "typesafe-actions"; @@ -29,7 +29,7 @@ import { Tooltip, Typography } from "antd"; -import {Peer} from "../store/peer/types"; +import {Peer, PeerDataTable} from "../store/peer/types"; import {filter} from "lodash" import {formatOS, timeAgo} from "../utils/common"; import {ExclamationCircleOutlined} from "@ant-design/icons"; @@ -39,18 +39,12 @@ import PeerUpdate from "../components/PeerUpdate"; import tableSpin from "../components/Spin"; import {TooltipPlacement} from "antd/es/tooltip"; import {useGetAccessTokenSilently} from "../utils/token"; +import {actions as userActions} from "../store/user"; const {Title, Paragraph, Text} = Typography; const {Column} = Table; const {confirm} = Modal; - -interface PeerDataTable extends Peer { - key: string; - groups: Group[]; - groupsCount: number; -} - export const Peers = () => { //const {accessToken} = useOidcAccessToken() @@ -67,6 +61,7 @@ export const Peers = () => { const savedGroups = useSelector((state: RootState) => state.peer.savedGroups); const updatedPeer = useSelector((state: RootState) => state.peer.updatedPeer); const updateGroupsVisible = useSelector((state: RootState) => state.peer.updateGroupsVisible) + const users = useSelector((state: RootState) => state.user.data); const [textToSearch, setTextToSearch] = useState(''); const [optionOnOff, setOptionOnOff] = useState('all'); @@ -111,6 +106,7 @@ export const Peers = () => { } useEffect(() => { + dispatch(userActions.getUsers.request({getAccessTokenSilently: getAccessTokenSilently, payload: null})); dispatch(peerActions.getPeers.request({getAccessTokenSilently: getAccessTokenSilently, payload: null})); dispatch(groupActions.getGroups.request({getAccessTokenSilently: getAccessTokenSilently, payload: null})); dispatch(routeActions.getRoutes.request({getAccessTokenSilently: getAccessTokenSilently, payload: null})); @@ -191,8 +187,13 @@ export const Peers = () => { const filterDataTable = (): Peer[] => { const t = textToSearch.toLowerCase().trim() - let f: Peer[] = filter(peers, (f: Peer) => - (f.name.toLowerCase().includes(t) || f.ip.includes(t) || f.os.includes(t) || t === "") + let f: Peer[] = filter(peers, (f: Peer) => { + let userEmail: string | null + const u = users?.find(u => u.id === f.user_id)?.email + userEmail = u ? u : "" + return (f.name.toLowerCase().includes(t) || f.ip.includes(t) || f.os.includes(t) || t === "" || + (userEmail && userEmail.toLowerCase().includes(t))) + } ) as Peer[] if (optionOnOff === "on") { f = filter(peers, (f: Peer) => f.connected) @@ -359,13 +360,30 @@ export const Peers = () => { return ( ) } + const renderName = (peer: PeerDataTable) => { + const userEmail = users?.find(u => u.id === peer.user_id)?.email + if (!userEmail) { + return + } + return
+ +
+ } + return ( <> @@ -377,7 +395,6 @@ export const Peers = () => { - {/**/} @@ -428,10 +445,10 @@ export const Peers = () => { (record as any).name.includes(value)} defaultSortOrder='ascend' + align="left" sorter={(a, b) => ((a as any).name.localeCompare((b as any).name))} render={(text: string, record: PeerDataTable,) => { - return + return renderName(record) }} /> { render={(text, record, index) => { return { + onOpenChange={visible => { if (visible) setPeerToAction(record as PeerDataTable) }}> }} diff --git a/src/views/Routes.tsx b/src/views/Routes.tsx index 1de3fc9..42749ab 100644 --- a/src/views/Routes.tsx +++ b/src/views/Routes.tsx @@ -424,7 +424,9 @@ export const Routes = () => { render={(text, record) => { const desc = (record as RouteDataTable).description.trim() return {text} + arrowPointAtCenter> + {text} + }} /> { render={(text, record, index) => { return + className="tooltip-label"> {text} + }} defaultSortOrder='ascend' /> diff --git a/src/views/Users.tsx b/src/views/Users.tsx index aa5dd85..4aea4d3 100644 --- a/src/views/Users.tsx +++ b/src/views/Users.tsx @@ -260,7 +260,10 @@ export const Users = () => { render={(text, record, index) => { return + className="tooltip-label"> + {(text && text.trim() !== "") ? text : (record as User).id} + + }} />