Compare commits

..
Author SHA1 Message Date
Sarooj Bukhari 8ad6952dae da 2023-08-25 14:44:10 +05:00
Sarooj Bukhari 7e5595c365 fix button hover 2023-08-15 21:39:36 +05:00
Sarooj Bukhari 12687379cc limit user account 2023-08-15 21:04:52 +05:00
braginini 62d80af186 Limit columns and navbar 2023-08-15 15:37:37 +02:00
22 changed files with 260 additions and 399 deletions

No files matched your search

-56
View File
@@ -1,56 +0,0 @@
import { Page, test, expect } from "@playwright/test";
export class AccessControlPage {
private readonly accessControlUrl = 'http://localhost:3000/acls'
private readonly defaulAccessControl = this.page.getByRole('cell', { name: 'Default' })
private readonly deleteButton = this.page.getByRole('button', { name: 'Delete' })
private readonly deleteModal = this.page.getByTestId('confirm-delete-modal-title')
private readonly confirmButton = this.page.getByRole('button', { name: 'OK' })
private readonly addRulesButton = this.page.getByTestId('add-rule-empty-state-button')
constructor(private readonly page: Page) {}
async openAccessControlPage() {
await test.step('Open Access Control page', async () => {
await this.page.goto(this.accessControlUrl);
})
}
async assertDefaultAccessCotrolIsCreated() {
await test.step('Assert that default cotrol access is created', async () => {
await expect(this.defaulAccessControl).toBeVisible();
})
}
async pressDeleteButton() {
await test.step('Press delete button', async () => {
await this.deleteButton.click();
})
}
async assertDeleteModalIsVisibile() {
await test.step('Assert access control deletion modal is visible', async () => {
await expect(this.deleteModal).toBeVisible();
})
}
async pressConfirmButton() {
await test.step('Press confirm button on access control deletion modal', async () => {
await this.confirmButton.click();
})
}
async assertDefaultAccessCotrolIsDeleted() {
await test.step('Assert default access control should be deleted', async () => {
await expect(this.defaulAccessControl).not.toBeVisible();
})
}
async assertAddRuleButtonIsVisile() {
await test.step('Assert Add Rules button is visible', async () => {
await expect(this.addRulesButton).toBeVisible();
})
}
}
export default AccessControlPage;
-34
View File
@@ -1,34 +0,0 @@
import { Page, test, expect} from "@playwright/test";
export class LoginPage {
private readonly localUrl = 'http://localhost:3000/'
private readonly usernameField = this.page.getByPlaceholder('username@domain')
private readonly nextButton = this.page.getByRole('button', { name: 'next' })
private readonly passwordField = this.page.getByLabel('Password')
private readonly skipButton = this.page.getByRole('button', { name: 'skip' });
private readonly netBirdLogo = this.page.getByRole('link', { name: 'logo' })
constructor(private readonly page: Page) {}
async doLogin() {
await test.step('Login to local enviroment', async () => {
await this.page.goto(this.localUrl);
await this.usernameField.fill('admin@localhost');
await this.pressNextButton();
await this.passwordField.fill('testMe123@');
await this.pressNextButton();
if (await this.skipButton.isVisible({ timeout: 300 })) {
await this.skipButton.click();
}
await expect(this.netBirdLogo).toBeVisible();
})
}
async pressNextButton() {
await test.step('Press next button', async () => {
await this.nextButton.click();
})
}
}
export default LoginPage;
+1 -1
View File
@@ -1,4 +1,4 @@
import { Page, test } from "@playwright/test";
import { Page, test, expect } from "@playwright/test";
export class PeersPage {
private readonly addNewPeerButton = this.page.getByTestId('add-new-peer-button')
+26 -15
View File
@@ -1,22 +1,33 @@
import { test } from '@playwright/test'
import {LoginPage} from '../pages/login-page'
import {AccessControlPage} from '../pages/access-control-page'
import { test, expect } from '@playwright/test';
import {AddPeerModal} from '../pages/modals/add-peer-modal'
import {TopMenu} from '../pages/top-menu';
let loginPage: LoginPage
let accessControlPage: AccessControlPage
const URL = 'https://app.netbird.io/'
const localUrl = 'http://localhost:3000/'
let addPeerModal: AddPeerModal;
let topMenu: TopMenu;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
await loginPage.doLogin();
addPeerModal = new AddPeerModal(page);
await page.goto(localUrl);
await page.getByPlaceholder('username@domain').fill('admin@localhost');
await page.getByRole('button', { name: 'next' }).click();
await page.getByLabel('Password').fill('testMe123@');
await page.getByRole('button', { name: 'next' }).click();
const skipButton = page.getByRole('button', { name: 'skip' });
if (await skipButton.isVisible({ timeout: 300 })) {
await skipButton.click();
}
await addPeerModal.assertPeerModalIsVisible();
});
test('Confirm that new user has Default access', async ({ page }) => {
accessControlPage = new AccessControlPage(page);
await accessControlPage.openAccessControlPage();
await accessControlPage.assertDefaultAccessCotrolIsCreated();
await accessControlPage.pressDeleteButton();
await accessControlPage.assertDeleteModalIsVisibile();
await accessControlPage.pressConfirmButton();
await accessControlPage.assertDefaultAccessCotrolIsDeleted();
await accessControlPage.assertAddRuleButtonIsVisile();
topMenu = new TopMenu(page);
await addPeerModal.closeAddPeerModal();
await addPeerModal.assertPeerModalIsNotVisible();
await topMenu.clickOnAccessControlOnTopMenu();
await expect(page.getByRole('cell', { name: 'Default' })).toBeVisible();
await page.getByRole('button', { name: 'Delete' }).click();
await expect(page.getByTestId('confirm-delete-modal-title')).toBeVisible();
await page.getByRole('button', { name: 'Cancel' }).click();
});
+19 -12
View File
@@ -1,41 +1,48 @@
import { test } from '@playwright/test'
import { test } from '@playwright/test';
import {AddPeerModal} from '../pages/modals/add-peer-modal'
import {PeersPage} from '../pages/peers-page'
import {LoginPage} from '../pages/login-page'
let addPeerModal: AddPeerModal
let peersPage: PeersPage
let loginPage: LoginPage
const URL = 'https://app.netbird.io/'
const localUrl = 'http://localhost:3000/'
let addPeerModal: AddPeerModal;
let peersPage: PeersPage;
test.beforeEach(async ({ page }) => {
addPeerModal = new AddPeerModal(page);
loginPage = new LoginPage(page);
await loginPage.doLogin();
await page.goto(localUrl);
await page.getByPlaceholder('username@domain').fill('admin@localhost');
await page.getByRole('button', { name: 'next' }).click();
await page.getByLabel('Password').fill('testMe123@');
await page.getByRole('button', { name: 'next' }).click();
const skipButton = page.getByRole('button', { name: 'skip' });
if (await skipButton.isVisible({ timeout: 300 })) {
await skipButton.click();
}
await addPeerModal.assertPeerModalIsVisible();
});
test('Test Linux tab on a first access add peer modal / @bc', async function () {
test('Test Linux tab on a first access add peer modal / @bc', async function ({ }) {
await addPeerModal.openLinuxTab();
await addPeerModal.assertLinuxTabHasCorrectText();
});
test('Test Windows tab on a first access add peer modal / @bc', async () => {
test('Test Windows tab on a first access add peer modal / @bc', async ({ }) => {
await addPeerModal.openWindowsTab();
await addPeerModal.assertWindowsDownloadButtonHasCorrectLink();
});
test('Test MacOS tab on a first access add peer modal / @bc', async () => {
test('Test MacOS tab on a first access add peer modal / @bc', async ({ }) => {
await addPeerModal.openMacTab();
await addPeerModal.assertIntelDownloadButtonHasCorrectLink();
await addPeerModal.assertM1M2DownloadButtonHasCorrectLink();
});
test('Test Android tab on a first access add peer modal', async () => {
test('Test Android tab on a first access add peer modal', async ({ }) => {
await addPeerModal.openAndroidTab();
await addPeerModal.assertAndroidDownloadButtonHasCorrectLink();
});
test('Test Docker tab on a first access add peer modal', async () => {
test('Test Docker tab on a first access add peer modal', async ({ }) => {
await addPeerModal.openDockerTab();
await addPeerModal.assertDockerDownloadButtonHasCorrectLink();
});
+33
View File
@@ -12,6 +12,8 @@
"@axa-fr/react-oidc": "^5.14.0",
"@headlessui/react": "^1.5.0",
"@heroicons/react": "^1.0.4",
"@stripe/react-stripe-js": "^2.1.2",
"@stripe/stripe-js": "^2.1.0",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
@@ -3405,6 +3407,24 @@
"@sinonjs/commons": "^1.7.0"
}
},
"node_modules/@stripe/react-stripe-js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-2.1.2.tgz",
"integrity": "sha512-2JcKRvOdMD698uGrY0cINLHb6XHnY24L+wlWlw2+TbI2aXlQZ9t8Mc+KssFES+EuNgISbrp7fJR3w/13epfiOw==",
"dependencies": {
"prop-types": "^15.7.2"
},
"peerDependencies": {
"@stripe/stripe-js": "^1.44.1 || ^2.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@stripe/stripe-js": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-2.1.0.tgz",
"integrity": "sha512-AdMHWqIq/s3TLmoyuzdb6l21STKDKNm82cjce1VelyQGinVNjVgSEPH5UDtxENEP7OzgMZH8RTphFMi0fMJGLQ=="
},
"node_modules/@surma/rollup-plugin-off-main-thread": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
@@ -19477,6 +19497,19 @@
"@sinonjs/commons": "^1.7.0"
}
},
"@stripe/react-stripe-js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-2.1.2.tgz",
"integrity": "sha512-2JcKRvOdMD698uGrY0cINLHb6XHnY24L+wlWlw2+TbI2aXlQZ9t8Mc+KssFES+EuNgISbrp7fJR3w/13epfiOw==",
"requires": {
"prop-types": "^15.7.2"
}
},
"@stripe/stripe-js": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-2.1.0.tgz",
"integrity": "sha512-AdMHWqIq/s3TLmoyuzdb6l21STKDKNm82cjce1VelyQGinVNjVgSEPH5UDtxENEP7OzgMZH8RTphFMi0fMJGLQ=="
},
"@surma/rollup-plugin-off-main-thread": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
+4 -2
View File
@@ -7,6 +7,8 @@
"@axa-fr/react-oidc": "^5.14.0",
"@headlessui/react": "^1.5.0",
"@heroicons/react": "^1.0.4",
"@stripe/react-stripe-js": "^2.1.2",
"@stripe/stripe-js": "^2.1.0",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
@@ -79,7 +81,7 @@
]
},
"devDependencies": {
"@types/react-syntax-highlighter": "^15.5.3",
"@playwright/test": "^1.36.2"
"@playwright/test": "^1.36.2",
"@types/react-syntax-highlighter": "^15.5.3"
}
}
+9 -9
View File
@@ -39,15 +39,15 @@ export default defineConfig({
use: { channel: 'chrome', },
},
// {
// name: 'firefox',
// use: { browserName: 'firefox', },
// },
//
// {
// name: 'webkit',
// use: { browserName: 'webkit', },
// },
{
name: 'firefox',
use: { browserName: 'firefox', },
},
{
name: 'webkit',
use: { browserName: 'webkit', },
},
/* Test against mobile viewports. */
// {
View File
Whitespace-only changes.
+34 -78
View File
@@ -13,7 +13,6 @@ import {
Tag,
Typography,
Card,
Tooltip,
} from "antd";
import { RootState } from "typesafe-actions";
import {
@@ -55,7 +54,7 @@ const SetupKeyNew = (props: any) => {
const savedSetupKey = useSelector(
(state: RootState) => state.setupKey.savedSetupKey
);
const groups = useSelector((state: RootState) => state.group.data);
const [form] = Form.useForm();
@@ -92,13 +91,14 @@ const SetupKeyNew = (props: any) => {
.filter((g) => allGroups.get(g))
.map((g) => allGroups.get(g)!.name);
}
const fSetupKey = {
...setupKey,
autoGroupNames: setupKey.auto_groups || [],
exp: moment(setupKey.expires),
last: moment(setupKey.last_used),
} as FormSetupKey;
form.setFieldsValue(fSetupKey);
form.setFieldsValue(fSetupKey);
setFormSetupKey(fSetupKey);
}, [setupKey]);
@@ -117,7 +117,6 @@ const SetupKeyNew = (props: any) => {
groupsToCreate: groupsToCreate,
expires_in: expiresIn,
usage_limit: formSetupKey.usage_limit,
ephemeral: formSetupKey.ephemeral,
} as SetupKeyToSave;
};
@@ -126,7 +125,8 @@ const SetupKeyNew = (props: any) => {
await form.validateFields();
} catch (e) {
const errorFields = (e as any).errorFields;
}
return console.log("errorInfo", errorFields);
}
const setupKeyToSave = createSetupKeyToSave();
dispatch(
@@ -257,7 +257,8 @@ const SetupKeyNew = (props: any) => {
dispatch(personalAccessTokenActions.resetPersonalAccessTokens(null));
setVisibleNewSetupKey(false);
};
return (
return (
<>
{!isGroupUpdateView && (
<Breadcrumb
@@ -301,9 +302,13 @@ const SetupKeyNew = (props: any) => {
{!isGroupUpdateView && (
<Row style={{ marginTop: "10px" }}>
<Col
xs={24}
sm={24}
md={8}
lg={8}
md={11}
lg={11}
xl={11}
xxl={11}
span={11}
style={{
paddingRight: "70px",
}}
@@ -337,14 +342,7 @@ const SetupKeyNew = (props: any) => {
/>
</Col>
<Col
sm={24}
md={8}
lg={6}
style={{
paddingRight: "70px",
}}
>
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
<Paragraph
style={{
whiteSpace: "pre-line",
@@ -359,48 +357,8 @@ const SetupKeyNew = (props: any) => {
fontWeight: "500",
}}
></Paragraph>
Type{" "}
{formSetupKey.ephemeral ? (
<Tooltip title="Peers that are offline for over 10 minutes will be removed automatically">
<Tag>
<Text type="secondary" style={{ fontSize: 10 }}>
Ephemeral
</Text>
</Tag>
</Tooltip>
) : (
" "
)}
</Paragraph>
<Col>
<Input
disabled
value={
formSetupKey.type === "one-off" ? "One-off" : "Reusable"
}
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
style={{ marginTop: "8px" }}
/>
</Col>
</Col>
<Col sm={24} md={8} lg={3}>
<Paragraph
style={{
whiteSpace: "pre-line",
margin: 0,
fontWeight: "500",
}}
>
<Paragraph
style={{
whiteSpace: "pre-line",
margin: 0,
fontWeight: "500",
}}
></Paragraph>
{/* {formSetupKey.type === "one-off" ? "One-off" : "Reusable"}, */}
Available uses
{formSetupKey.type === "one-off" ? "One-off" : "Reusable"},
available uses
</Paragraph>
<Col>
<Input
@@ -418,25 +376,6 @@ const SetupKeyNew = (props: any) => {
</Col>
</Row>
)}
<Row style={{ marginTop: `${isGroupUpdateView ? "0" : "39px"}` }}>
{!isGroupUpdateView && (
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
<Paragraph style={{ margin: 0, fontWeight: "500" }}>
Expires
</Paragraph>
<Row>
<Input
style={{ marginTop: "8px" }}
disabled
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
value={
customExpiresFormat(new Date(formSetupKey.expires))!
}
/>
</Row>
</Col>
)}
</Row>
<Row style={{ marginTop: `${isGroupUpdateView ? "0" : "39px"}` }}>
<Col
xs={24}
@@ -474,7 +413,7 @@ const SetupKeyNew = (props: any) => {
dropdownRender={dropDownRender}
// enabled only when we have a new key !setupkey.id or when the key is valid
disabled={!(!setupKey.id || setupKey.valid)}
optionFilterProp="searchValue"
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
@@ -485,6 +424,23 @@ const SetupKeyNew = (props: any) => {
</Form.Item>
</Col>
</Col>
{!isGroupUpdateView && (
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
<Paragraph style={{ margin: 0, fontWeight: "500" }}>
Expires
</Paragraph>
<Row>
<Input
style={{ marginTop: "8px" }}
disabled
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
value={
customExpiresFormat(new Date(formSetupKey.expires))!
}
/>
</Row>
</Col>
)}
</Row>
</Form>
</div>
-39
View File
@@ -75,7 +75,6 @@ const SetupKeyNew = () => {
const expiresIn = formSetupKey.expires_in
? formSetupKey.expires_in * 24 * 3600
: 7 * 24 * 3600; // the api expects seconds we have days
return {
id: formSetupKey.id,
name: formSetupKey.name,
@@ -85,7 +84,6 @@ const SetupKeyNew = () => {
groupsToCreate: groupsToCreate,
expires_in: expiresIn,
usage_limit: formSetupKey.usage_limit,
ephemeral: formSetupKey.ephemeral,
} as SetupKeyToSave;
};
@@ -157,7 +155,6 @@ const SetupKeyNew = () => {
usage_limit: 0,
used_times: 0,
expires_in: 7,
ephemeral: false,
} as SetupKey)
);
setFormSetupKey({} as FormSetupKey);
@@ -490,42 +487,6 @@ const SetupKeyNew = () => {
</Col>
</Row>
<Row style={{ marginTop: "24px" }} justify={"space-between"}>
<Col span={18}>
<Paragraph
style={{
whiteSpace: "pre-line",
margin: 0,
fontWeight: "500",
}}
>
Ephemeral peers
</Paragraph>
<Paragraph
type={"secondary"}
style={{ whiteSpace: "pre-line", margin: 0 }}
>
Peers that are offline for over 10 minutes will be removed
automatically
</Paragraph>
</Col>
<Col span={6}>
<Row justify={"end"}>
<Form.Item name="ephemeral" valuePropName="checked">
<Switch
size="small"
onChange={(checked) => {
setFormSetupKey({
...formSetupKey,
ephemeral: checked,
});
}}
/>
</Form.Item>
</Row>
</Col>
</Row>
<Row style={{ marginTop: "24px" }}>
<Col span={24}>
<Paragraph
-9
View File
@@ -519,13 +519,4 @@ ul.ant-list-items {
.nohover {
background: transparent!important;
cursor: text;
}
.emp-wrapper {
display: flex;
align-items: center;
gap: 8px;
}
.emp-wrapper p {
margin: 0;
}
+1 -2
View File
@@ -63,8 +63,7 @@ export function* saveSetupKey(action: ReturnType<typeof actions.saveSetupKey.req
auto_groups: newGroups,
type: keyToSave.type,
expires_in: keyToSave.expires_in,
usage_limit: keyToSave.usage_limit,
ephemeral: keyToSave.ephemeral
usage_limit: keyToSave.usage_limit
} as SetupKeyToSave
});
} else {
-1
View File
@@ -14,7 +14,6 @@ export interface SetupKey {
auto_groups: string[]
expires_in: number;
usage_limit: any;
ephemeral: boolean;
}
export interface FormSetupKey extends SetupKey {
-1
View File
@@ -8,7 +8,6 @@ export interface User {
is_current?: boolean;
is_service_user?: boolean;
is_blocked?: boolean;
last_login?: string;
}
export interface FormUser extends User {
+1 -3
View File
@@ -100,7 +100,7 @@ export const timeAgo = (dateParam) => {
const isToday = today.toDateString() === date.toDateString();
const isYesterday = yesterday.toDateString() === date.toDateString();
const isThisYear = today.getFullYear() === date.getFullYear();
const never = date.getFullYear() === 1;
if (seconds < -1) {
return getFormattedDate(date, false, true);
@@ -118,8 +118,6 @@ export const timeAgo = (dateParam) => {
return getFormattedDate(date, 'yesterday'); // Yesterday at 10:20
} else if (isThisYear) {
return getFormattedDate(date, false, true); // 10. January at 10:20
} else if (never) {
return 'never';
}
return getFormattedDate(date); // 10. January 2017. at 10:20
-2
View File
@@ -666,7 +666,6 @@ export const AccessControl = () => {
<Row justify="end">
<Col>
<Button
data-testid="add-rule-main-button"
type="primary"
disabled={savedPolicy.loading}
onClick={onClickAddNewPolicy}
@@ -720,7 +719,6 @@ export const AccessControl = () => {
</a>
</Paragraph>
<Button
data-testid="add-rule-empty-state-button"
size={"middle"}
type="primary"
onClick={() => onClickAddNewPolicy()}
-33
View File
@@ -169,37 +169,7 @@ export const Activity = () => {
const renderInitiator = (event: EventDataTable) => {
let body = <></>;
const user = users?.find((u) => u.id === event.initiator_id);
if (event.initiator_id == "sys") {
body = (
<span
style={{
height: "auto",
whiteSpace: "normal",
textAlign: "left",
}}
>
<Row>
<Text type="secondary">System</Text>
</Row>
</span>
);
}
switch (event.activity_code) {
case "peer.login.expire":
body = (
<span
style={{
height: "auto",
whiteSpace: "normal",
textAlign: "left",
}}
>
<Row>
<Text type="secondary">System</Text>
</Row>
</span>
);
break;
case "setupkey.peer.add":
const key = setupKeys?.find((k) => k.id === event.initiator_id);
if (key) {
@@ -285,7 +255,6 @@ export const Activity = () => {
switch (event.activity_code) {
case "account.create":
case "user.join":
case "dashboard.login":
return "-";
case "rule.add":
case "rule.delete":
@@ -321,8 +290,6 @@ export const Activity = () => {
case "peer.rename":
case "peer.login.expiration.disable":
case "peer.login.expiration.enable":
case "user.peer.login":
case "peer.login.expire":
return renderMultiRowSpan(event.meta.fqdn, event.meta.ip);
case "route.add":
case "route.delete":
+6 -8
View File
@@ -248,7 +248,6 @@ export const Peers = () => {
const t = searchText
? searchText.toLowerCase().trim()
: textToSearch.toLowerCase().trim();
let f: Peer[] = filter(peers, (f: Peer) => {
let userEmail: string | null;
const u = users?.find((u) => u.id === f.user_id)?.email;
@@ -262,9 +261,8 @@ export const Peers = () => {
(userEmail && userEmail.toLowerCase().includes(t))
);
}) as Peer[];
if (optionOnOff === "on") {
f = filter(f, (f: Peer) => f.connected);
f = filter(peers, (f: Peer) => f.connected);
}
let filterByGroupArray: any = [];
@@ -635,16 +633,16 @@ export const Peers = () => {
<Container style={{ paddingTop: "40px" }}>
<Row>
<Col span={24}>
<Title className="page-heading">{isAdmin ? "Peers" : "My peers"}</Title>
<Title className="page-heading">Peers</Title>
{peers.length ? (
<Paragraph style={{ marginTop: "5px" }}>
{isAdmin ? "A list of all machines and devices connected to your private network. Use this view to manage peers" :
"A list of all your machines and devices that you connected to NetBird."}
A list of all machines and devices connected to your private
network. Use this view to manage peers
</Paragraph>
) : (
<Paragraph style={{ marginTop: "5px" }} type={"secondary"}>
{isAdmin ? "A list of all machines and devices connected to your private network. Use this view to manage peers" :
"A list of all your machines and devices that you connected to NetBird."}
A list of all machines and devices connected to your private
network. Use this view to manage peers
</Paragraph>
)}
+26 -35
View File
@@ -31,7 +31,7 @@ import { useGetTokenSilently } from "../utils/token";
import { actions as groupActions } from "../store/group";
import { Group } from "../store/group/types";
import { TooltipPlacement } from "antd/es/tooltip";
import {capitalize, isLocalDev, isNetBirdHosted, timeAgo} from "../utils/common";
import { capitalize, isLocalDev, isNetBirdHosted } from "../utils/common";
import { usePageSizeHelpers } from "../utils/pageSize";
import AddServiceUserPopup from "../components/popups/AddServiceUserPopup";
import InviteUserPopup from "../components/popups/InviteUserPopup";
@@ -499,54 +499,45 @@ export const RegularUsers = () => {
defaultSortOrder="ascend"
render={(text, record, index) => {
const btn = (
<Button
type="text"
onClick={() =>
handleEditUser(record as UserDataTable)
}
className="tooltip-label"
>
<Text className="font-500">
{text && text.trim() !== ""
? text
: (record as User).id}
</Text>
</Button>
<Button
type="text"
onClick={() =>
handleEditUser(record as UserDataTable)
}
className="tooltip-label"
>
<Text className="font-500">
{text && text.trim() !== ""
? text
: (record as User).id}
</Text>
</Button>
);
if ((record as User).is_current) {
return (
<>
<div>
{btn}
<Tag color="blue">me</Tag>
</div>
<Text type={"secondary"} style={{paddingLeft: "15px"}}>Last login: {String(timeAgo((record as User).last_login))}</Text>
</>
<div>
{btn}
<Tag color="blue">me</Tag>
</div>
);
}
if ((record as User).status === "invited") {
return (
<>
<div>
{btn}
<Tag color="gold">invited</Tag>
</div>
<Text type={"secondary"} style={{paddingLeft: "15px", paddingTop: "0px"}}>Last login: {String(timeAgo((record as User).last_login))}</Text>
</>
<div>
{btn}
<Tag color="gold">invited</Tag>
</div>
);
}
if ((record as User).status === "blocked") {
return (
<>
<div>
{btn}
<Tag color="red">blocked</Tag>
</div>
<Text type={"secondary"} style={{paddingLeft: "15px"}}>Last login: {String(timeAgo((record as User).last_login))}</Text>
</>
<div>
{btn}
<Tag color="red">blocked</Tag>
</div>
);
}
Loaded 20 of 22 files, more files were not shown because too many files have changed in this diff. Show more