Compare commits

...
12 Commits
Author SHA1 Message Date
pascal-fischer 67fd2fcb2e Update links to docs (#182) 2023-05-24 17:31:57 +02:00
Misha Bragin f4933e45ee Add peer on Android (#185) 2023-05-19 21:42:13 +02:00
Misha Bragin 331dd2b429 Make it more visible that user can be blocked (#184) 2023-05-19 12:40:08 +02:00
Misha Bragin 3a8106c1e7 Track block/unblock user activity (#181) 2023-05-17 09:53:46 +02:00
Misha Bragin b595e0d6a8 Switch to activate/deactivate a user (#179)
This PR adds a switch to deactivate (or block) a user.
Only admins can block/unblock users.
Users can't block themselves.
2023-05-15 16:57:35 +02:00
pascal-fischer 33621cae5d remove href- from breadcrumbs (#180) 2023-05-15 14:28:14 +02:00
Maycon Santos 360d807008 Enable creating service user for all domains (#178)
Removed unnecessary check from create button.
2023-05-14 11:56:14 +02:00
Misha Bragin 6f8897ffa5 Make breadcrumbs look like links (#176) 2023-05-10 18:48:11 +02:00
pascal-fischer 75d5f804c5 fix dropdown button in lists to only show ellipsis (#175) 2023-05-10 16:45:47 +02:00
pascal-fischer f7cac02a2d reduce api calls on user edit (#174) 2023-05-10 16:44:43 +02:00
Misha Bragin ec40730cb2 Fix setup key layout (#172) 2023-05-08 17:49:27 +02:00
Misha Bragin 7f3648861b Fix popups layout (#171) 2023-05-08 12:30:53 +02:00
26 changed files with 622 additions and 463 deletions

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

+1 -1
View File
@@ -408,7 +408,7 @@ const AccessControlNew = () => {
<Col span={24}>
<Divider></Divider>
<Button icon={<QuestionCircleFilled/>} type="link" target="_blank"
href="https://docs.netbird.io/docs/overview/acls">Learn more about access controls</Button>
href="https://docs.netbird.io/how-to/manage-network-access">Learn more about access controls</Button>
</Col>
</Row>
</Form>
+1 -1
View File
@@ -22,7 +22,7 @@ const Banner = () => {
const linkLearnMore = () => {
return (
<a
href="https://netbird.io/docs/how-to-guides/nameservers"
href="https://docs.netbird.io/how-to/manage-dns-in-your-network"
className="font-bold underline"
target="_blank"
rel="noreferrer"
+1 -1
View File
@@ -604,7 +604,7 @@ const NameServerGroupUpdate = () => {
<Col span={24}>
<Divider></Divider>
<Button icon={<QuestionCircleFilled/>} type="link" target="_blank"
href="https://netbird.io/docs/how-to-guides/nameservers">Learn more about nameservers</Button>
href="https://docs.netbird.io/how-to/manage-dns-in-your-network">Learn more about nameservers</Button>
</Col>
</Row>
</Form>) :
+1 -1
View File
@@ -458,7 +458,7 @@ const RouteUpdate = () => {
<Col span={24}>
<Divider></Divider>
<Button icon={<QuestionCircleFilled/>} type="link" target="_blank"
href="https://netbird.io/docs/how-to-guides/network-routes">Learn more about network routes</Button>
href="https://docs.netbird.io/how-to/routing-traffic-to-private-networks">Learn more about network routes</Button>
</Col>
</Row>
</Form>
File diff suppressed because it is too large. Load diff
+161 -107
View File
@@ -1,7 +1,7 @@
import {
Badge,
Breadcrumb,
Button,
Button, Card,
Col,
Divider,
Form,
@@ -10,7 +10,7 @@ import {
Row,
Select,
Skeleton,
Space, Table,
Space, Switch, Table,
Tag, Typography
} from "antd";
import {useDispatch, useSelector} from "react-redux";
@@ -33,6 +33,7 @@ import Column from "antd/lib/table/Column";
import {useOidcUser} from "@axa-fr/react-oidc";
const {Option} = Select;
const {Meta} = Card;
const {Title, Paragraph, Text} = Typography;
interface TokenDataTable extends PersonalAccessToken {
@@ -62,6 +63,7 @@ const UserEdit = () => {
const [formUser, setFormUser] = useState({} as FormUser)
const [form] = Form.useForm()
const [isAdmin, setIsAdmin] = useState(false);
const [confirmModal, confirmModalContextHolder] = Modal.useModal();
@@ -86,10 +88,20 @@ const UserEdit = () => {
name: values.name,
groupsToCreate: groupsToCreate,
auto_groups: autoGroups,
is_service_user: isServiceUser
is_service_user: isServiceUser,
is_blocked: values.is_blocked
} as UserToSave
}
useEffect(() => {
if(users) {
let currentUser = users.find((user) => user.is_current)
if(currentUser) {
setIsAdmin(currentUser.role === "admin");
}
}
}, [users])
const handleFormSubmit = () => {
form.validateFields()
.then((values) => {
@@ -101,18 +113,6 @@ const UserEdit = () => {
dispatch(userActions.setEditUserPopupVisible(false));
dispatch(userActions.setUser(null as unknown as User))
dispatch(personalAccessTokenActions.resetPersonalAccessTokens(null))
dispatch(groupActions.getGroups.request({
getAccessTokenSilently: getTokenSilently,
payload: null
}));
dispatch(userActions.getServiceUsers.request({
getAccessTokenSilently: getTokenSilently,
payload: null
}))
dispatch(userActions.getUsers.request({
getAccessTokenSilently: getTokenSilently,
payload: null
}))
})
.catch((errorInfo) => {
console.log('errorInfo', errorInfo)
@@ -208,14 +208,15 @@ const UserEdit = () => {
}
const transformTokenTable = (d: PersonalAccessToken[]): TokenDataTable[] => {
if(!d) {
if (!d) {
return []
}
return d.map(p => ({
key: p.id,
status: Date.parse(p.expiration_date) > Date.now() ? "valid" : "expired",
created_by_email: getEmail(p),
...p} as TokenDataTable))
...p
} as TokenDataTable))
}
const getEmail = (token: PersonalAccessToken): string => {
@@ -271,8 +272,10 @@ const UserEdit = () => {
useEffect(() => {
if (user.is_current || user.is_service_user) {
dispatch(personalAccessTokenActions.getPersonalAccessTokens.request({getAccessTokenSilently: getTokenSilently,
payload: user.id}))
dispatch(personalAccessTokenActions.getPersonalAccessTokens.request({
getAccessTokenSilently: getTokenSilently,
payload: user.id
}))
}
}, [user])
@@ -282,29 +285,12 @@ const UserEdit = () => {
name: user.name,
role: user.role,
email: user.email,
is_blocked: user.is_blocked,
autoGroupsNames: currentGroups,
})
}
}, [form, user, currentGroups])
const menuItems = [
{
key: '1',
label: (
<Text onClick={() => onBreadcrumbUsersClick("Users")}>
Users
</Text>
),
},
{
key: '2',
label: (
<Text onClick={() => onBreadcrumbUsersClick("Service Users")}>
Service Users
</Text>
),
},
];
const isUserAdmin = (userId: string): boolean => {
return users.find(u => u.id === userId)?.role === "admin"
@@ -316,10 +302,10 @@ const UserEdit = () => {
<Breadcrumb style={{marginBottom: "30px"}}
items={[
{
title: <Text onClick={() => onBreadcrumbUsersClick("Users")}>All Users</Text>,
title: <a onClick={() => onBreadcrumbUsersClick("Users")}>All Users</a>,
},
{
title: <Text onClick={() => onBreadcrumbUsersClick(tab)}>{tab}</Text>,
title: <a onClick={() => onBreadcrumbUsersClick(tab)}>{tab}</a>,
// menu: { items: menuItems },
},
{
@@ -327,35 +313,42 @@ 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"}}>
<Paragraph style={{textAlign: "left", whiteSpace: "pre-line", fontSize: "1.5em"}}>{user.name}</Paragraph>
<Form layout="vertical" hideRequiredMark form={form}
initialValues={{
name: formUser.name,
role: formUser.role,
email: formUser.email,
is_blocked: formUser.is_blocked,
autoGroupsNames: formUser.autoGroupsNames,
}}
>
<Row style={{ paddingBottom: "15px"}}>
{!user.is_service_user && <Col xs={24} sm={24} md={11} lg={11} xl={11} xxl={11} span={11}>
<Form.Item
name="email"
label={<Text style={{fontSize: "16px", fontWeight: "500"}}>Email</Text>}
style={{marginRight: "70px"}}
>
<Input
disabled={user.id}
value={formUser.email}
style={{color: "#5a5c5a"}}
autoComplete="off"/>
</Form.Item>
</Col>}
<Row style={{paddingBottom: "15px"}}>
{!user.is_service_user &&
<Col xs={24} sm={24} md={11} lg={11} xl={11} xxl={11} span={11}>
<Form.Item
name="email"
label={<Text style={{}}>Email</Text>}
style={{marginRight: "70px"}}
>
<Input
disabled={user.id}
value={formUser.email}
style={{color: "#5a5c5a"}}
autoComplete="off"/>
</Form.Item>
</Col>}
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
<Form.Item
name="role"
label={<Text style={{fontSize: "16px", fontWeight: "500"}}>Role</Text>}
label={<Text style={{}}>Role</Text>}
style={{marginRight: "50px"}}
>
<Select style={{width: '100%'}}
@@ -366,30 +359,45 @@ const UserEdit = () => {
</Form.Item>
</Col>
</Row>
{!user.is_service_user && <Row style={{ paddingBottom: "15px"}}>
<Col span={9}>
<Form.Item
name="autoGroupsNames"
label={<Text style={{fontSize: "16px", fontWeight: "500"}}>Auto-assigned groups</Text>}
tooltip="Every peer enrolled with this user will be automatically added to these groups"
rules={[{validator: selectValidator}]}
>
<Select mode="tags"
style={{width: '100%'}}
placeholder="Associate groups with the user"
tagRender={tagRender}
dropdownRender={dropDownRender}
disabled={oidcUser && !isUserAdmin(oidcUser.sub)}
{!user.is_service_user && <Row style={{paddingBottom: "15px"}}>
<Col xs={24} sm={24} md={11} lg={11} xl={11} xxl={11} span={11}>
<Form.Item
name="autoGroupsNames"
label={<Text style={{}}>Auto-assigned groups</Text>}
tooltip="Every peer enrolled with this user will be automatically added to these groups"
rules={[{validator: selectValidator}]}
style={{marginRight: "70px"}}
>
{
tagGroups.map(m =>
<Option key={m}>{optionRender(m)}</Option>
)
}
</Select>
<Select mode="tags"
placeholder="Associate groups with the user"
tagRender={tagRender}
dropdownRender={dropDownRender}
disabled={oidcUser && !isUserAdmin(oidcUser.sub)}
>
{
tagGroups.map(m =>
<Option key={m}>{optionRender(m)}</Option>
)
}
</Select>
</Form.Item>
</Col>
{!user.is_current && isAdmin && (
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
<Form.Item
valuePropName="checked"
name="is_blocked"
label="Block user"
style={{marginRight: "50px"}}
>
<Switch/>
</Form.Item>
</Col>
</Col>)}
</Row>}
<Space style={{display: 'flex', justifyContent: 'start'}}>
<Button disabled={loading} onClick={onCancel}>Cancel</Button>
<Button type="primary"
@@ -397,16 +405,27 @@ const UserEdit = () => {
</Space>
</Form>
</div>
</Container>
{user && (user.is_current || user.is_service_user) && <Container style={{backgroundColor: "white", padding: "20px", borderRadius: "4px", boxSizing: "border-box", border: "0.5px solid #D9D9D9"}}>
</Card>
{user && (user.is_current || user.is_service_user) && <Card
bordered={true}
loading={loading}
style={{marginBottom: "7px"}}
>
<div style={{maxWidth: "800px"}}>
<Paragraph style={{textAlign: "left", whiteSpace: "pre-line", fontSize: "1.5em"}}>Access tokens</Paragraph>
<Row gutter={21} style={{marginTop: "-22px", marginBottom: "10px"}}>
<Paragraph
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}>
<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 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>
</Row>
{personalAccessTokens && personalAccessTokens.length > 0 &&
@@ -418,34 +437,62 @@ const UserEdit = () => {
pagination={false}
loading={tableSpin(loading)}
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'
render={(text, record, index) => {
return (<>
<Row>
<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>
<Paragraph style={{fontSize: "16px", fontWeight: "500", 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>
<Paragraph style={{
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>
</Row>
</>)
</>)
}}/>
<Column render={(text, record, index) => {
return <>
<Paragraph type={"secondary"} style={{textAlign: "left", fontSize: "11px"}}>Expires on</Paragraph>
<Paragraph type={"secondary"} style={{textAlign: "left", marginTop: "-10px", marginBottom: "0", fontSize: "15px"}}>{fullDate((record as TokenDataTable).expiration_date)}</Paragraph>
</>
}}
return <>
<Paragraph type={"secondary"} style={{textAlign: "left", fontSize: "11px"}}>Expires
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) => {
return <>
<Paragraph type={"secondary"} style={{textAlign: "left", fontSize: "11px"}}>Last 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>
</>
}}
return <>
<Paragraph type={"secondary"} style={{textAlign: "left", fontSize: "11px"}}>Last
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"
render={(text, record, index) => {
@@ -460,16 +507,23 @@ const UserEdit = () => {
/>
</Table>}
<Divider style={{marginTop: "-12px"}}></Divider>
{(personalAccessTokens === null || personalAccessTokens.length === 0) && <Space direction="vertical" size="small" align="start"
style={{display: 'flex', padding: '45px 0px', marginTop: "-40px", justifyContent: 'center'}}>
<Paragraph
style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "16px"}}>
You don’t have any access tokens yet.
</Paragraph>
<Button type="primary" onClick={onClickAddNewPersonalAccessToken}>Create Token</Button>
</Space>}
{(personalAccessTokens === null || personalAccessTokens.length === 0) &&
<Space direction="vertical" size="small" align="start"
style={{
display: 'flex',
padding: '35px 0px',
marginTop: "-40px",
justifyContent: 'center'
}}>
<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>
</Container>}
</Card>}
</div>
<AddPATPopup/>
{confirmModalContextHolder}
+16 -18
View File
@@ -130,27 +130,25 @@ const AddPATPopup = () => {
}
width={460}
>
<Container style={{textAlign: "start"}}>
<Container style={{textAlign: "start", marginLeft: "-15px", marginRight: "-15px"}}>
<Paragraph
style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px", fontWeight: "500"}}>
{showPlainToken ? "Token created successfully!" : "Create a Personal Access Token"}
style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px"}}>
{showPlainToken ? "Token created successfully!" : "Create token"}
</Paragraph>
{!showPlainToken && <Paragraph type={"secondary"}
style={{
textAlign: "start",
fontSize: "14px",
whiteSpace: "pre-line",
marginTop: "-23px",
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>}
{showPlainToken && <Paragraph type={"secondary"} style={{
textAlign: "start",
fontSize: "14px",
whiteSpace: "pre-line",
marginTop: "40px",
}}>{"This token will not be shown again, so be sure to copy it and" + "\n" + "store in a secure location."}</Paragraph>}
marginTop: "25px",
}}>{"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}
initialValues={{
expires_in: ExpiresInDefault,
@@ -160,14 +158,14 @@ const AddPATPopup = () => {
<Col span={24}>
<Row align="top">
<Col flex="auto">
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "-8px"}}>Token name</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Create a name to identify the token easily</Paragraph>
<Paragraph style={{fontWeight: "bold", marginTop: "-10px"}}>Name</Paragraph>
<Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Set an easily identifiable name for your token</Paragraph>
<Form.Item
name="name"
style={{marginTop: "-10px"}}
rules={[{
required: true,
message: 'Please add a name for this personal access token',
message: 'Please add a name for this token',
whitespace: true
}]}
>
@@ -179,9 +177,9 @@ const AddPATPopup = () => {
</Col>
</Row>
</Col>
<Col span={24} style={{textAlign: "left"}}>
<Paragraph style={{fontSize: "16px", fontWeight: "500"}}>Expires in</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Number of days this token is valid for</Paragraph>
<Col span={24} style={{textAlign: "left", marginTop: "10px"}}>
<Paragraph style={{fontWeight: "bold", marginTop: "-10px"}}>Expires in</Paragraph>
<Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Number of days this token will be valid for</Paragraph>
<Form.Item
name="expires_in"
style={{marginTop: "-10px"}}
@@ -195,10 +193,10 @@ const AddPATPopup = () => {
</Form.Item>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Should be between 1 and 365 days</Paragraph>
</Col>
{/*<Col span={24}>*/}
{/* <Button icon={<QuestionCircleFilled/>} type="link" target="_blank" disabled={true} style={{marginTop: "20px", marginBottom: "20px"}}*/}
{/* href="https://netbird.io/docs/overview/personal-access-tokens">Learn more about personal access tokens</Button>*/}
{/*</Col>*/}
<Col span={24}>
<Button icon={<QuestionCircleFilled/>} type="link" target="_blank" disabled={true} style={{marginTop: "20px", marginBottom: "20px"}}
href="https://docs.netbird.io/how-to/access-netbird-public-api">Learn more about personal access tokens</Button>
</Col>
</Row>
</Form>}
{showPlainToken &&
+11 -11
View File
@@ -199,10 +199,10 @@ const AddServiceUserPopup = () => {
}
width={460}
>
<Container style={{textAlign: "start"}}>
<Container style={{textAlign: "start", marginLeft: "-15px", marginRight: "-15px"}}>
<Paragraph
style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px", fontWeight: "500"}}>
{"Add Service User"}
style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px"}}>
{"Add service user"}
</Paragraph>
<Paragraph type={"secondary"}
style={{
@@ -211,7 +211,7 @@ const AddServiceUserPopup = () => {
marginTop: "-23px",
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>
<Form layout="vertical" hideRequiredMark form={form}
initialValues={{
@@ -220,8 +220,8 @@ const AddServiceUserPopup = () => {
>
<Row gutter={16}>
<Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "-10px"}}>Name</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Set a name to easily identify the user</Paragraph>
<Paragraph style={{fontWeight: "bold", marginTop: "-10px"}}>Name</Paragraph>
<Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Set a name to easily identify the user</Paragraph>
<Form.Item
name="name"
rules={[{
@@ -232,14 +232,14 @@ const AddServiceUserPopup = () => {
style={{marginTop: "-8px"}}
>
<Input
placeholder={'for example "Ansible User"'}
placeholder={'for example "Ansible user"'}
ref={inputNameRef}
autoComplete="off"/>
</Form.Item>
</Col>
<Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", 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 style={{fontWeight: "bold", marginTop: "0px"}}>Role</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-15px"}}>Set a role for the user to assign access permissions</Paragraph>
<Form.Item
name="role"
rules={[{
@@ -256,8 +256,8 @@ const AddServiceUserPopup = () => {
</Form.Item>
</Col>
{/*<Col span={24}>*/}
{/* <Paragraph style={{fontSize: "16px", fontWeight: "500", 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 style={{fontWeight: "bold", marginTop: "0px"}}>Auto-assigned groups</Paragraph>*/}
{/* <Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-15px"}}>Add groups, that will be assigned to peers added by this user</Paragraph>*/}
{/* <Form.Item*/}
{/* name="autoGroupsNames"*/}
{/* label="Auto-assigned groups"*/}
+15 -16
View File
@@ -12,7 +12,6 @@ import {
Typography
} from "antd";
import {Container} from "../Container";
import {CloseOutlined} from "@ant-design/icons";
import React, {useEffect, useRef, useState} from "react";
import {useDispatch, useSelector} from "react-redux";
import {RootState} from "typesafe-actions";
@@ -20,9 +19,9 @@ import {useGetTokenSilently} from "../../utils/token";
import {actions as userActions} from "../../store/user";
import {actions as groupActions} from "../../store/group";
import {User, UserToSave} from "../../store/user/types";
import {Header} from "antd/es/layout/layout";
import {RuleObject} from "antd/lib/form";
import {CustomTagProps} from "rc-select/lib/BaseSelect";
import {QuestionCircleFilled} from "@ant-design/icons";
const {Title, Text, Paragraph} = Typography;
const {Option} = Select;
@@ -200,10 +199,10 @@ const InviteUserPopup = () => {
}
width={460}
>
<Container style={{textAlign: "start"}}>
<Container style={{textAlign: "start", marginLeft: "-15px", marginRight: "-15px"}}>
<Paragraph
style={{textAlign: "start", whiteSpace: "pre-line", fontSize: "22px", fontWeight: "500"}}>
{"Invite User"}
{"Invite user"}
</Paragraph>
<Paragraph type={"secondary"}
style={{
@@ -222,8 +221,8 @@ const InviteUserPopup = () => {
>
<Row gutter={16}>
<Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "-10px"}}>Name</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Set a name to easily identify the user</Paragraph>
<Paragraph style={{fontWeight: "bold", marginTop: "-10px"}}>Name</Paragraph>
<Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Set a name to easily identify the user</Paragraph>
<Form.Item
name="name"
rules={[{
@@ -240,8 +239,8 @@ const InviteUserPopup = () => {
</Form.Item>
</Col>
<Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", marginTop: "0px"}}>Email</Paragraph>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Provide the email address of the user</Paragraph>
<Paragraph style={{ fontWeight: "bold", marginTop: "0px"}}>Email</Paragraph>
<Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Provide the email address of the user</Paragraph>
<Form.Item
name="email"
rules={[{
@@ -259,8 +258,8 @@ const InviteUserPopup = () => {
</Form.Item>
</Col>
<Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", 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 style={{ fontWeight: "bold", marginTop: "0px"}}>Role</Paragraph>
<Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Set a role for the user to assign access permissions</Paragraph>
<Form.Item
name="role"
rules={[{
@@ -277,8 +276,8 @@ const InviteUserPopup = () => {
</Form.Item>
</Col>
<Col span={24}>
<Paragraph style={{fontSize: "16px", fontWeight: "500", 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 style={{fontWeight: "bold", marginTop: "0px"}}>Auto-assigned groups</Paragraph>
<Paragraph type={"secondary"} style={{marginTop: "-15px"}}>Add groups, that will be assigned to peers added by this user</Paragraph>
<Form.Item
name="autoGroupsNames"
tooltip="Every peer enrolled with this user will be automatically added to these groups"
@@ -300,10 +299,10 @@ const InviteUserPopup = () => {
</Select>
</Form.Item>
</Col>
{/*<Col span={24}>*/}
{/* <Button icon={<QuestionCircleFilled/>} type="link" target="_blank" disabled={true} style={{marginTop: "20px", marginBottom: "20px"}}*/}
{/* href="https://netbird.io/docs/overview/personal-access-tokens">Learn more about user</Button>*/}
{/*</Col>*/}
<Col span={24}>
<Button icon={<QuestionCircleFilled/>} type="link" target="_blank" disabled={true} style={{marginTop: "20px", marginBottom: "20px"}}
href="https://docs.netbird.io/how-to/access-netbird-public-api">Learn more about user</Button>
</Col>
</Row>
</Form>
</Container>
@@ -10,6 +10,7 @@ import WindowsTab from "./WindowsTab";
import MacTab from "./MacTab";
import Link from "antd/lib/typography/Link";
import DockerTab from "./DockerTab";
import AndroidTab from "./AndroidTab";
type Props = {
greeting?: string;
@@ -51,11 +52,11 @@ export const AddPeerPopup: React.FC<Props> = ({
label: <span><AppleFilled/>macOS</span>,
children: <MacTab/>,
},
/*{
{
key: "4",
label: <span><AndroidFilled/>Android</span>,
children: <></>,
},*/
children: <AndroidTab/>,
},
{
key: "5",
label: <span><Icon component={DockerSVG}/>Docker</span>,
@@ -91,7 +92,7 @@ export const AddPeerPopup: React.FC<Props> = ({
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 {<Link target="_blank"
href={"https://netbird.io/docs/getting-started/installation"}>installation
href={"https://docs.netbird.io/how-to/getting-started#installation"}>installation
guide</Link>}
</Paragraph>
</>
@@ -0,0 +1,51 @@
import React, {useState} from 'react';
import {Button, Image, Typography} from "antd";
import TabSteps from "./TabSteps";
import { StepCommand } from "./types"
import googleplay from '../../../../assets/google-play-badge.png';
const {Text} = Typography;
export const AndroidTab = () => {
const [steps, setSteps] = useState([
{
key: 1,
title: 'Download and install the application from Google Play Store:',
commands: (
<a href="https://play.google.com/store/apps/details?id=io.netbird.client" target="_blank">
<Image width="12em" preview={false} style={{marginTop: "5px"}} src={googleplay}/>
</a>
),
copied: false
} as StepCommand,
{
key: 2,
title: 'Run the application and click on the "Connect" button in the middle of the screen',
commands: '',
copied: false,
showCopyButton: false
},
{
key: 3,
title: 'Sign up using your email address',
commands: '',
copied: false,
showCopyButton: false
}
])
return (
<div style={{marginTop: 10}}>
<Text style={{fontWeight: "bold"}}>
Install on Android
</Text>
<div style={{marginTop: 5}}>
<TabSteps stepsItems={steps}/>
</div>
</div>
)
}
export default AndroidTab
@@ -31,7 +31,7 @@ export const DockerTab = () => {
key: 3,
title: "Read docs",
commands: (
<Link href="https://netbird.io/docs/getting-started/installation#running-netbird-in-docker" target="_blank">Running NetBird in Docker</Link>
<Link href="https://docs.netbird.io/how-to/getting-started#running-net-bird-in-docker" target="_blank">Running NetBird in Docker</Link>
),
copied: false,
showCopyButton: false
@@ -12,7 +12,7 @@ export const OtherTab = () => {
key: 1,
title: 'For other installation options check our documentation.',
commands: (
<Button type="primary" href={`https://netbird.io/docs/getting-started/installation#binary-install`} target="_blank">
<Button type="primary" href={`https://docs.netbird.io/how-to/getting-started#binary-install`} target="_blank">
Documentation
</Button>
),
+2 -12
View File
@@ -5,8 +5,6 @@ import service from './service';
import actions from './actions';
import serviceGroup from "../group/service";
import {Group} from "../group/types";
import {actions as groupActions} from "../group";
import {PersonalAccessToken} from "../personal-access-token/types";
export function* getUsers(action: ReturnType<typeof actions.getUsers.request>): Generator {
try {
@@ -74,7 +72,8 @@ export function* saveUser(action: ReturnType<typeof actions.saveUser.request>):
email: userToSave.email,
role: userToSave.role,
auto_groups: newGroups,
is_service_user: userToSave.is_service_user
is_service_user: userToSave.is_service_user,
is_blocked: userToSave.is_blocked
} as UserToSave
let effect
@@ -99,15 +98,6 @@ export function* saveUser(action: ReturnType<typeof actions.saveUser.request>):
error: null,
data: response.body
} as CreateResponse<User | null>));
yield put(groupActions.getGroups.request({
getAccessTokenSilently: action.payload.getAccessTokenSilently,
payload: null
}));
yield put(actions.getUsers.request({
getAccessTokenSilently: action.payload.getAccessTokenSilently,
payload: null
}));
} catch (err) {
yield put(actions.saveUser.failure({
loading: false,
+2
View File
@@ -7,10 +7,12 @@ export interface User {
auto_groups: string[];
is_current?: boolean;
is_service_user?: boolean;
is_blocked?: boolean;
}
export interface FormUser extends User {
autoGroupsNames: string[]
is_active?: boolean
}
export interface UserToSave extends User {
+13 -6
View File
@@ -27,7 +27,7 @@ import {Rule} from "../store/rule/types";
import {actions as ruleActions} from "../store/rule";
import {actions as groupActions} from "../store/group";
import {filter, sortBy} from "lodash";
import {CloseOutlined, ExclamationCircleOutlined} from "@ant-design/icons";
import {CloseOutlined, EllipsisOutlined, ExclamationCircleOutlined} from "@ant-design/icons";
import bidirect from '../assets/direct_bi.svg';
import inbound from '../assets/direct_in.svg';
import outbound from '../assets/direct_out.svg';
@@ -37,6 +37,7 @@ import AccessControlModalGroups from "../components/AccessControlModalGroups";
import tableSpin from "../components/Spin";
import {useGetTokenSilently} from "../utils/token";
import {usePageSizeHelpers} from "../utils/pageSize";
import {PeerDataTable} from "../store/peer/types";
const {Title, Paragraph, Text} = Typography;
const {Column} = Table;
@@ -449,11 +450,17 @@ export const AccessControl = () => {
<Column title="" align="center"
render={(text, record, index) => {
if (deletedRule.loading || savedRule.loading) return <></>
return <Dropdown.Button type="text" overlay={actionsMenu}
trigger={["click"]}
onOpenChange={visible => {
if (visible) setRuleToAction(record as RuleDataTable)
}}></Dropdown.Button>
return (
<Dropdown trigger={["click"]} overlay={actionsMenu} onOpenChange={visible => {
if (visible) setRuleToAction(record as RuleDataTable)
}}>
<Button type="text">
<Space>
<EllipsisOutlined />
</Space>
</Button>
</Dropdown>
)
}}
/>
</Table>
+3 -1
View File
@@ -212,6 +212,8 @@ export const Activity = () => {
case "service.user.delete":
return renderMultiRowSpan(event.meta.name,"Service User")
case "user.invite":
case "user.block":
case "user.unblock":
if (user) {
return renderMultiRowSpan(user.name ? user.name : user.id,user.email ? user.email : "User")
}
@@ -252,7 +254,7 @@ export const Activity = () => {
<Row justify="end">
<Col>
<Button icon={<QuestionCircleFilled/>} type="link" target="_blank"
href="https://netbird.io/docs/how-to-guides/activity-monitoring">Learn more about activity tracking</Button>
href="https://docs.netbird.io/how-to/monitor-system-and-network-activity">Learn more about activity tracking</Button>
</Col>
</Row>
</Col>
+11 -6
View File
@@ -31,7 +31,7 @@ import {Group} from "../store/group/types";
import {TooltipPlacement} from "antd/es/tooltip";
import {NameServer, NameServerGroup} from "../store/nameservers/types";
import NameServerGroupUpdate from "../components/NameServerGroupUpdate";
import {ExclamationCircleOutlined} from "@ant-design/icons";
import {EllipsisOutlined, ExclamationCircleOutlined} from "@ant-design/icons";
import {useGetGroupTagHelpers} from "../utils/groups";
import {usePageSizeHelpers} from "../utils/pageSize";
@@ -441,11 +441,16 @@ export const Nameservers = () => {
<Column title="" align="center" width="30px"
render={(text, record) => {
return (
<Dropdown.Button type="text" overlay={actionsMenu}
trigger={["click"]}
onOpenChange={visible => {
if (visible) setNsGroupToAction(record as NameserverGroupDataTable)
}}></Dropdown.Button>)
<Dropdown trigger={["click"]} overlay={actionsMenu} onOpenChange={visible => {
if (visible) setNsGroupToAction(record as NameserverGroupDataTable)
}}>
<Button type="text">
<Space>
<EllipsisOutlined />
</Space>
</Button>
</Dropdown>
)
}}
/>
</Table>
+12 -6
View File
@@ -6,7 +6,7 @@ import {actions as peerActions} from '../store/peer';
import {actions as groupActions} from '../store/group';
import {actions as routeActions} from '../store/route';
import {Container} from "../components/Container";
import {ExclamationCircleOutlined, ReloadOutlined,} from '@ant-design/icons';
import {EllipsisOutlined, ExclamationCircleOutlined, ReloadOutlined,} from '@ant-design/icons';
import {
Alert,
Button,
@@ -611,11 +611,17 @@ export const Peers = () => {
<Column title="Version" dataIndex="version"/>
<Column title="" align="center"
render={(text, record, index) => {
return <Dropdown.Button type="text" overlay={actionsMenu}
trigger={["click"]}
onOpenChange={visible => {
if (visible) setPeerToAction(record as PeerDataTable)
}}></Dropdown.Button>
return (
<Dropdown trigger={["click"]} overlay={actionsMenu} onOpenChange={visible => {
if (visible) setPeerToAction(record as PeerDataTable)
}}>
<Button type="text">
<Space>
<EllipsisOutlined />
</Space>
</Button>
</Dropdown>
)
}}
/>
</Table>)}
Loaded 20 of 26 files, more files were not shown because too many files have changed in this diff. Show more