Compare commits

...
5 Commits
Author SHA1 Message Date
braginini 9875bb0fcd Fix setup key create popup 2023-05-07 23:16:55 +02:00
braginini ae586b4dfe Fix add PAT popup 2023-05-07 19:59:57 +02:00
braginini c0a6965310 Fix user edit view 2023-05-07 19:59:47 +02:00
braginini f12a923c61 Fix user edit view 2023-05-07 19:32:14 +02:00
braginini ad798bbab4 Fix invite and add user popups 2023-05-07 18:55:34 +02:00
6 changed files with 284 additions and 240 deletions

No files matched your search

+136 -144
View File
@@ -1,23 +1,23 @@
import React, { useEffect, useRef, useState } from "react"; import React, {useEffect, useRef, useState} from "react";
import { useDispatch, useSelector } from "react-redux"; import {useDispatch, useSelector} from "react-redux";
import { actions as setupKeyActions } from "../store/setup-key"; import {actions as setupKeyActions} from "../store/setup-key";
import { Button, Col, Divider, Form, Input, InputNumber, Modal, Row, Select, Switch, Tag, Typography } from "antd"; import {Button, Col, Divider, Form, Input, InputNumber, Modal, Row, Select, Space, Switch, Tag, Typography} from "antd";
import { RootState } from "typesafe-actions"; import {RootState} from "typesafe-actions";
import { FormSetupKey, SetupKey, SetupKeyToSave } from "../store/setup-key/types"; import {FormSetupKey, SetupKey, SetupKeyToSave} from "../store/setup-key/types";
import { formatDate, timeAgo } from "../utils/common"; import {formatDate, timeAgo} from "../utils/common";
import { RuleObject } from "antd/lib/form"; import {RuleObject} from "antd/lib/form";
import { CustomTagProps } from "rc-select/lib/BaseSelect"; import {CustomTagProps} from "rc-select/lib/BaseSelect";
import { Group } from "../store/group/types"; import {Group} from "../store/group/types";
import { useGetTokenSilently } from "../utils/token"; import {useGetTokenSilently} from "../utils/token";
import { expiresInToSeconds, ExpiresInValue } from "../views/ExpiresInInput"; import {expiresInToSeconds, ExpiresInValue} from "../views/ExpiresInInput";
import moment from "moment"; import moment from "moment";
import { Container } from "./Container"; import {Container} from "./Container";
import Paragraph from "antd/es/typography/Paragraph"; import Paragraph from "antd/es/typography/Paragraph";
import { EditOutlined, LockOutlined } from "@ant-design/icons"; import {EditOutlined, LockOutlined} from "@ant-design/icons";
const { Option } = Select; const {Option} = Select;
const { Text } = Typography; const {Text} = Typography;
const ExpiresInDefault: ExpiresInValue = { number: 30, interval: "day" }; const ExpiresInDefault: ExpiresInValue = {number: 30, interval: "day"};
const customExpiresFormat = (value: Date): string | null => { const customExpiresFormat = (value: Date): string | null => {
return formatDate(value); return formatDate(value);
@@ -36,7 +36,7 @@ const customLastUsedFormat = (value: Date): string | null => {
}; };
const SetupKeyNew = () => { const SetupKeyNew = () => {
const { getTokenSilently } = useGetTokenSilently(); const {getTokenSilently} = useGetTokenSilently();
const dispatch = useDispatch(); const dispatch = useDispatch();
const setupNewKeyVisible = useSelector((state: RootState) => state.setupKey.setupNewKeyVisible); const setupNewKeyVisible = useSelector((state: RootState) => state.setupKey.setupNewKeyVisible);
const setupKey = useSelector((state: RootState) => state.setupKey.setupKey); const setupKey = useSelector((state: RootState) => state.setupKey.setupKey);
@@ -53,7 +53,7 @@ const SetupKeyNew = () => {
useEffect(() => { useEffect(() => {
if (!editName) return; if (!editName) return;
inputNameRef.current!.focus({ cursor: "end" }); inputNameRef.current!.focus({cursor: "end"});
}, [editName]); }, [editName]);
useEffect(() => { useEffect(() => {
@@ -147,7 +147,7 @@ const SetupKeyNew = () => {
}; };
const onChange = (data: any) => { const onChange = (data: any) => {
setFormSetupKey({ ...formSetupKey, ...data }); setFormSetupKey({...formSetupKey, ...data});
}; };
const toggleEditName = (status: boolean) => { const toggleEditName = (status: boolean) => {
@@ -171,7 +171,7 @@ const SetupKeyNew = () => {
}; };
const tagRender = (props: CustomTagProps) => { const tagRender = (props: CustomTagProps) => {
const { value, closable, onClose } = props; const {value, closable, onClose} = props;
const onPreventMouseDown = (event: React.MouseEvent<HTMLSpanElement>) => { const onPreventMouseDown = (event: React.MouseEvent<HTMLSpanElement>) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@@ -183,7 +183,7 @@ const SetupKeyNew = () => {
onMouseDown={onPreventMouseDown} onMouseDown={onPreventMouseDown}
closable={closable} closable={closable}
onClose={onClose} onClose={onClose}
style={{ marginRight: 3 }} style={{marginRight: 3}}
> >
<strong>{value}</strong> <strong>{value}</strong>
</Tag> </Tag>
@@ -202,10 +202,10 @@ const SetupKeyNew = () => {
return ( return (
<> <>
<Tag color="blue" style={{ marginRight: 3 }}> <Tag color="blue" style={{marginRight: 3}}>
<strong>{label}</strong> <strong>{label}</strong>
</Tag> </Tag>
<span style={{ fontSize: ".85em" }}>{peersCount}</span> <span style={{fontSize: ".85em"}}>{peersCount}</span>
</> </>
); );
}; };
@@ -213,10 +213,10 @@ const SetupKeyNew = () => {
const dropDownRender = (menu: React.ReactElement) => ( const dropDownRender = (menu: React.ReactElement) => (
<> <>
{menu} {menu}
<Divider style={{ margin: "8px 0" }} /> <Divider style={{margin: "8px 0"}}/>
<Row style={{ padding: "0 8px 4px" }}> <Row style={{padding: "0 8px 4px"}}>
<Col flex="auto"> <Col flex="auto">
<span style={{ color: "#9CA3AF" }}>Add new group by pressing "Enter"</span> <span style={{color: "#9CA3AF"}}>Add new group by pressing "Enter"</span>
</Col> </Col>
<Col flex="none"> <Col flex="none">
<svg width="14" height="12" viewBox="0 0 14 12" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="14" height="12" viewBox="0 0 14 12" fill="none" xmlns="http://www.w3.org/2000/svg">
@@ -252,23 +252,10 @@ const SetupKeyNew = () => {
return ( return (
<Modal <Modal
style={{ style={{
...{ maxWidth: window.screen.availWidth <= 425 ? "90%" : "414px" }, ...{maxWidth: window.screen.availWidth <= 425 ? "90%" : "414px"},
}} }}
open={setupNewKeyVisible} open={setupNewKeyVisible}
onCancel={onCancel} onCancel={onCancel}
title={
<Paragraph
style={{
whiteSpace: "pre-line",
fontSize: "18px",
fontWeight: "600",
lineHeight: "26px",
color: "#252526",
}}
>
{isEditMode ? "Setup Key overview" : "Create Setup Key"}
</Paragraph>
}
footer={[ footer={[
<Container <Container
style={{ style={{
@@ -290,45 +277,55 @@ const SetupKeyNew = () => {
disabled={savedSetupKey.loading || !changesDetected()} disabled={savedSetupKey.loading || !changesDetected()}
onClick={handleFormSubmit} onClick={handleFormSubmit}
> >
{`${formSetupKey.id ? "Save" : "Create"} Key`} {`${formSetupKey.id ? "Save" : "Create"} key`}
</Button> </Button>
</Container>, </Container>,
]} ]}
> >
<Form <Container style={{textAlign: "start", marginLeft: "-15px", marginRight: "-15px"}}>
layout="vertical" <Paragraph
hideRequiredMark style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px"}}>
form={form} {isEditMode ? "Setup key overview" : "Create setup key"}
onValuesChange={onChange} </Paragraph>
initialValues={{ <Paragraph type={"secondary"}
expiresIn: ExpiresInDefault, style={{
usage_limit: 1, textAlign: "start",
}} whiteSpace: "pre-line",
> marginTop: "-23px",
<Container paddingBottom: "25px",
style={{ }}>
padding: 0, {"Use this key to register new machines in your network"}
</Paragraph>
<Form
layout="vertical"
requiredMark={false}
form={form}
onValuesChange={onChange}
initialValues={{
expiresIn: ExpiresInDefault,
usage_limit: 1,
}} }}
> >
<Row style={{ marginTop: "28px" }}>
<Row>
{isEditMode ? ( {isEditMode ? (
<></> <></>
) : ( ) : (
<Col span={24}> <Col span={24}>
<Paragraph <Paragraph style={{fontWeight: "bold"}}>
style={{ whiteSpace: "pre-line", fontSize: "16px", fontWeight: "600", margin: 0 }} Name
> </Paragraph>
Key name <Paragraph type={"secondary"} style={{marginTop: "-15px"}}>
Set an easily identifiable name for your key
</Paragraph> </Paragraph>
<Text style={{ color: "#818183" }}>Name the key to identify it easily</Text>
</Col> </Col>
)} )}
<Col span={24}> <Col span={24}>
<Form.Item <Form.Item
style={{ marginBottom: "0px" }} style={{marginBottom: "0px", marginTop: "-10px"}}
name="name" name="name"
rules={[{ required: true, message: "Please enter key name." }]} rules={[{required: true, message: "Please enter key name."}]}
> >
{isEditMode ? ( {isEditMode ? (
<Input <Input
@@ -337,93 +334,89 @@ const SetupKeyNew = () => {
placeholder={setupKey.name} placeholder={setupKey.name}
autoComplete="off" autoComplete="off"
ref={inputNameRef} ref={inputNameRef}
suffix={<EditOutlined onClick={() => toggleEditName(true)} />} suffix={<EditOutlined onClick={() => toggleEditName(true)}/>}
onPressEnter={() => toggleEditName(false)} onPressEnter={() => toggleEditName(false)}
onBlur={() => toggleEditName(false)} onBlur={() => toggleEditName(false)}
/> />
) : ( ) : (
<Input placeholder={`e.g. "AWS servers"`} /> <Input placeholder={`e.g. "AWS servers"`}/>
)} )}
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
{isEditMode && ( {isEditMode && (
<Row style={{ marginTop: "28px" }}> <Row style={{marginTop: "20px"}}>
<Col span={24}> <Col span={24}>
<Paragraph <Paragraph
style={{ whiteSpace: "pre-line", fontSize: "16px", fontWeight: "600", margin: 0 }} style={{whiteSpace: "pre-line", fontWeight: "bold", margin: 0}}
> >
Key Key
<Tag <Tag
color={`${formSetupKey.state === "valid" ? "green" : "red"}`} color={`${formSetupKey.state === "valid" ? "green" : "red"}`}
style={{ marginLeft: "10px", borderRadius: "2px", fontWeight: "500" }} style={{marginLeft: "10px", borderRadius: "2px", fontWeight: "500"}}
> >
{formSetupKey.state} {formSetupKey.state}
</Tag> </Tag>
</Paragraph> </Paragraph>
<Input <Input
style={{ marginTop: "10px" }} style={{marginTop: "10px"}}
disabled disabled
value={formSetupKey.key} value={formSetupKey.key}
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />} suffix={<LockOutlined style={{color: "#BFBFBF"}}/>}
/> />
</Col> </Col>
</Row> </Row>
)} )}
{!isEditMode && (
<Row style={{ marginTop: "28px" }}> <Row
{isEditMode ? ( style={{marginTop: "20px"}}
<Row style={{ fontSize: "16px" }}> justify={"space-between"}>
<Paragraph style={{ whiteSpace: "pre-line", margin: 0, fontWeight: "600" }}> <Col span={18}>
{formSetupKey.type === "one-off" ? "One-off" : "Reusable"} <Paragraph
</Paragraph>
<Text style={{ marginLeft: "5px", color: "#818183" }}>type</Text>
</Row>
) : (
<Row>
<Col style={{ width: "80%" }}>
<Paragraph
style={{
whiteSpace: "pre-line",
fontSize: "16px",
margin: 0,
fontWeight: "600",
}}
>
Reusable
</Paragraph>
<Text style={{ color: "#818183" }}>
This type of a setup key allows to enroll multiple peers
</Text>
</Col>
<Form.Item
name="reusable"
valuePropName="checked"
style={{ style={{
display: "flex", whiteSpace: "pre-line",
flexDirection: "column", margin: 0,
alignItems: "end", fontWeight: "bold",
flexGrow: 1,
}} }}
> >
<Switch Reusable
onChange={(checked) => { </Paragraph>
setFormSetupKey({ <Text type={"secondary"}>
...formSetupKey, Use this type to enroll multiple peers
type: checked ? "reusable" : "one-off", </Text>
}); </Col>
}} <Col span={6}>
/> <Row justify={"end"}>
</Form.Item> <Form.Item
</Row> name="reusable"
)} valuePropName="checked"
</Row> >
<Switch
onChange={(checked) => {
setFormSetupKey({
...formSetupKey,
type: checked ? "reusable" : "one-off",
});
}}
/>
</Form.Item>
</Row>
</Col>
</Row>)}
<Row style={{ marginTop: "28px" }}> {isEditMode && (
<Row style={{marginTop: "20px"}}>
<Paragraph style={{whiteSpace: "pre-line", margin: 0, fontWeight: "bold"}}>
{formSetupKey.type === "one-off" ? "One-off" : "Reusable"}
</Paragraph>
<Text type={"secondary"} style={{marginLeft: "5px"}}>type</Text>
</Row>)}
<Row style={{marginTop: "10px"}}>
<Col span={24}> <Col span={24}>
<Paragraph <Paragraph
style={{ whiteSpace: "pre-line", fontSize: "16px", margin: 0, fontWeight: "600" }} style={{whiteSpace: "pre-line", margin: 0, fontWeight: "bold"}}
> >
{isEditMode ? "Available uses" : "Usage limit"} {isEditMode ? "Available uses" : "Usage limit"}
</Paragraph> </Paragraph>
@@ -433,12 +426,12 @@ const SetupKeyNew = () => {
<Input <Input
disabled disabled
value={formSetupKey.usage_limit} value={formSetupKey.usage_limit}
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />} suffix={<LockOutlined style={{color: "#BFBFBF"}}/>}
style={{ width: "104px" }} style={{width: "104px"}}
/> />
) : ( ) : (
<Form.Item <Form.Item
style={{ marginTop: "5px", width: "112px", marginBottom: "5px" }} style={{marginTop: "5px", width: "112px", marginBottom: "5px"}}
name="usage_limit" name="usage_limit"
> >
<InputNumber <InputNumber
@@ -453,37 +446,37 @@ const SetupKeyNew = () => {
<></> <></>
) : ( ) : (
<Col span={24}> <Col span={24}>
<Text style={{ color: "#818183" }}> <Text type={"secondary"}>
1 usage = 1 peer. E.g., set to 30 if you want to enroll 30 peers For example, set to 30 if you want to enroll 30 peers
</Text> </Text>
</Col> </Col>
)} )}
</Row> </Row>
<Row style={{ marginTop: "20px" }}> <Row style={{marginTop: "15px"}}>
{isEditMode ? ( {isEditMode ? (
<Container style={{ width: "100%", padding: 0, margin: 0 }}> <Container style={{width: "100%", padding: 0, margin: 0}}>
<Row> <Row>
<Col span={11}> <Col span={11}>
<Paragraph style={{ fontSize: "16px", margin: 0, fontWeight: "600" }}> <Paragraph style={{margin: 0, fontWeight: "bold"}}>
Expires Expires
</Paragraph> </Paragraph>
<Row> <Row>
<Input <Input
disabled disabled
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />} suffix={<LockOutlined style={{color: "#BFBFBF"}}/>}
value={customExpiresFormat(new Date(formSetupKey.expires))!} value={customExpiresFormat(new Date(formSetupKey.expires))!}
/> />
</Row> </Row>
</Col> </Col>
<Col span={11} offset={1}> <Col span={11} offset={1}>
<Paragraph style={{ fontSize: "16px", margin: 0, fontWeight: "600" }}> <Paragraph style={{margin: 0, fontWeight: "bold"}}>
Last used Last used
</Paragraph> </Paragraph>
<Row> <Row>
<Input <Input
disabled disabled
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />} suffix={<LockOutlined style={{color: "#BFBFBF"}}/>}
value={customLastUsedFormat(new Date(formSetupKey.last_used))!} value={customLastUsedFormat(new Date(formSetupKey.last_used))!}
/> />
</Row> </Row>
@@ -496,9 +489,8 @@ const SetupKeyNew = () => {
<Paragraph <Paragraph
style={{ style={{
whiteSpace: "pre-line", whiteSpace: "pre-line",
fontSize: "16px",
margin: 0, margin: 0,
fontWeight: "600", fontWeight: "bold",
}} }}
> >
Expires in Expires in
@@ -512,7 +504,7 @@ const SetupKeyNew = () => {
marginBottom: "0px", marginBottom: "0px",
}} }}
name="expiresIn" name="expiresIn"
rules={[{ required: true, message: "Please enter expiration date." }]} rules={[{required: true, message: "Please enter expiration date."}]}
> >
<Col <Col
style={{ style={{
@@ -541,37 +533,37 @@ const SetupKeyNew = () => {
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={24} style={{ marginTop: "5px" }}> <Col span={24} style={{marginTop: "5px"}}>
<Text style={{ color: "#818183" }}>Should be between 1 and 180 days</Text> <Text type={"secondary"}>Should be between 1 and 180 days</Text>
</Col> </Col>
</> </>
)} )}
</Row> </Row>
<Row style={{ marginTop: "20px" }}> <Row style={{marginTop: "20px"}}>
<Col span={24}> <Col span={24}>
<Paragraph <Paragraph
style={{ whiteSpace: "pre-line", fontSize: "16px", margin: 0, fontWeight: "600" }} style={{whiteSpace: "pre-line", margin: 0, fontWeight: "bold"}}
> >
Auto-assigned groups Auto-assigned groups
</Paragraph> </Paragraph>
{isEditMode ? ( {isEditMode ? (
<></> <></>
) : ( ) : (
<Text style={{ color: "#818183" }}> <Text type={"secondary"}>
These groups will be automatically assigned to peers enrolled with this key These groups will be automatically assigned to peers enrolled with this key
</Text> </Text>
)} )}
</Col> </Col>
<Col span={24}> <Col span={24}>
<Form.Item <Form.Item
style={{ marginTop: "5px", marginBottom: 0 }} style={{marginTop: "5px", marginBottom: 0}}
name="autoGroupNames" name="autoGroupNames"
rules={[{ validator: selectValidator }]} rules={[{validator: selectValidator}]}
> >
<Select <Select
mode="tags" mode="tags"
style={{ width: "100%" }} style={{width: "100%"}}
placeholder="Associate groups with the key" placeholder="Associate groups with the key"
tagRender={tagRender} tagRender={tagRender}
dropdownRender={dropDownRender} dropdownRender={dropDownRender}
@@ -585,17 +577,17 @@ const SetupKeyNew = () => {
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
<Row style={{ marginTop: "40px", marginBottom: "28px" }}> <Row style={{marginTop: "40px", marginBottom: "28px"}}>
<Text style={{ color: "#818183" }}> <Text type={"secondary"}>
Learn more about Learn more about
<a target="_blank" rel="noreferrer" href="https://netbird.io/docs/overview/setup-keys"> <a target="_blank" rel="noreferrer" href="https://netbird.io/docs/overview/setup-keys">
{" "} {" "}
Setup Keys setup keys
</a> </a>
</Text> </Text>
</Row> </Row>
</Container> </Form>
</Form> </Container>
</Modal> </Modal>
); );
}; };
+110 -54
View File
@@ -1,7 +1,7 @@
import { import {
Badge, Badge,
Breadcrumb, Breadcrumb,
Button, Button, Card,
Col, Col,
Divider, Divider,
Form, Form,
@@ -33,6 +33,7 @@ import Column from "antd/lib/table/Column";
import {useOidcUser} from "@axa-fr/react-oidc"; import {useOidcUser} from "@axa-fr/react-oidc";
const {Option} = Select; const {Option} = Select;
const {Meta} = Card;
const {Title, Paragraph, Text} = Typography; const {Title, Paragraph, Text} = Typography;
interface TokenDataTable extends PersonalAccessToken { interface TokenDataTable extends PersonalAccessToken {
@@ -208,14 +209,15 @@ const UserEdit = () => {
} }
const transformTokenTable = (d: PersonalAccessToken[]): TokenDataTable[] => { const transformTokenTable = (d: PersonalAccessToken[]): TokenDataTable[] => {
if(!d) { if (!d) {
return [] return []
} }
return d.map(p => ({ return d.map(p => ({
key: p.id, key: p.id,
status: Date.parse(p.expiration_date) > Date.now() ? "valid" : "expired", status: Date.parse(p.expiration_date) > Date.now() ? "valid" : "expired",
created_by_email: getEmail(p), created_by_email: getEmail(p),
...p} as TokenDataTable)) ...p
} as TokenDataTable))
} }
const getEmail = (token: PersonalAccessToken): string => { const getEmail = (token: PersonalAccessToken): string => {
@@ -271,8 +273,10 @@ const UserEdit = () => {
useEffect(() => { useEffect(() => {
if (user.is_current || user.is_service_user) { if (user.is_current || user.is_service_user) {
dispatch(personalAccessTokenActions.getPersonalAccessTokens.request({getAccessTokenSilently: getTokenSilently, dispatch(personalAccessTokenActions.getPersonalAccessTokens.request({
payload: user.id})) getAccessTokenSilently: getTokenSilently,
payload: user.id
}))
} }
}, [user]) }, [user])
@@ -327,9 +331,14 @@ const UserEdit = () => {
}, },
]} ]}
/> />
<Container style={{backgroundColor: "white", padding: "20px", borderRadius: "4px", boxSizing: "border-box", border: "0.5px solid #D9D9D9", marginBottom: "7px"}}>
<Card
bordered={true}
title={user.name}
loading={loading}
style={{marginBottom: "7px"}}
>
<div style={{maxWidth: "800px"}}> <div style={{maxWidth: "800px"}}>
<Paragraph style={{textAlign: "left", whiteSpace: "pre-line", fontSize: "1.5em"}}>{user.name}</Paragraph>
<Form layout="vertical" hideRequiredMark form={form} <Form layout="vertical" hideRequiredMark form={form}
initialValues={{ initialValues={{
name: formUser.name, name: formUser.name,
@@ -338,24 +347,25 @@ const UserEdit = () => {
autoGroupsNames: formUser.autoGroupsNames, autoGroupsNames: formUser.autoGroupsNames,
}} }}
> >
<Row style={{ paddingBottom: "15px"}}> <Row style={{paddingBottom: "15px"}}>
{!user.is_service_user && <Col xs={24} sm={24} md={11} lg={11} xl={11} xxl={11} span={11}> {!user.is_service_user &&
<Form.Item <Col xs={24} sm={24} md={11} lg={11} xl={11} xxl={11} span={11}>
name="email" <Form.Item
label={<Text style={{fontSize: "16px", fontWeight: "500"}}>Email</Text>} name="email"
style={{marginRight: "70px"}} label={<Text style={{}}>Email</Text>}
> style={{marginRight: "70px"}}
<Input >
disabled={user.id} <Input
value={formUser.email} disabled={user.id}
style={{color: "#5a5c5a"}} value={formUser.email}
autoComplete="off"/> style={{color: "#5a5c5a"}}
</Form.Item> autoComplete="off"/>
</Col>} </Form.Item>
</Col>}
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}> <Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
<Form.Item <Form.Item
name="role" name="role"
label={<Text style={{fontSize: "16px", fontWeight: "500"}}>Role</Text>} label={<Text style={{}}>Role</Text>}
style={{marginRight: "50px"}} style={{marginRight: "50px"}}
> >
<Select style={{width: '100%'}} <Select style={{width: '100%'}}
@@ -366,11 +376,11 @@ const UserEdit = () => {
</Form.Item> </Form.Item>
</Col> </Col>
</Row> </Row>
{!user.is_service_user && <Row style={{ paddingBottom: "15px"}}> {!user.is_service_user && <Row style={{paddingBottom: "15px"}}>
<Col span={9}> <Col span={9}>
<Form.Item <Form.Item
name="autoGroupsNames" name="autoGroupsNames"
label={<Text style={{fontSize: "16px", fontWeight: "500"}}>Auto-assigned groups</Text>} label={<Text style={{}}>Auto-assigned groups</Text>}
tooltip="Every peer enrolled with this user will be automatically added to these groups" tooltip="Every peer enrolled with this user will be automatically added to these groups"
rules={[{validator: selectValidator}]} rules={[{validator: selectValidator}]}
> >
@@ -397,16 +407,27 @@ const UserEdit = () => {
</Space> </Space>
</Form> </Form>
</div> </div>
</Container> </Card>
{user && (user.is_current || user.is_service_user) && <Container style={{backgroundColor: "white", padding: "20px", borderRadius: "4px", boxSizing: "border-box", border: "0.5px solid #D9D9D9"}}>
{user && (user.is_current || user.is_service_user) && <Card
bordered={true}
loading={loading}
style={{marginBottom: "7px"}}
>
<div style={{maxWidth: "800px"}}> <div style={{maxWidth: "800px"}}>
<Paragraph style={{textAlign: "left", whiteSpace: "pre-line", fontSize: "1.5em"}}>Access tokens</Paragraph> <Paragraph
<Row gutter={21} style={{marginTop: "-22px", marginBottom: "10px"}}> style={{textAlign: "left", whiteSpace: "pre-line", fontSize: "16px", fontWeight: "bold"}}>Access
tokens</Paragraph>
<Row gutter={21} style={{marginTop: "-16px", marginBottom: "10px"}}>
<Col xs={24} sm={24} md={20} lg={20} xl={20} xxl={20} span={20}> <Col xs={24} sm={24} md={20} lg={20} xl={20} xxl={20} span={20}>
<Paragraph type={"secondary"} style={{textAlign: "left", whiteSpace: "pre-line"}}>Access tokens give access to the Netbird API</Paragraph> <Paragraph type={"secondary"}
style={{textAlign: "left", whiteSpace: "pre-line"}}>
Access tokens give access to NetBird API</Paragraph>
</Col> </Col>
<Col xs={24} sm={24} md={1} lg={1} xl={1} xxl={1} span={1} style={{marginTop: "-16px"}}> <Col xs={24} sm={24} md={1} lg={1} xl={1} xxl={1} span={1} style={{marginTop: "-16px"}}>
{personalAccessTokens && personalAccessTokens.length > 0 && <Button type="primary" onClick={onClickAddNewPersonalAccessToken}>Create Token</Button>} {personalAccessTokens && personalAccessTokens.length > 0 &&
<Button type="primary" onClick={onClickAddNewPersonalAccessToken}>Create
token</Button>}
</Col> </Col>
</Row> </Row>
{personalAccessTokens && personalAccessTokens.length > 0 && {personalAccessTokens && personalAccessTokens.length > 0 &&
@@ -418,34 +439,62 @@ const UserEdit = () => {
pagination={false} pagination={false}
loading={tableSpin(loading)} loading={tableSpin(loading)}
dataSource={tokenTable}> dataSource={tokenTable}>
<Column className={"non-highlighted-table-column"} sorter={(a, b) => ((a as TokenDataTable).created_at.localeCompare((b as TokenDataTable).created_at))} <Column className={"non-highlighted-table-column"}
sorter={(a, b) => ((a as TokenDataTable).created_at.localeCompare((b as TokenDataTable).created_at))}
defaultSortOrder='descend' defaultSortOrder='descend'
render={(text, record, index) => { render={(text, record, index) => {
return (<> return (<>
<Row> <Row>
<Col> <Col>
<Badge status={(record as TokenDataTable).status === "valid" ? "success" : "error"} style={{marginTop: "1px", marginRight: "5px", marginLeft: "0px"}}/> <Badge
status={(record as TokenDataTable).status === "valid" ? "success" : "error"}
style={{
marginTop: "1px",
marginRight: "5px",
marginLeft: "0px"
}}/>
</Col> </Col>
<Col> <Col>
<Paragraph style={{fontSize: "16px", fontWeight: "500", margin: "0px", padding: "0px"}}>{(record as TokenDataTable).name}</Paragraph> <Paragraph style={{
<Paragraph type={"secondary"} style={{fontSize: "13px", fontWeight: "400", margin: "0px", marginTop: "-2px", padding: "0px"}}>{"Created" + ((record as TokenDataTable).created_by_email && user.is_service_user ? " by " + (record as TokenDataTable).created_by_email : "") + " on " + fullDate((record as TokenDataTable).created_at)}</Paragraph> margin: "0px",
padding: "0px"
}}>{(record as TokenDataTable).name}</Paragraph>
<Paragraph type={"secondary"} style={{
fontSize: "13px",
fontWeight: "400",
margin: "0px",
marginTop: "-2px",
padding: "0px"
}}>{"Created" + ((record as TokenDataTable).created_by_email && user.is_service_user ? " by " + (record as TokenDataTable).created_by_email : "") + " on " + fullDate((record as TokenDataTable).created_at)}</Paragraph>
</Col> </Col>
</Row> </Row>
</>) </>)
}}/> }}/>
<Column render={(text, record, index) => { <Column render={(text, record, index) => {
return <> return <>
<Paragraph type={"secondary"} style={{textAlign: "left", fontSize: "11px"}}>Expires on</Paragraph> <Paragraph type={"secondary"} style={{textAlign: "left", fontSize: "11px"}}>Expires
<Paragraph type={"secondary"} style={{textAlign: "left", marginTop: "-10px", marginBottom: "0", fontSize: "15px"}}>{fullDate((record as TokenDataTable).expiration_date)}</Paragraph> on</Paragraph>
</> <Paragraph type={"secondary"} style={{
}} textAlign: "left",
marginTop: "-10px",
marginBottom: "0",
fontSize: "15px"
}}>{fullDate((record as TokenDataTable).expiration_date)}</Paragraph>
</>
}}
/> />
<Column render={(text, record, index) => { <Column render={(text, record, index) => {
return <> return <>
<Paragraph type={"secondary"} style={{textAlign: "left", fontSize: "11px"}}>Last used</Paragraph> <Paragraph type={"secondary"} style={{textAlign: "left", fontSize: "11px"}}>Last
<Paragraph type={"secondary"} style={{textAlign: "left", marginTop: "-10px", marginBottom: "0", fontSize: "15px"}}>{(record as TokenDataTable).last_used ? fullDate((record as TokenDataTable).last_used) : "Never"}</Paragraph> used</Paragraph>
</> <Paragraph type={"secondary"} style={{
}} textAlign: "left",
marginTop: "-10px",
marginBottom: "0",
fontSize: "15px"
}}>{(record as TokenDataTable).last_used ? fullDate((record as TokenDataTable).last_used) : "Never"}</Paragraph>
</>
}}
/> />
<Column align="right" <Column align="right"
render={(text, record, index) => { render={(text, record, index) => {
@@ -460,16 +509,23 @@ const UserEdit = () => {
/> />
</Table>} </Table>}
<Divider style={{marginTop: "-12px"}}></Divider> <Divider style={{marginTop: "-12px"}}></Divider>
{(personalAccessTokens === null || personalAccessTokens.length === 0) && <Space direction="vertical" size="small" align="start" {(personalAccessTokens === null || personalAccessTokens.length === 0) &&
style={{display: 'flex', padding: '45px 0px', marginTop: "-40px", justifyContent: 'center'}}> <Space direction="vertical" size="small" align="start"
<Paragraph style={{
style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "16px"}}> display: 'flex',
You don’t have any access tokens yet. padding: '35px 0px',
</Paragraph> marginTop: "-40px",
<Button type="primary" onClick={onClickAddNewPersonalAccessToken}>Create Token</Button> justifyContent: 'center'
</Space>} }}>
<Paragraph
style={{textAlign: "start", whiteSpace: "pre-line"}}>
You don’t have any access tokens yet
</Paragraph>
<Button type="primary" onClick={onClickAddNewPersonalAccessToken}>Create token</Button>
</Space>}
</div> </div>
</Container>}
</Card>}
</div> </div>
<AddPATPopup/> <AddPATPopup/>
{confirmModalContextHolder} {confirmModalContextHolder}
+12 -14
View File
@@ -130,27 +130,25 @@ const AddPATPopup = () => {
} }
width={460} width={460}
> >
<Container style={{textAlign: "start"}}> <Container style={{textAlign: "start", marginLeft: "-15px", marginRight: "-15px"}}>
<Paragraph <Paragraph
style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px", fontWeight: "500"}}> style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px"}}>
{showPlainToken ? "Token created successfully!" : "Create a Personal Access Token"} {showPlainToken ? "Token created successfully!" : "Create token"}
</Paragraph> </Paragraph>
{!showPlainToken && <Paragraph type={"secondary"} {!showPlainToken && <Paragraph type={"secondary"}
style={{ style={{
textAlign: "start", textAlign: "start",
fontSize: "14px",
whiteSpace: "pre-line", whiteSpace: "pre-line",
marginTop: "-23px", marginTop: "-23px",
paddingBottom: "25px", paddingBottom: "25px",
}}> }}>
{"This token can be used to authenticate against" + "\n" + "NetBird's Public API."} {"Use this token to access NetBird's public API"}
</Paragraph>} </Paragraph>}
{showPlainToken && <Paragraph type={"secondary"} style={{ {showPlainToken && <Paragraph type={"secondary"} style={{
textAlign: "start", textAlign: "start",
fontSize: "14px",
whiteSpace: "pre-line", whiteSpace: "pre-line",
marginTop: "40px", marginTop: "25px",
}}>{"This token will not be shown again, so be sure to copy it and" + "\n" + "store in a secure location."}</Paragraph>} }}>{"This token won't be shown again, so be sure to copy and store it in a secure location"}</Paragraph>}
{!showPlainToken && <Form layout="vertical" hideRequiredMark form={form} {!showPlainToken && <Form layout="vertical" hideRequiredMark form={form}
initialValues={{ initialValues={{
expires_in: ExpiresInDefault, expires_in: ExpiresInDefault,
@@ -160,14 +158,14 @@ const AddPATPopup = () => {
<Col span={24}> <Col span={24}>
<Row align="top"> <Row align="top">
<Col flex="auto"> <Col flex="auto">
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "-8px"}}>Token name</Paragraph> <Paragraph style={{fontWeight: "bold", marginTop: "-10px"}}>Name</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Create a name to identify the token easily</Paragraph> <Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Set an easily identifiable name for your token</Paragraph>
<Form.Item <Form.Item
name="name" name="name"
style={{marginTop: "-10px"}} style={{marginTop: "-10px"}}
rules={[{ rules={[{
required: true, required: true,
message: 'Please add a name for this personal access token', message: 'Please add a name for this token',
whitespace: true whitespace: true
}]} }]}
> >
@@ -179,9 +177,9 @@ const AddPATPopup = () => {
</Col> </Col>
</Row> </Row>
</Col> </Col>
<Col span={24} style={{textAlign: "left"}}> <Col span={24} style={{textAlign: "left", marginTop: "10px"}}>
<Paragraph style={{fontSize: "16px", fontWeight: "500"}}>Expires in</Paragraph> <Paragraph style={{fontWeight: "bold", marginTop: "-10px"}}>Expires in</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Number of days this token is valid for</Paragraph> <Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Number of days this token will be valid for</Paragraph>
<Form.Item <Form.Item
name="expires_in" name="expires_in"
style={{marginTop: "-10px"}} style={{marginTop: "-10px"}}
+11 -11
View File
@@ -199,10 +199,10 @@ const AddServiceUserPopup = () => {
} }
width={460} width={460}
> >
<Container style={{textAlign: "start"}}> <Container style={{textAlign: "start", marginLeft: "-15px", marginRight: "-15px"}}>
<Paragraph <Paragraph
style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px", fontWeight: "500"}}> style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px"}}>
{"Add Service User"} {"Add service user"}
</Paragraph> </Paragraph>
<Paragraph type={"secondary"} <Paragraph type={"secondary"}
style={{ style={{
@@ -211,7 +211,7 @@ const AddServiceUserPopup = () => {
marginTop: "-23px", marginTop: "-23px",
paddingBottom: "25px", paddingBottom: "25px",
}}> }}>
{"Service Users are non-login users that are not associated with any specific person."} {"Service users are non-login users that are not associated with any specific person."}
</Paragraph> </Paragraph>
<Form layout="vertical" hideRequiredMark form={form} <Form layout="vertical" hideRequiredMark form={form}
initialValues={{ initialValues={{
@@ -220,8 +220,8 @@ const AddServiceUserPopup = () => {
> >
<Row gutter={16}> <Row gutter={16}>
<Col span={24}> <Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "-10px"}}>Name</Paragraph> <Paragraph style={{fontWeight: "bold", marginTop: "-10px"}}>Name</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Set a name to easily identify the user</Paragraph> <Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Set a name to easily identify the user</Paragraph>
<Form.Item <Form.Item
name="name" name="name"
rules={[{ rules={[{
@@ -232,14 +232,14 @@ const AddServiceUserPopup = () => {
style={{marginTop: "-8px"}} style={{marginTop: "-8px"}}
> >
<Input <Input
placeholder={'for example "Ansible User"'} placeholder={'for example "Ansible user"'}
ref={inputNameRef} ref={inputNameRef}
autoComplete="off"/> autoComplete="off"/>
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={24}> <Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "0px"}}>Role</Paragraph> <Paragraph style={{fontWeight: "bold", marginTop: "0px"}}>Role</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Set a role for the user to assign dashboard access permissions</Paragraph> <Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-15px"}}>Set a role for the user to assign access permissions</Paragraph>
<Form.Item <Form.Item
name="role" name="role"
rules={[{ rules={[{
@@ -256,8 +256,8 @@ const AddServiceUserPopup = () => {
</Form.Item> </Form.Item>
</Col> </Col>
{/*<Col span={24}>*/} {/*<Col span={24}>*/}
{/* <Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "0px"}}>Auto-assigned groups</Paragraph>*/} {/* <Paragraph style={{fontWeight: "bold", marginTop: "0px"}}>Auto-assigned groups</Paragraph>*/}
{/* <Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Add groups, that will be assigned to peers added by this user</Paragraph>*/} {/* <Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-15px"}}>Add groups, that will be assigned to peers added by this user</Paragraph>*/}
{/* <Form.Item*/} {/* <Form.Item*/}
{/* name="autoGroupsNames"*/} {/* name="autoGroupsNames"*/}
{/* label="Auto-assigned groups"*/} {/* label="Auto-assigned groups"*/}
+10 -12
View File
@@ -12,7 +12,6 @@ import {
Typography Typography
} from "antd"; } from "antd";
import {Container} from "../Container"; import {Container} from "../Container";
import {CloseOutlined} from "@ant-design/icons";
import React, {useEffect, useRef, useState} from "react"; import React, {useEffect, useRef, useState} from "react";
import {useDispatch, useSelector} from "react-redux"; import {useDispatch, useSelector} from "react-redux";
import {RootState} from "typesafe-actions"; import {RootState} from "typesafe-actions";
@@ -20,7 +19,6 @@ import {useGetTokenSilently} from "../../utils/token";
import {actions as userActions} from "../../store/user"; import {actions as userActions} from "../../store/user";
import {actions as groupActions} from "../../store/group"; import {actions as groupActions} from "../../store/group";
import {User, UserToSave} from "../../store/user/types"; import {User, UserToSave} from "../../store/user/types";
import {Header} from "antd/es/layout/layout";
import {RuleObject} from "antd/lib/form"; import {RuleObject} from "antd/lib/form";
import {CustomTagProps} from "rc-select/lib/BaseSelect"; import {CustomTagProps} from "rc-select/lib/BaseSelect";
@@ -200,10 +198,10 @@ const InviteUserPopup = () => {
} }
width={460} width={460}
> >
<Container style={{textAlign: "start"}}> <Container style={{textAlign: "start", marginLeft: "-15px", marginRight: "-15px"}}>
<Paragraph <Paragraph
style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px", fontWeight: "500"}}> style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px", fontWeight: "500"}}>
{"Invite User"} {"Invite user"}
</Paragraph> </Paragraph>
<Paragraph type={"secondary"} <Paragraph type={"secondary"}
style={{ style={{
@@ -222,8 +220,8 @@ const InviteUserPopup = () => {
> >
<Row gutter={16}> <Row gutter={16}>
<Col span={24}> <Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "-10px"}}>Name</Paragraph> <Paragraph style={{fontWeight: "bold", marginTop: "-10px"}}>Name</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Set a name to easily identify the user</Paragraph> <Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Set a name to easily identify the user</Paragraph>
<Form.Item <Form.Item
name="name" name="name"
rules={[{ rules={[{
@@ -240,8 +238,8 @@ const InviteUserPopup = () => {
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={24}> <Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "0px"}}>Email</Paragraph> <Paragraph style={{ fontWeight: "bold", marginTop: "0px"}}>Email</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Provide the email address of the user</Paragraph> <Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Provide the email address of the user</Paragraph>
<Form.Item <Form.Item
name="email" name="email"
rules={[{ rules={[{
@@ -259,8 +257,8 @@ const InviteUserPopup = () => {
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={24}> <Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "0px"}}>Role</Paragraph> <Paragraph style={{ fontWeight: "bold", marginTop: "0px"}}>Role</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Set a role for the user to assign dashboard access permissions</Paragraph> <Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Set a role for the user to assign access permissions</Paragraph>
<Form.Item <Form.Item
name="role" name="role"
rules={[{ rules={[{
@@ -277,8 +275,8 @@ const InviteUserPopup = () => {
</Form.Item> </Form.Item>
</Col> </Col>
<Col span={24}> <Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "0px"}}>Auto-assigned groups</Paragraph> <Paragraph style={{fontWeight: "bold", marginTop: "0px"}}>Auto-assigned groups</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Add groups, that will be assigned to peers added by this user</Paragraph> <Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Add groups, that will be assigned to peers added by this user</Paragraph>
<Form.Item <Form.Item
name="autoGroupsNames" name="autoGroupsNames"
tooltip="Every peer enrolled with this user will be automatically added to these groups" tooltip="Every peer enrolled with this user will be automatically added to these groups"
+5 -5
View File
@@ -372,7 +372,7 @@ export const SetupKeys = () => {
<Row justify="end"> <Row justify="end">
<Col> <Col>
<Button type="primary" onClick={onClickAddNewSetupKey}> <Button type="primary" onClick={onClickAddNewSetupKey}>
Add Key Add key
</Button> </Button>
</Col> </Col>
</Row> </Row>
@@ -418,7 +418,7 @@ export const SetupKeys = () => {
color: "#252526", color: "#252526",
}} }}
> >
Create Setup Key Create setup key
</Text> </Text>
</Col> </Col>
<Col style={{ marginTop: "17px" }}> <Col style={{ marginTop: "17px" }}>
@@ -429,8 +429,8 @@ export const SetupKeys = () => {
lineHeight: "22px", lineHeight: "22px",
}} }}
> >
Manage Setup Keys to register new machines in your network. The key Manage setup keys to register new machines in your network. The key
links the machine to an account during initial setup. links machines to your account during initial setup.
<a <a
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
@@ -457,7 +457,7 @@ export const SetupKeys = () => {
}} }}
onClick={onClickAddNewSetupKey} onClick={onClickAddNewSetupKey}
> >
Add Key Add key
</Button> </Button>
</Col> </Col>
</Container> </Container>