Compare commits

..
7 Commits
Author SHA1 Message Date
Yulia e8d57c3445 Fix flaky Access control test (#261)
Fixed flaky test by changing the way to access 
Access Control Page and add some test ids of Add Rules buttons.

Temporary removed tests for Firefox and webkit(safari)
2023-08-22 11:38:11 +02:00
pascal-fischer 0b892c0056 Add User last login and new events
Add last login to users overview list.
Additionally added new events for dashboard login, peer expiration and peer login.
2023-08-18 19:23:56 +02:00
Misha Bragin 14d9b80029 Limit UI view for the "user" role (#259) 2023-08-15 22:36:21 +02:00
B. Baumgartl dedbe55308 Add windows/macos/android instructions for self-hosted (#254)
* Add windows/macos instructions for self-hosted

* Add android instructions for self-hosted
2023-08-14 18:54:44 +03:00
Yulia 796a06cf27 Add end-to-end tests using playwright (#257)
Add tests with playwright for:

- add peer modal on first access
- add peer modal on empty peer list
- test install buttons and instructions for Linux, 
Docker, macOS, Windows and Android
- check default ACL

The tests are using a modified version of the getting 
started scripts to run a local environment of 
management services and run the dashboard from the current version

Todo:

- run tests before create docker container
- add more tests
2023-08-12 23:11:32 +02:00
Sarooj bukhari 2443c6332d Apply quick group on all application (#253) 2023-08-10 15:34:21 +02:00
braginini 3b5193ae4e Fix protocol ALL value 2023-08-05 11:42:06 +02:00
43 changed files with 2596 additions and 1026 deletions

No files matched your search

+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
node-version: '16'
cache: 'npm'
- name: Install dependecies
- name: Install dependencies
run: npm install
- name: Build
+42
View File
@@ -0,0 +1,42 @@
name: run e2e tests
on:
push:
branches:
- main
pull_request:
jobs:
e2e_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: setup-node
uses: actions/setup-node@v3
with:
node-version: '16'
cache: 'npm'
- name: Install dependencies
run: npm install
- name: install playwright
run: npx playwright install
- name: install playwright deps
run: npx playwright install-deps
- name: create test environment
run: bash ./e2e-tests/create-test-env.sh
- name: run e2e tests
run: npx playwright test --workers 2
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: |
playwright-report/
test-results/
retention-days: 3
+12
View File
@@ -29,3 +29,15 @@ src/auth_config.json
src/.local-config*.json
/public/OidcServiceWorker.js
/public/OidcTrustedDomains.js
/e2e-tests/node_modules/
/e2e-tests/playwright-report/
/e2e-tests/test-results/
/test-results/
/playwright-report/
.env
Caddyfile
docker-compose.yml
machinekey/
management.json
turnserver.conf
zitadel.env
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
docker-compose down --volumes
rm -f docker-compose.yml Caddyfile zitadel.env dashboard.env machinekey/zitadel-admin-sa.token turnserver.conf management.json
File diff suppressed because it is too large. Load diff
+56
View File
@@ -0,0 +1,56 @@
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
@@ -0,0 +1,34 @@
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;
+111
View File
@@ -0,0 +1,111 @@
import { Page, test, expect } from "@playwright/test";
export class AddPeerModal {
private readonly addPeerModal = this.page.getByTestId('add-peer-modal').locator('div').nth(2)
private readonly linuxTab = this.page.getByTestId('add-peer-modal-linux-tab')
private readonly windowsTab = this.page.getByTestId('add-peer-modal-windows-tab')
private readonly macTab = this.page.getByTestId('add-peer-modal-mac-tab')
private readonly androidTab = this.page.getByTestId('add-peer-modal-android-tab')
private readonly dockerTab = this.page.getByTestId('add-peer-modal-docker-tab')
private readonly linuxTabText = this.page.locator('pre').filter({ hasText: 'curl -fsSL https://pkgs.netbird.io/install.sh | sh' })
private readonly windowsDownloadButton = this.page.getByTestId('download-windows-button')
private readonly intelDownloadButton = this.page.getByTestId('download-intel-button')
private readonly m1M2DownloadButton = this.page.getByTestId('download-m1-m2-button')
private readonly androidDownloadButton = this.page.getByTestId('download-android-button')
private readonly dockerDownloadButton = this.page.getByTestId('download-docker-button')
private readonly closeButton = this.page.getByLabel('Close', { exact: true })
constructor(private readonly page: Page) {}
async assertPeerModalIsVisible() {
await test.step('Assert that add peer modal is visible', async () => {
await expect(this.addPeerModal).toBeVisible();
})
}
async assertPeerModalIsNotVisible() {
await test.step('Assert that add peer modal is not visible', async () => {
await expect(this.addPeerModal).not.toBeVisible();
})
}
async openLinuxTab() {
await test.step('Open Linux tab on add peer modal', async () => {
await this.linuxTab.click();
})
}
async openWindowsTab() {
await test.step('Open Windows tab on add peer modal', async () => {
await this.windowsTab.click();
})
}
async openMacTab() {
await test.step('Open MacOS tab on add peer modal', async () => {
await this.macTab.click();
})
}
async openAndroidTab() {
await test.step('Open Android tab on add peer modal', async () => {
await this.androidTab.click();
})
}
async openDockerTab() {
await test.step('Open Docker tab on add peer modal', async () => {
await this.dockerTab.click();
})
}
async assertLinuxTabHasCorrectText() {
await test.step('Assert Linux tab has correct installation text', async () => {
await expect(this.linuxTabText).toBeVisible();
})
}
async assertWindowsDownloadButtonHasCorrectLink() {
await test.step('Assert Windows download button has a correct link', async () => {
await expect(this.windowsDownloadButton).toHaveAttribute('href', 'https://pkgs.netbird.io/windows/x64');
})
}
async assertIntelDownloadButtonHasCorrectLink() {
await test.step('Assert Intel download button has a correct link', async () => {
await expect(this.intelDownloadButton).toHaveAttribute('href', 'https://pkgs.netbird.io/macos/amd64');
})
}
async assertM1M2DownloadButtonHasCorrectLink() {
await test.step('Assert M1 & M2 download button has a correct link', async () => {
await expect(this.m1M2DownloadButton).toHaveAttribute('href', 'https://pkgs.netbird.io/macos/arm64');
})
}
async assertAndroidDownloadButtonHasCorrectLink() {
await test.step('Assert Android download button has a correct link', async () => {
await expect(this.androidDownloadButton).toHaveAttribute('href', 'https://play.google.com/store/apps/details?id=io.netbird.client');
})
}
async assertDockerDownloadButtonHasCorrectLink() {
await test.step('Assert Docker download button has a correct link', async () => {
await expect(this.dockerDownloadButton).toHaveAttribute('href', 'https://docs.docker.com/engine/install/');
})
}
async closeAddPeerModal() {
await test.step('Close Add peer modal', async () => {
await this.closeButton.click();
})
}
}
export default AddPeerModal;
+15
View File
@@ -0,0 +1,15 @@
import { Page, test } from "@playwright/test";
export class PeersPage {
private readonly addNewPeerButton = this.page.getByTestId('add-new-peer-button')
constructor(private readonly page: Page) {}
async clickOnAddNewPeerButton() {
await test.step('Click on Add new peer Button to open Add peer modal', async () => {
await this.addNewPeerButton.click();
})
}
}
export default PeersPage;
+15
View File
@@ -0,0 +1,15 @@
import { Page, test} from "@playwright/test";
export class TopMenu {
private readonly accessControlButton = this.page.getByTestId('access-control-page')
constructor(private readonly page: Page) {}
async clickOnAccessControlOnTopMenu() {
await test.step('Click on Access Control page on a top menu', async () => {
await this.accessControlButton.click();
})
}
}
export default TopMenu;
+22
View File
@@ -0,0 +1,22 @@
import { test } from '@playwright/test'
import {LoginPage} from '../pages/login-page'
import {AccessControlPage} from '../pages/access-control-page'
let loginPage: LoginPage
let accessControlPage: AccessControlPage
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
await loginPage.doLogin();
});
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();
});
+49
View File
@@ -0,0 +1,49 @@
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
test.beforeEach(async ({ page }) => {
addPeerModal = new AddPeerModal(page);
loginPage = new LoginPage(page);
await loginPage.doLogin();
await addPeerModal.assertPeerModalIsVisible();
});
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 () => {
await addPeerModal.openWindowsTab();
await addPeerModal.assertWindowsDownloadButtonHasCorrectLink();
});
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 () => {
await addPeerModal.openAndroidTab();
await addPeerModal.assertAndroidDownloadButtonHasCorrectLink();
});
test('Test Docker tab on a first access add peer modal', async () => {
await addPeerModal.openDockerTab();
await addPeerModal.assertDockerDownloadButtonHasCorrectLink();
});
test('Close and open Add peer modal', async ({ page }) => {
peersPage = new PeersPage(page);
await addPeerModal.closeAddPeerModal();
await addPeerModal.assertPeerModalIsNotVisible();
await peersPage.clickOnAddNewPeerButton();
await addPeerModal.assertPeerModalIsVisible();
});
+49
View File
@@ -58,6 +58,7 @@
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@playwright/test": "^1.36.2",
"@types/react-syntax-highlighter": "^15.5.3"
}
},
@@ -3087,6 +3088,25 @@
"opener": "^1.5.2"
}
},
"node_modules/@playwright/test": {
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.37.0.tgz",
"integrity": "sha512-181WBLk4SRUyH1Q96VZl7BP6HcK0b7lbdeKisn3N/vnjitk+9HbdlFz/L5fey05vxaAhldIDnzo8KUoy8S3mmQ==",
"dev": true,
"dependencies": {
"@types/node": "*",
"playwright-core": "1.37.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=16"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.7.tgz",
@@ -11712,6 +11732,18 @@
"node": ">=4"
}
},
"node_modules/playwright-core": {
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.37.0.tgz",
"integrity": "sha512-1c46jhTH/myQw6sesrcuHVtLoSNfJv8Pfy9t3rs6subY7kARv0HRw5PpyfPYPpPtQvBOmgbE6K+qgYUpj81LAA==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=16"
}
},
"node_modules/postcss": {
"version": "8.4.16",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
@@ -19234,6 +19266,17 @@
"opener": "^1.5.2"
}
},
"@playwright/test": {
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.37.0.tgz",
"integrity": "sha512-181WBLk4SRUyH1Q96VZl7BP6HcK0b7lbdeKisn3N/vnjitk+9HbdlFz/L5fey05vxaAhldIDnzo8KUoy8S3mmQ==",
"dev": true,
"requires": {
"@types/node": "*",
"fsevents": "2.3.2",
"playwright-core": "1.37.0"
}
},
"@pmmmwh/react-refresh-webpack-plugin": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.7.tgz",
@@ -25594,6 +25637,12 @@
}
}
},
"playwright-core": {
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.37.0.tgz",
"integrity": "sha512-1c46jhTH/myQw6sesrcuHVtLoSNfJv8Pfy9t3rs6subY7kARv0HRw5PpyfPYPpPtQvBOmgbE6K+qgYUpj81LAA==",
"dev": true
},
"postcss": {
"version": "8.4.16",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz",
+2 -1
View File
@@ -79,6 +79,7 @@
]
},
"devDependencies": {
"@types/react-syntax-highlighter": "^15.5.3"
"@types/react-syntax-highlighter": "^15.5.3",
"@playwright/test": "^1.36.2"
}
}
+80
View File
@@ -0,0 +1,80 @@
import { defineConfig, devices } from '@playwright/test';
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// require('dotenv').config();
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './e2e-tests/tests',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://127.0.0.1:3000',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { channel: 'chrome', },
},
// {
// name: 'firefox',
// use: { browserName: 'firefox', },
// },
//
// {
// name: 'webkit',
// use: { browserName: 'webkit', },
// },
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],
/* Run your local dev server before starting the tests */
webServer: {
command: 'npm run start',
url: 'http://127.0.0.1:3000',
reuseExistingServer: !process.env.CI,
timeout: 180 * 1000,
},
});
+3 -1
View File
@@ -64,7 +64,7 @@ const AccessControlEdit = () => {
{ label: "Drop", value: "drop" },
];
const protocols: SelectProps["options"] = [
{ label: "All", value: "all" },
{ label: "ALL", value: "all" },
{ label: "TCP", value: "tcp" },
{ label: "UDP", value: "udp" },
{ label: "ICMP", value: "icmp" },
@@ -461,6 +461,7 @@ const AccessControlEdit = () => {
},
]}
/>
<Card bordered={true} style={{ marginBottom: "7px" }}>
<div style={{ maxWidth: "550px" }}>
<Form
@@ -606,6 +607,7 @@ const AccessControlEdit = () => {
</div>
</Form.Item>
</Col>
<Col span={24}>
<Row gutter={15}>
<Col span={10}>
+1 -1
View File
@@ -67,7 +67,7 @@ const AccessControlNew = () => {
{ label: "Drop", value: "drop" },
];
const protocols: SelectProps["options"] = [
{ label: "All", value: "all" },
{ label: "ALL", value: "all" },
{ label: "TCP", value: "tcp" },
{ label: "UDP", value: "udp" },
{ label: "ICMP", value: "icmp" },
+159 -143
View File
@@ -35,7 +35,9 @@ const { Paragraph, Text } = Typography;
interface formNSGroup extends NameServerGroup {}
const NameServerGroupUpdate = () => {
const NameServerGroupUpdate = (props: any) => {
const { isGroupUpdateView, setShowGroupModal } = props;
const {
blueTagRender,
handleChangeTags,
@@ -121,6 +123,9 @@ const NameServerGroupUpdate = () => {
);
setEditName(false);
setIsPrimary(false);
if (setShowGroupModal) {
setShowGroupModal(false);
}
};
const onChange = (changedValues: any) => {
@@ -553,19 +558,21 @@ const NameServerGroupUpdate = () => {
return (
<>
<Container style={{ paddingTop: "40px" }}>
<Breadcrumb
style={{ marginBottom: "25px" }}
items={[
{
title: <a onClick={onBreadcrumbUsersClick}>DNS</a>,
},
{
title: formNSGroup.name,
},
]}
/>
<Card>
<Container style={{ paddingTop: `${!isGroupUpdateView ? "40px" : "0"}` }}>
{!isGroupUpdateView && (
<Breadcrumb
style={{ marginBottom: "25px" }}
items={[
{
title: <a onClick={onBreadcrumbUsersClick}>DNS</a>,
},
{
title: formNSGroup.name,
},
]}
/>
)}
<Card className={isGroupUpdateView ? "noborderPadding" : ""}>
<Form
layout="vertical"
requiredMark={false}
@@ -573,139 +580,148 @@ const NameServerGroupUpdate = () => {
onValuesChange={onChange}
>
<Row gutter={16}>
<Col span={24}>
<Header
style={{
border: "none",
}}
>
<Row align="top">
<Col flex="auto">
{!editName && formNSGroup.id ? (
<div
className={
"access-control input-text ant-drawer-title"
}
onClick={() => toggleEditName(true)}
style={{
fontSize: "22px",
margin: " 0px 0px 10px",
cursor: "pointer",
fontWeight: "500",
lineHeight: "24px",
}}
>
{formNSGroup.id
? formNSGroup.name
: "New nameserver group"}
</div>
) : (
<Row>
<Col span={8}>
<div style={{ lineHeight: "15px" }}>
<label
style={{
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
}}
>
Name
</label>
<Form.Item
name="name"
rules={[
{
required: true,
message:
"Please add an identifier for this nameserver group",
whitespace: true,
},
{
validator: nameValidator,
},
]}
style={{
marginBottom: "10px",
marginTop: "10px",
}}
>
<Input
placeholder="e.g. Public DNS"
ref={inputNameRef}
onPressEnter={() => toggleEditName(false)}
onBlur={() => toggleEditName(false)}
autoComplete="off"
maxLength={40}
/>
</Form.Item>
</div>
</Col>
</Row>
)}
{!editDescription ? (
<div
className={
"access-control input-text ant-drawer-subtitle"
}
style={{ margin: "0 0 39px 0px" }}
onClick={() => toggleEditDescription(true)}
>
{formNSGroup.description &&
formNSGroup.description.trim() !== ""
? formNSGroup.description
: "Add description"}
</div>
) : (
<Row>
<Col span={8} style={{ marginBottom: "15px" }}>
<span className={isGroupUpdateView ? "d-none" : ""}>
<Col span={24}>
<Header
style={{
border: "none",
}}
>
<Row align="top">
<Col flex="auto">
{!editName && formNSGroup.id ? (
<div
style={{ lineHeight: "15px", marginTop: "24px" }}
className={
"access-control input-text ant-drawer-title"
}
onClick={() => toggleEditName(true)}
style={{
fontSize: "22px",
margin: " 0px 0px 10px",
cursor: "pointer",
fontWeight: "500",
lineHeight: "24px",
}}
>
<label
style={{
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
}}
>
Description
</label>
<Form.Item
name="description"
style={{ marginTop: "8px" }}
>
<Input
placeholder="Add description..."
ref={inputDescriptionRef}
onPressEnter={() =>
toggleEditDescription(false)
}
onBlur={() => toggleEditDescription(false)}
autoComplete="off"
/>
</Form.Item>
{formNSGroup.id
? formNSGroup.name
: "New nameserver group"}
</div>
</Col>
</Row>
)}
</Col>
</Row>
</Header>
</Col>
) : (
<Row>
<Col span={8}>
<div style={{ lineHeight: "15px" }}>
<label
style={{
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
}}
>
Name
</label>
<Form.Item
name="name"
rules={[
{
required: true,
message:
"Please add an identifier for this nameserver group",
whitespace: true,
},
{
validator: nameValidator,
},
]}
style={{
marginBottom: "10px",
marginTop: "10px",
}}
>
<Input
placeholder="e.g. Public DNS"
ref={inputNameRef}
onPressEnter={() => toggleEditName(false)}
onBlur={() => toggleEditName(false)}
autoComplete="off"
maxLength={40}
/>
</Form.Item>
</div>
</Col>
</Row>
)}
{!editDescription ? (
<div
className={
"access-control input-text ant-drawer-subtitle"
}
style={{ margin: "0 0 39px 0px" }}
onClick={() => toggleEditDescription(true)}
>
{formNSGroup.description &&
formNSGroup.description.trim() !== ""
? formNSGroup.description
: "Add description"}
</div>
) : (
<Row>
<Col span={8} style={{ marginBottom: "15px" }}>
<div
style={{
lineHeight: "15px",
marginTop: "24px",
}}
>
<label
style={{
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
}}
>
Description
</label>
<Form.Item
name="description"
style={{ marginTop: "8px" }}
>
<Input
placeholder="Add description..."
ref={inputDescriptionRef}
onPressEnter={() =>
toggleEditDescription(false)
}
onBlur={() =>
toggleEditDescription(false)
}
autoComplete="off"
/>
</Form.Item>
</div>
</Col>
</Row>
)}
</Col>
</Row>
</Header>
</Col>
<Col span={24} style={{ marginBottom: "15px" }}>
<Form.List
name="nameservers"
rules={[{ validator: formListValidator }]}
>
{renderNSList}
</Form.List>
</Col>
<Col span={24} style={{ marginBottom: "15px" }}>
<Form.List
name="nameservers"
rules={[{ validator: formListValidator }]}
>
{renderNSList}
</Form.List>
</Col>
<Col span={24} style={{ marginBottom: "15px" }}>
<Form.List name="domains">{renderDomains}</Form.List>
</Col>
<Col span={24} style={{ marginBottom: "15px" }}>
<Form.List name="domains">{renderDomains}</Form.List>
</Col>
</span>
<Col span={24} style={{ marginBottom: "15px" }}>
<label
style={{
@@ -749,7 +765,7 @@ const NameServerGroupUpdate = () => {
<Space
style={{
display: "flex",
justifyContent: "start",
justifyContent: `${!isGroupUpdateView ? "start" : "end"}`,
width: "100%",
}}
>
+7 -6
View File
@@ -35,12 +35,12 @@ const Navbar = () => {
const [isRefreshingUserState, setIsRefreshingUserState] = useState(false);
const items = [
{ label: <Link to="/peers">Peers</Link>, key: "/peers" },
{ 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 data-testid="peers-page" to="/peers">Peers</Link>, key: "/peers" },
{ label: <Link data-testid="setup-keys-page" to="/setup-keys">Setup Keys</Link>, key: "/setup-keys" },
{ label: <Link data-testid="access-control-page" to="/acls">Access Control</Link>, key: "/acls" },
{ label: <Link data-testid="network-routes-page" to="/routes">Network Routes</Link>, key: "/routes" },
{ label: <Link data-testid="dns-page"to="/dns">DNS</Link>, key: "/dns" },
{ label: <Link data-testid="usersf-page" to="/users">Users</Link>, key: "/users" },
{ label: <Link to="/activity">Activity</Link>, key: "/activity" },
{ label: <Link to="/settings">Settings</Link>, key: "/settings" },
] as ItemType[];
@@ -53,6 +53,7 @@ const Navbar = () => {
"/acls",
"/routes",
"/dns",
"/users",
"/activity",
"/settings",
];
-1
View File
@@ -52,7 +52,6 @@ const { Text } = Typography;
const PeerUpdate = (props: any) => {
const { isGroupUpdateView, setShowGroupModal } = props;
console.log("isGroupUpdateView", isGroupUpdateView);
const { getTokenSilently } = useGetTokenSilently();
const { Column } = Table;
const { confirm } = Modal;
Loaded 20 of 43 files, more files were not shown because too many files have changed in this diff. Show more