Compare commits

...
23 Commits
Author SHA1 Message Date
Misha Bragin 5bd94eff56 Fix add peer popup tab layout on mobile (#154) 2023-03-23 12:10:27 +01:00
Misha Bragin 77f065b093 Update theme border radius (#152) 2023-03-22 16:56:36 +01:00
Misha Bragin a4d55cfb90 Fix settings modal styles (#151) 2023-03-22 16:14:49 +01:00
Misha Bragin cfd4c9075b Add onboarding steps (#150) 2023-03-22 15:21:52 +01:00
braginini 962180030a Fix activity docs link 2023-03-15 14:20:48 +01:00
Misha Bragin 485e1e8d79 Add more references to docs (#149) 2023-03-15 14:18:22 +01:00
Givi Khojanashvili b11007b29f Add policy add activities (#147)
Related changes for netbirdio/netbird#700
2023-03-13 10:58:34 +01:00
Maycon Santos bce75c1ca9 Disable banner (#146) 2023-03-02 15:55:31 +01:00
Maycon Santos 0c09992b38 Use user.is_current (#145)
prevent update for own user

use the is_current for label

removed unused imports
2023-03-01 22:50:26 +01:00
Maycon Santos 86b12f30d2 Use new windows release URL (#144)
removed latestVersion logic and environment support
2023-03-01 15:00:36 +01:00
Maycon Santos d3e34d8448 Use single page size helper with new larger values (#143)
Reduce duplicated code with single helper for pagination

On larger deployments we should allow for larger pages

fix popover key issue and vertical spacing

update deprecated keys
2023-02-28 16:32:12 +01:00
Misha Bragin 76083168f6 Log error when activity event is not handled (#142) 2023-02-28 11:22:40 +01:00
Misha Bragin a54b3687ae Display user in the user role update event (#141)
Handling of the "User role updated" event (user.role.update) 
was missing in the Activity tab.
2023-02-27 15:27:00 +01:00
Zoltan Papp 25f154dc83 Capitalize first letter of OS (#140) 2023-02-27 14:54:39 +01:00
pascal-fischer f3c7d877f8 Add additional step in the Mac installation instructions to start the daemon (#138) 2023-02-22 20:55:36 +01:00
Misha Bragin 7cea7e7f54 Format individual peer login expiration event (#139)
Events peer.login.expiration.disable and peer.login.expiration.enable
are handled in the Activity tab now and properly displayed.
2023-02-22 20:54:56 +01:00
Misha Bragin aaa351635f Add peer expiration setting confirmation modal (#137)
Add a confirmation dialog to notify a user of possible
consequences of the peer login expiration enabling/disabling.
2023-02-21 08:47:14 +01:00
Misha Bragin 379ff5486e Account settings view (#136)
New Settings tab added to the dashboard.
It is possible to enable or disable peer login expiration globally for an account.
As well as defining the expiration time period.
2023-02-20 08:57:24 +01:00
Misha Bragin 8bcd9918e2 Fix expires in input filed of the setup key (#135) 2023-02-17 14:30:22 +01:00
Misha Bragin 044ccd0ce6 Display login expiration activities (#134) 2023-02-16 15:36:45 +01:00
braginini ab09ca3697 Display API error in peers view 2023-02-16 13:03:39 +01:00
Misha Bragin 1644ed5dce Add peer login expiration tooltip (#133) 2023-02-16 12:47:35 +01:00
Misha Bragin cea459792f Add peer login expiration (#132)
Display if peer login has expired in the Peers table
Enable/Disable peer login expiration
2023-02-16 12:18:15 +01:00
51 changed files with 1885 additions and 862 deletions

No files matched your search

+1 -4
View File
@@ -53,13 +53,10 @@ export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(
export NETBIRD_MGMT_GRPC_API_ENDPOINT=${NETBIRD_MGMT_GRPC_API_ENDPOINT}
export NETBIRD_HOTJAR_TRACK_ID=${NETBIRD_HOTJAR_TRACK_ID}
REPO="https://github.com/netbirdio/netbird/"
# this command will fetch the latest release e.g. v0.6.3
export NETBIRD_LATEST_VERSION=$(basename $(curl -fs -o/dev/null -w %{redirect_url} ${REPO}releases/latest))
echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}"
# replace ENVs in the config
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_LATEST_VERSION \$\$NETBIRD_HOTJAR_TRACK_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI"
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_HOTJAR_TRACK_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI"
MAIN_JS=$(find /usr/share/nginx/html/static/js/main.*js)
OIDC_TRUSTED_DOMAINS="/usr/share/nginx/html/OidcTrustedDomains.js"
+740 -437
View File
File diff suppressed because it is too large. Load diff
+4 -2
View File
@@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@ant-design/icons": "^4.7.0",
"@ant-design/icons": "^4.8.0",
"@axa-fr/react-oidc": "^5.14.0",
"@headlessui/react": "^1.5.0",
"@heroicons/react": "^1.0.4",
@@ -18,7 +18,7 @@
"@types/react-redux": "^7.1.24",
"@types/react-router-dom": "^5.3.3",
"@types/styled-components": "^5.1.25",
"antd": "^4.20.6",
"antd": "^5.3.1",
"autoprefixer": "^10.4.4",
"axios": "^0.27.2",
"cidr-regex": "^3.1.1",
@@ -27,11 +27,13 @@
"highlight.js": "^11.2.0",
"history": "^5.0.1",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"postcss": "^8.4.12",
"prop-types": "^15.7.2",
"punycode": "^2.1.1",
"rc-overflow": "^1.2.8",
"react": "^18.2.0",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.1.0",
"react-hotjar": "^5.1.0",
"react-redux": "^8.0.2",
+53 -42
View File
@@ -4,7 +4,7 @@ import {apiClient, store} from "./store";
import {hotjar} from 'react-hotjar';
import {getConfig} from "./config";
import Banner from "./components/Banner";
import {Col, Layout, Row} from "antd";
import {Col, ConfigProvider, Layout, Row} from "antd";
import {Container} from "./components/Container";
import Navbar from "./components/Navbar";
import {Redirect, Route, Switch} from "react-router-dom";
@@ -21,7 +21,7 @@ import {User} from "./store/user/types";
import {SecureLoading} from "./components/Loading";
import DNS from "./views/DNS";
import Activity from "./views/Activity";
import Settings from "./views/Settings";
const {Header, Content} = Layout;
@@ -57,7 +57,7 @@ function App() {
run.current = true
apiClient.request<User[]>('GET', `/api/users`, {getAccessTokenSilently: getAccessTokenSilently})
.then(() => {
setShow(true)
setShow(true)
})
.catch(e => {
setShow(true)
@@ -69,50 +69,61 @@ function App() {
return (
<>
<ConfigProvider
theme={{
token: {
borderRadius: 4,
colorPrimary: "#1890ff",
fontFamily: "Arial"
},
}}
>
<Provider store={store}>
{!show && <SecureLoading padding="3em" width={50} height={50}/>}
{show &&
<Layout>
<Banner/>
<Header className="header" style={{
display: "flex",
flexDirection: "column",
justifyContent: "space-around",
alignContent: "center"
}}>
<Row justify="space-around" align="middle">
<Col span={24}>
<Container>
<Navbar/>
</Container>
</Col>
</Row>
</Header>
<Content style={{minHeight: "100vh"}}>
<Switch>
<Route
exact
path="/"
render={() => {
return (
<Redirect to="/peers"/>
)
}}
/>
<Route path='/peers' exact component={withOidcSecure(Peers)}/>
<Route path="/add-peer" component={withOidcSecure(AddPeer)}/>
<Route path="/setup-keys" component={withOidcSecure(SetupKeys)}/>
<Route path="/acls" component={withOidcSecure(AccessControl)}/>
<Route path="/routes" component={withOidcSecure(Routes)}/>
<Route path="/users" component={withOidcSecure(Users)}/>
<Route path="/dns" component={withOidcSecure(DNS)}/>
<Route path="/activity" component={withOidcSecure(Activity)}/>
</Switch>
</Content>
<FooterComponent/>
</Layout>
<Layout>
<Banner/>
<Header className="header" style={{
display: "flex",
flexDirection: "column",
justifyContent: "space-around",
alignContent: "center"
}}>
<Row justify="space-around" align="middle">
<Col span={24}>
<Container>
<Navbar/>
</Container>
</Col>
</Row>
</Header>
<Content style={{minHeight: "100vh"}}>
<Switch>
<Route
exact
path="/"
render={() => {
return (
<Redirect to="/peers"/>
)
}}
/>
<Route path='/peers' exact component={withOidcSecure(Peers)}/>
<Route path="/setup-keys" component={withOidcSecure(SetupKeys)}/>
<Route path="/acls" component={withOidcSecure(AccessControl)}/>
<Route path="/routes" component={withOidcSecure(Routes)}/>
<Route path="/users" component={withOidcSecure(Users)}/>
<Route path="/dns" component={withOidcSecure(DNS)}/>
<Route path="/activity" component={withOidcSecure(Activity)}/>
<Route path="/settings" component={withOidcSecure(Settings)}/>
</Switch>
</Content>
<FooterComponent/>
</Layout>
}
</Provider>
</ConfigProvider>
</>
)
}
+1 -1
View File
@@ -16,7 +16,7 @@ const AccessControlModalGroups:React.FC<Props> = ({data, title, visible, onCance
return (
<>
<Modal title={title} visible={isModalVisible} onCancel={() => onCancel()} footer={null}>
<Modal title={title} open={isModalVisible} onCancel={() => onCancel()} footer={null}>
<List
itemLayout="horizontal"
dataSource={data as Group[] | undefined}
+1 -3
View File
@@ -408,9 +408,7 @@ const AccessControlNew = () => {
<Col span={24}>
<Divider></Divider>
<Button icon={<QuestionCircleFilled/>} type="link" target="_blank"
href="https://docs.netbird.io/docs/overview/acls"
style={{color: 'rgb(07, 114, 128)'}}>Learn
more about access controls</Button>
href="https://docs.netbird.io/docs/overview/acls">Learn more about access controls</Button>
</Col>
</Row>
</Form>
+1 -1
View File
@@ -36,7 +36,7 @@ const Banner = () => {
if((!stored_banner_closed || stored_banner_closed !== 'true') ||
(!store_banner_md5 || store_banner_md5 !== announcement_md5)) {
setShow(true);
//setShow(true);
localStorage.setItem(banner_md5_key,announcement_md5);
localStorage.setItem(banner_closed_key,'false');
}
+1 -3
View File
@@ -604,9 +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"
style={{color: 'rgb(07, 114, 128)'}}>Learn
more about nameservers</Button>
href="https://netbird.io/docs/how-to-guides/nameservers">Learn more about nameservers</Button>
</Col>
</Row>
</Form>) :
+3 -3
View File
@@ -35,19 +35,19 @@ const Navbar = () => {
const items = [
{label: (<Link to="/peers">Peers</Link>), key: '/peers'},
{label: (<Link to="/add-peer">Add Peer</Link>), key: '/add-peer'},
{label: (<Link to="/setup-keys">Setup Keys</Link>), key: '/setup-keys'},
{label: (<Link to="/acls">Access Control</Link>), key: '/acls'},
{label: (<Link to="/routes">Network Routes</Link>), key: '/routes'},
{ label: (<Link to="/dns">DNS</Link>), key: '/dns' },
{label: (<Link to="/users">Users</Link>), key: '/users'},
{label: (<Link to="/activity">Activity</Link>), key: '/activity'}
{label: (<Link to="/activity">Activity</Link>), key: '/activity'},
{label: (<Link to="/settings">Settings</Link>), key: '/settings'}
] as ItemType[]
const userEmailKey = 'user-email'
const userLogoutKey = 'user-logout'
const userDividerKey = 'user-divider'
const adminOnlyTabs = ["/setup-keys", "/acls", "/routes", "/dns", "/activity"]
const adminOnlyTabs = ["/setup-keys", "/acls", "/routes", "/dns", "/activity", "/settings"]
const [menuItems, setMenuItems] = useState(items)
const logoutWithRedirect = () =>
logout("/", {client_id: config.clientId});
+25 -22
View File
@@ -2,7 +2,7 @@ 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, Collapse, Divider, Drawer, Form, Input, Row, Select, Space, Tag, Typography} from "antd";
import {Button, Col, Collapse, Divider, Drawer, Form, Input, Radio, Row, Select, Space, Tag, Typography} from "antd";
import {Header} from "antd/es/layout/layout";
import type {CustomTagProps} from 'rc-select/lib/BaseSelect'
import {FormPeer, Peer, PeerGroupsToSave} from "../store/peer/types";
@@ -18,6 +18,7 @@ const {Panel} = Collapse;
const punycode = require('punycode/')
const PeerUpdate = () => {
const {getAccessTokenSilently} = useGetAccessTokenSilently()
const dispatch = useDispatch()
const groups = useSelector((state: RootState) => state.group.data)
@@ -200,6 +201,10 @@ const PeerUpdate = () => {
return !formPeer.name || formPeer.name === peer.name
}
const noUpdateToLoginExpiration = (): Boolean => {
return formPeer.login_expiration_enabled === peer.login_expiration_enabled
}
const onChange = (data: any) => {
setFormPeer({...formPeer, ...data})
}
@@ -232,7 +237,8 @@ const PeerUpdate = () => {
return {
id: formPeer.id,
ssh_enabled: formPeer.ssh_enabled,
name: formPeer.name
name: formPeer.name,
login_expiration_enabled: formPeer.login_expiration_enabled
} as Peer
}
@@ -240,7 +246,7 @@ const PeerUpdate = () => {
form.validateFields()
.then((values) => {
setSubmitRunning(true)
if (!noUpdateToName()) {
if (!noUpdateToName() || !noUpdateToLoginExpiration()) {
const peerUpdate = createPeerToSave()
setCallingPeerAPI(true)
dispatch(peerActions.updatePeer.request({
@@ -248,7 +254,7 @@ const PeerUpdate = () => {
payload: peerUpdate
}))
}
if (peerGroupsToSave.groupsToRemove.length || peerGroupsToSave.groupsToAdd.length || peerGroupsToSave.groupsNoId.length) {
if (!noUpdateToGroups()) {
setCallingGroupAPI(true)
dispatch(peerActions.saveGroups.request({
getAccessTokenSilently: getAccessTokenSilently,
@@ -303,7 +309,7 @@ const PeerUpdate = () => {
<Space style={{display: 'flex', justifyContent: 'end'}}>
<Button onClick={onCancel} disabled={savedGroups.loading}>Cancel</Button>
<Button type="primary"
disabled={(savedGroups.loading || updatedPeers.loading) || (noUpdateToGroups() && noUpdateToName())}
disabled={(savedGroups.loading || updatedPeers.loading) || (noUpdateToGroups() && noUpdateToName() && noUpdateToLoginExpiration())}
onClick={handleFormSubmit}>Save</Button>
</Space>
}
@@ -435,6 +441,20 @@ const PeerUpdate = () => {
</Form.Item>
</Col>
)}
<Col span={24}>
<Form.Item
name="login_expiration_enabled"
label="Login expiration"
tooltip="When login expires, the user has to re-authenticate this peer. This only applies to peers added with the SSO login."
>
<Radio.Group
options={[{label: 'Enabled', value: true}, {label: 'Disabled', value: false}]}
optionType="button"
buttonStyle="solid"
disabled={!formPeer.user_id}
/>
</Form.Item>
</Col>
<Col span={24}>
<Form.Item
name="groupsNames"
@@ -458,23 +478,6 @@ const PeerUpdate = () => {
</Select>
</Form.Item>
</Col>
{/*<Col span={24}>
<Row wrap={false} gutter={12}>
<Col flex="none">
<FlagFilled/>
</Col>
<Col flex="auto">
<Paragraph>
Every peer is part of the group All, thus you can't remove it.
</Paragraph>
</Col>
</Row>
</Col>*/}
{/*<Col span={24}>
<Divider orientation="left" plain style={{color: "#5a5c5a"}}>
System Info
</Divider>
</Col>*/}
<Col span={24}>
<Collapse onChange={onChange} bordered={false} ghost={true}
style={{color: "#5a5c5a"}}>
+1 -3
View File
@@ -453,9 +453,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"
style={{color: 'rgb(07, 114, 128)'}}>Learn
more about network routes</Button>
href="https://netbird.io/docs/how-to-guides/network-routes">Learn more about network routes</Button>
</Col>
</Row>
</Form>
+21 -45
View File
@@ -11,7 +11,7 @@ import {
Form,
Input,
InputNumber,
List,
List, Modal,
Radio,
Row,
Select,
@@ -23,25 +23,27 @@ import {RootState} from "typesafe-actions";
import {CloseOutlined, EditOutlined, QuestionCircleFilled} from "@ant-design/icons";
import {FormSetupKey, SetupKey, SetupKeyToSave} from "../store/setup-key/types";
import {Header} from "antd/es/layout/layout";
import {formatDate, timeAgo} from "../utils/common";
import {checkExpiresIn, formatDate, timeAgo} from "../utils/common";
import {RuleObject} from "antd/lib/form";
import {CustomTagProps} from "rc-select/lib/BaseSelect";
import {Group} from "../store/group/types";
import {useGetAccessTokenSilently} from "../utils/token";
import ExpiresInInput, {ExpiresInValue} from "../views/ExpiresInInput";
import ExpiresInInput, {expiresInToSeconds, ExpiresInValue} from "../views/ExpiresInInput";
import moment from "moment";
const {Option} = Select;
const {Text} = Typography;
const ExpiresInDefault: ExpiresInValue = {number: 30, interval: "Days"}
const ExpiresInDefault: ExpiresInValue = {number: 30, interval: "day"}
const customExpiresFormat: DatePickerProps['format'] = value => {
return formatDate(value)
}
const customLastUsedFormat: DatePickerProps['format'] = value => {
if (value.toString().startsWith("0001")) {
if (value.year() == 1) {
// 1st of Jan 0001
return "never"
}
let ago = timeAgo(value.toString())
@@ -93,7 +95,9 @@ const SetupKeyNew = () => {
const fSetupKey = {
...setupKey,
autoGroupNames: setupKey.auto_groups ? formKeyGroups : [],
expiresInFormatted: ExpiresInDefault
expiresInFormatted: ExpiresInDefault,
exp: moment(setupKey.expires),
last: moment(setupKey.last_used)
} as FormSetupKey
setFormSetupKey(fSetupKey)
form.setFieldsValue(fSetupKey)
@@ -117,31 +121,6 @@ const SetupKeyNew = () => {
usage_limit: formSetupKey.usage_limit
} as SetupKeyToSave
}
const expiresInToSeconds = (expiresIn: ExpiresInValue): number => {
if (!expiresIn.number || !expiresIn.interval) {
return 0
}
let multiplier = 0
switch (expiresIn.interval.toLowerCase()) {
case "day":
multiplier = 24 * 3600
break
case "week":
multiplier = 7 * 24 * 3600
break
case "month":
multiplier = 30 * 24 * 3600
break
case "year":
multiplier = 365 * 24 * 3600
break
default:
multiplier = 0
}
return expiresIn.number * multiplier
}
const handleFormSubmit = () => {
form.validateFields()
@@ -290,13 +269,6 @@ const SetupKeyNew = () => {
return setupKey.auto_groups?.filter(g => !formGroupIds.includes(g)).length > 0
}
const checkExpiresIn = (_: any, value: { number: number }) => {
if (value.number > 0) {
return Promise.resolve();
}
return Promise.reject(new Error("Expiration must be greater than zero"));
};
return (
<>
{setupKey &&
@@ -384,7 +356,7 @@ const SetupKeyNew = () => {
{setupKey.id && formSetupKey.name &&
<Col span={12}>
<Form.Item
name="expires"
name="exp"
label="Expires"
tooltip="The expiration date of the key"
>
@@ -397,7 +369,7 @@ const SetupKeyNew = () => {
{setupKey.id && formSetupKey.name &&
<Col span={12}>
<Form.Item
name="last_used"
name="last"
label="Last Used"
tooltip="The last time the key was used"
>
@@ -447,7 +419,12 @@ const SetupKeyNew = () => {
<Col span={24}>
<Form.Item name="expiresInFormatted" label="Expires In"
rules={[{validator: checkExpiresIn}]}>
<ExpiresInInput/>
<ExpiresInInput options={
Array.of(
{key: "day", title: "Days"},
{key: "month", title: "Months"},
{key: "year", title: "Years"})
}/>
</Form.Item>
</Col>}
<Col span={12}>
@@ -455,7 +432,8 @@ const SetupKeyNew = () => {
label="Usage Limit"
tooltip="Limit the number of times this key can be used. Use 0 for unlimited use."
>
<InputNumber min={0} defaultValue={0} disabled={setupKey.id || formSetupKey.type !== "reusable"}
<InputNumber min={0} defaultValue={0}
disabled={setupKey.id || formSetupKey.type !== "reusable"}
style={{width: "100%"}}
/>
</Form.Item>
@@ -496,9 +474,7 @@ const SetupKeyNew = () => {
<Col span={24}>
<Divider></Divider>
<Button icon={<QuestionCircleFilled/>} type="link" target="_blank"
href="https://netbird.io/docs/overview/setup-keys"
style={{color: 'rgb(07, 114, 128)'}}>Learn
more about setup keys</Button>
href="https://netbird.io/docs/overview/setup-keys">Learn more about setup keys</Button>
</Col>
</Row>
</Form>
+2 -2
View File
@@ -12,7 +12,7 @@ import {actions as userActions} from "../store/user";
import {useGetAccessTokenSilently} from "../utils/token";
import {useOidcUser} from "@axa-fr/react-oidc";
const {Paragraph, Text} = Typography;
const {Paragraph} = Typography;
const {confirm} = Modal;
@@ -358,7 +358,7 @@ const UserUpdate = () => {
>
<Select
style={{width: '100%'}}
disabled={currentUser.role != null && currentUser.role !== "admin"}>
disabled={(currentUser.role != null && currentUser.role !== "admin") || formUser.is_current}>
<Option value="admin">admin</Option>
<Option value="user">user</Option>
</Select>
+100
View File
@@ -0,0 +1,100 @@
import React, {useState} from 'react';
import {Tabs, TabsProps} from "antd";
import Icon, {AndroidFilled, AppleFilled, WindowsFilled} from "@ant-design/icons";
import {ReactComponent as LinuxSVG} from "../icons/terminal_icon.svg";
import UbuntuTab from "./UbuntuTab";
import {ReactComponent as DockerSVG} from "../icons/docker_icon.svg";
import Paragraph from "antd/lib/typography/Paragraph";
import WindowsTab from "./WindowsTab";
import MacTab from "./MacTab";
import Link from "antd/lib/typography/Link";
import DockerTab from "./DockerTab";
type Props = {
greeting?: string;
headline: string;
};
const detectOSTab = () => {
let os = 1;
if (navigator.userAgent.indexOf("Win") !== -1) os = 2;
if (navigator.userAgent.indexOf("Mac") !== -1) os = 3;
if (navigator.userAgent.indexOf("X11") !== -1) os = 1;
if (navigator.userAgent.indexOf("Linux") !== -1) os = 1
return os
}
export const AddPeerPopup: React.FC<Props> = ({
greeting,
headline,
}) => {
const [openTab, setOpenTab] = useState(detectOSTab);
const [width, setWidth] = useState<number>(window.innerWidth);
const isMobile = width <= 768;
const items: TabsProps['items'] = [
{
key: "1",
label: <span><Icon component={LinuxSVG}/>Ubuntu</span>,
children: <UbuntuTab/>,
},
{
key: "2",
label: <span><WindowsFilled/>Windows</span>,
children: <WindowsTab/>,
},
{
key: "3",
label: <span><AppleFilled/>macOS</span>,
children: <MacTab/>,
},
/*{
key: "4",
label: <span><AndroidFilled/>Android</span>,
children: <></>,
},*/
{
key: "5",
label: <span><Icon component={DockerSVG}/>Docker</span>,
children: <DockerTab/>,
}
];
return <>
{greeting && <Paragraph
style={{textAlign: "center", whiteSpace: "pre-line", fontSize: "2em", marginBottom: -10}}>
{greeting}
</Paragraph>}
<Paragraph
style={{textAlign: "center", whiteSpace: "pre-line", fontSize: "2em"}}>
{headline}
</Paragraph>
<Paragraph type={"secondary"}
style={{
marginTop: "-15px",
textAlign: "center",
whiteSpace: "pre-line",
}}>
To get started install NetBird and log in using your {"\n"} email account.
</Paragraph>
<Tabs centered={!isMobile}
defaultActiveKey={openTab.toString()} tabPosition="top" animated={{inkBar: true, tabPane: false}}
items={items}/>
<Paragraph type={"secondary"}
style={{
marginTop: "15px",
}}>
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
guide</Link>}
</Paragraph>
</>
}
export default AddPeerPopup
+63
View File
@@ -0,0 +1,63 @@
import React, {useState} from 'react';
import {StepCommand} from "./types"
import {formatDockerCommand, formatNetBirdUP} from "./common"
import SyntaxHighlighter from "react-syntax-highlighter";
import TabSteps from "./TabSteps";
import {Button, Typography} from "antd";
import Link from "antd/lib/typography/Link";
const {Title, Paragraph, Text} = Typography;
export const DockerTab = () => {
const [steps, setSteps] = useState([
{
key: 1,
title: 'Install Docker',
commands: (
<Button style={{marginTop: "5px"}} type="primary" href="https://docs.docker.com/engine/install/" target="_blank">Official Docker website</Button>
),
copied: false,
showCopyButton: false
} as StepCommand,
{
key: 2,
title: 'Run NetBird container',
commands: formatDockerCommand(),
copied: false,
showCopyButton: false
} as StepCommand,
{
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>
),
copied: false,
showCopyButton: false
} as StepCommand
])
return (
<div style={{marginTop: 10}}>
{/*<Text style={{fontWeight: "bold"}}>
Run in Docker
</Text>
<div style={{fontSize: ".85em", marginTop: 5, marginBottom: 25}}>
<SyntaxHighlighter language="bash">
{formatDockerCommand()}
</SyntaxHighlighter>
</div>*/}
<Text style={{fontWeight: "bold"}}>
Install on Ubuntu
</Text>
<div style={{marginTop: 5}}>
<TabSteps stepsItems={steps}/>
</div>
</div>
)
}
export default DockerTab
+68 -12
View File
@@ -1,18 +1,49 @@
import React, {useState} from 'react';
import { Button } from "antd";
import {Button, Typography} from "antd";
import TabSteps from "./TabSteps";
import { StepCommand } from "./types"
import { formatNetBirdUP } from "./common"
import {StepCommand} from "./types"
import {formatNetBirdUP} from "./common"
import {Collapse} from "antd";
const { Panel } = Collapse;
const {Text} = Typography;
export const LinuxTab = () => {
const [quickSteps, setQuickSteps] = useState([
{
key: 1,
title: 'Download and run installer:',
commands: (
<Button style={{marginTop: "5px"}} type="primary" href="https://pkgs.netbird.io/windows/x64"
target="_blank">Download NetBird</Button>
),
copied: false
} as StepCommand,
{
key: 2,
title: 'Click on "Connect" from the NetBird icon in your system tray',
commands: '',
copied: false,
showCopyButton: false
},
{
key: 3,
title: 'Sign up using your email address',
commands: '',
copied: false,
showCopyButton: false
}
])
const [steps, setSteps] = useState([
{
key: 1,
title: 'Download and install Brew (package manager)',
title: 'Download and install Homebrew',
commands: (
<Button type="primary" href="https://brew.sh/" target="_blank">Download Brew</Button>
<Button style={{marginTop: "5px"}} type="primary" href="https://brew.sh/" target="_blank">Download
Brew</Button>
),
copied: false
} as StepCommand,
@@ -30,24 +61,49 @@ export const LinuxTab = () => {
} as StepCommand,
{
key: 3,
title: 'Run NetBird and log in the browser:',
commands: formatNetBirdUP(),
title: 'Start NetBird daemon:',
commands: [
`sudo netbird service install`,
`sudo netbird service start`
].join('\n'),
copied: false,
showCopyButton: true
} as StepCommand,
{
key: 4,
title: 'Get your IP address:',
commands: [
`sudo ifconfig utun100`
].join('\n'),
title: 'Run NetBird and log in the browser:',
commands: formatNetBirdUP(),
copied: false,
showCopyButton: true
} as StepCommand
])
return (
<TabSteps stepsItems={steps}/>
/*<div style={{marginTop: 10}}>
<Text style={{fontWeight: "bold"}}>
Install on macOS
</Text>
<div style={{marginTop: 5}}>
<TabSteps stepsItems={quickSteps}/>
</div>
<Collapse style={{marginLeft: -15}} bordered={false}>
<Panel header={<Text style={{fontWeight: "bold"}}>
Or install manually with Homebrew
</Text>} key="1">
<div style={{marginTop: 5}}>
<TabSteps stepsItems={steps}/>
</div>
</Panel>
</Collapse>
</div>*/
<div style={{marginTop: 10}}>
<Text style={{fontWeight: "bold"}}>
Install on macOS with Homebrew
</Text>
<div style={{marginTop: 5}}>
<TabSteps stepsItems={steps}/>
</div>
</div>
)
}
+7 -20
View File
@@ -2,16 +2,16 @@ import "highlight.js/styles/mono-blue.css";
import "highlight.js/lib/languages/bash";
import { StepCommand } from './types'
import SyntaxHighlighter from 'react-syntax-highlighter';
import { monoBlue } from 'react-syntax-highlighter/dist/esm/styles/hljs';
import {
Typography,
Space,
Steps, Button
Steps, Button, Popover, StepsProps
} from "antd";
import {copyToClipboard} from "../../utils/common";
import {CheckOutlined, CopyOutlined} from "@ant-design/icons";
import React, {useEffect, useState} from "react";
const { Step } = Steps;
const {Text} = Typography;
type Props = {
stepsItems: Array<StepCommand>
@@ -36,35 +36,22 @@ const TabSteps:React.FC<Props> = ({stepsItems}) => {
}, 2000)
}
}
return (
<Steps direction="vertical" current={0}>
<Steps direction="vertical" size={"small"}>
{steps.map(c =>
<Step
status={"process"}
key={c.key}
title={c.title}
title={<Text>{c.title}</Text>}
description={
<Space className="nb-code" direction="vertical" size="small" style={{display: "flex"}}>
<Space className="nb-code" direction="vertical" size="small" style={{display: "flex", fontSize: ".85em"}}>
{ (c.commands && (typeof c.commands === 'string')) ? (
<SyntaxHighlighter language="bash" style={monoBlue}>
<SyntaxHighlighter language="bash">
{c.commands}
</SyntaxHighlighter>
) : (
c.commands
)}
{ c.showCopyButton &&
<>
{ !c.copied ? (
<Button type="text" size="large" className="btn-copy-code" icon={<CopyOutlined/>}
style={{color: "rgb(107, 114, 128)"}}
onClick={() => onCopyClick(c.key, c.commands, true)}/>
): (
<Button type="text" size="large" className="btn-copy-code" icon={<CheckOutlined/>}
style={{color: "green"}}/>
)}
</>
}
</Space>
}
/>
+34 -36
View File
@@ -1,31 +1,29 @@
import React, { useState } from 'react';
import { Button } from "antd";
import React, {useState} from 'react';
import {StepCommand} from "./types"
import {formatNetBirdUP} from "./common"
import SyntaxHighlighter from "react-syntax-highlighter";
import TabSteps from "./TabSteps";
import { StepCommand } from "./types"
import { getConfig } from "../../config";
import Paragraph from 'antd/lib/skeleton/Paragraph';
import { formatNetBirdUP } from "./common"
import {Typography} from "antd";
const {Title, Paragraph, Text} = Typography;
export const UbuntuTab = () => {
const [steps, setSteps] = useState([
{
key: 1,
title: 'Add repository:',
title: 'Add repository',
commands: [
`sudo apt install ca-certificates curl gnupg -y`,
`curl -L https://pkgs.wiretrustee.com/debian/public.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/wiretrustee.gpg`,
`echo 'deb https://pkgs.wiretrustee.com/debian stable main' | sudo tee /etc/apt/sources.list.d/wiretrustee.list`
].join('\n'),
copied: false,
showCopyButton: true
showCopyButton: false
} as StepCommand,
{
key: 2,
title: 'Install NetBird:',
title: 'Install NetBird',
commands: [
`sudo apt-get update`,
`# for CLI only`,
@@ -34,39 +32,39 @@ export const UbuntuTab = () => {
`sudo apt-get install netbird-ui`
].join('\n'),
copied: false,
showCopyButton: true
showCopyButton: false
} as StepCommand,
{
key: 3,
title: 'Run NetBird and log in the browser:',
title: 'Run NetBird and log in the browser',
commands: formatNetBirdUP(),
copied: false,
showCopyButton: true
} as StepCommand,
{
key: 4,
title: 'Get your IP address:',
commands: [
`ip addr show wt0`
].join('\n'),
copied: false,
showCopyButton: true
} as StepCommand,
showCopyButton: false
} as StepCommand
])
/*const clickTest = () => {
steps.push({
key: steps.length+1,
title: `Test ${steps.length+1}`,
commands: [`hi lorena!`].join('\n'),
copied: false
})
console.log(steps)
setSteps([...steps])
}*/
return (
<TabSteps stepsItems={steps} />
<div style={{marginTop: 10}}>
{/*<Text style={{fontWeight: "bold"}}>
Install with one command
</Text>
<div style={{fontSize: ".85em", marginTop: 5, marginBottom: 25}}>
<SyntaxHighlighter language="bash">
curl -fsSL https://netbird.io/install.sh | sh
</SyntaxHighlighter>
</div>*/}
{/*<Text style={{fontWeight: "bold"}}>*/}
{/* Or install manually*/}
{/*</Text>*/}
<Text style={{fontWeight: "bold"}}>
Install on Ubuntu
</Text>
<div style={{marginTop: 5}}>
<TabSteps stepsItems={steps}/>
</div>
</div>
)
}
+14 -8
View File
@@ -1,33 +1,31 @@
import React, {useState} from 'react';
import { Button } from "antd";
import {Button, Typography} from "antd";
import TabSteps from "./TabSteps";
import { StepCommand } from "./types"
import {getConfig} from "../../config";
const {latestVersion} = getConfig();
const {Text} = Typography;
export const WindowsTab = () => {
const releaseVersion = latestVersion ? latestVersion.replace("v", "") : "0.6.3"
const [steps, setSteps] = useState([
{
key: 1,
title: 'Download and run Windows installer:',
commands: (
<Button type="primary" href={`https://github.com/netbirdio/netbird/releases/download/v${releaseVersion}/netbird_installer_${releaseVersion}_windows_amd64.exe`} target="_blank">Download NetBird</Button>
<Button style={{marginTop: "5px"}} type="primary" href="https://pkgs.netbird.io/windows/x64" target="_blank">Download NetBird</Button>
),
copied: false
} as StepCommand,
{
key: 2,
title: 'Click on "Connect" from the NetBird icon in your system tray.',
title: 'Click on "Connect" from the NetBird icon in your system tray',
commands: '',
copied: false,
showCopyButton: false
},
{
key: 3,
title: 'Log in your browser.\n',
title: 'Sign up using your email address',
commands: '',
copied: false,
showCopyButton: false
@@ -35,7 +33,15 @@ export const WindowsTab = () => {
])
return (
<TabSteps stepsItems={steps}/>
<div style={{marginTop: 10}}>
<Text style={{fontWeight: "bold"}}>
Install on Windows
</Text>
<div style={{marginTop: 5}}>
<TabSteps stepsItems={steps}/>
</div>
</div>
)
}
+14 -2
View File
@@ -3,11 +3,23 @@ const { grpcApiOrigin } = getConfig();
export const formatNetBirdUP = () => {
let cmd = "sudo netbird up"
let cmd = "netbird up"
if (grpcApiOrigin) {
cmd = "sudo netbird up --management-url " + grpcApiOrigin
cmd = "netbird up --management-url " + grpcApiOrigin
}
return [
cmd
].join('\n')
}
export const formatDockerCommand = () => {
let cmd = ["docker run --rm -d",
" --cap-add=NET_ADMIN",
" -e NB_SETUP_KEY=SETUP_KEY",
" -v netbird-client:/etc/netbird"]
if (grpcApiOrigin) {
cmd.push(" -e NB_MANAGEMENT_URL="+grpcApiOrigin)
}
cmd.push(" netbirdio/netbird:latest")
return cmd.join(' \\\n')
}
Loaded 20 of 51 files, more files were not shown because too many files have changed in this diff. Show more