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
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
Sarooj bukhari cf42dd52fc fix expiration validation (#252) 2023-08-04 23:30:08 +02:00
Sarooj bukhari bc6842e5b5 Add quick update of group on peer (#250) 2023-08-04 12:03:35 +02:00
Sarooj bukhari a8ed755dda Sidebar menu for Settings (#249)
Replace tab view in the Settings panel with the left-handed
sidebar menu.
2023-08-02 16:14:13 +02:00
Sarooj bukhari a87c06ef52 Groups management (#246) 2023-08-01 21:05:42 +02:00
Sarooj bukhari c0130d265c fix domain validation (#247)
* fix domain validation

* handle on update

* move logic to utils
2023-08-01 10:48:10 +02:00
Misha Bragin 63ced3088a Add public installation page (#248) 2023-07-31 20:21:15 +02:00
Misha Bragin 42b7a15466 Drag custom query params to auth layer (e.g., utm_source) (#244) 2023-07-31 15:16:51 +02:00
Sarooj bukhari c88bfa6476 Add filter by groups in peer (#243) 2023-07-24 17:45:53 +02:00
Maycon Santos c4138a8c45 fix one-off key creation 2023-07-21 20:18:59 +02:00
Sarooj bukhari 3f5418bebc Bug/remove group duplication on select view (#241)
* remove duplicate group on select view to change the logic from name to id

* fix group bug and add grouping on DNS

* fix setup key issue
2023-07-21 19:46:22 +02:00
Maycon Santos f60605e5e3 Allow unset audience (#240)
by setting the AUTH_AUDIENCE=none we will unset the audience value,

not passing that to the requests

This is required for the jumpcloud support
2023-07-21 19:45:37 +02:00
Sarooj bukhari c1b2ededa7 remove duplicate group on select view to change the logic from name to id (#238) 2023-07-20 10:08:26 +02:00
Sarooj bukhari 31eaa4a241 add all filter state on persist on page refresh (#236)
* add all filter state on persist on page refresh

* clear state on logout

* fix issues while refresh
2023-07-20 09:22:01 +02:00
dependabot[bot] ba365336ff Bump word-wrap from 1.2.3 to 1.2.4 (#237)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-19 22:02:03 +05:00
Sarooj bukhari 06c238b013 Fix peer mobile view (#233) 2023-07-18 08:50:58 +02:00
dependabot[bot] ed56c240f3 Bump semver from 6.3.0 to 6.3.1 (#230)
Bumps [semver](https://github.com/npm/node-semver) from 6.3.0 to 6.3.1.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v6.3.1/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v6.3.0...v6.3.1)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-15 01:01:59 +05:00
dependabot[bot] 1f3c7d87d7 Bump tough-cookie from 4.1.2 to 4.1.3 (#223)
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.1.2...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-15 01:01:37 +05:00
Zoltan Papp 9de2906fb2 Extend activity view with group delete (#232) 2023-07-14 10:11:32 +02:00
Sarooj bukhari 359b443326 Update remaining pages layout (#231) 2023-07-14 10:09:08 +02:00
braginini ecae39d94b Adjust DNS view 2023-07-13 12:55:04 +02:00
Sarooj bukhari 30b858c1bc Make all modals UI consistent (#229) 2023-07-12 17:35:55 +02:00
Sarooj bukhari e82b269ff5 fix network routes pages (#228) 2023-07-11 09:06:08 +02:00
braginini 23a4b79f01 Fix disabled links 2023-07-10 18:13:08 +02:00
Sarooj bukhari cc5a9b1033 Fix table loading glitch (#227) 2023-07-10 16:49:52 +02:00
61 changed files with 6195 additions and 3123 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
+6 -1
View File
@@ -22,6 +22,10 @@ if [[ -z "${AUTH_AUDIENCE}" ]]; then
fi
fi
if [[ "${AUTH_AUDIENCE}" == "none" ]]; then
unset AUTH_AUDIENCE
fi
if [[ -z "${AUTH_SUPPORTED_SCOPES}" ]]; then
if [[ -z "${AUTH0_DOMAIN}" ]]; then
echo "AUTH_SUPPORTED_SCOPES environment variable must be set"
@@ -54,11 +58,12 @@ 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}
export NETBIRD_TOKEN_SOURCE=${NETBIRD_TOKEN_SOURCE:-accessToken}
export NETBIRD_DRAG_QUERY_PARAMS=${NETBIRD_DRAG_QUERY_PARAMS:-false}
echo "NetBird latest version: ${NETBIRD_LATEST_VERSION}"
# replace ENVs in the config
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_CLIENT_SECRET \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_HOTJAR_TRACK_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE"
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_CLIENT_SECRET \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_HOTJAR_TRACK_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE \$\$NETBIRD_DRAG_QUERY_PARAMS"
MAIN_JS=$(find /usr/share/nginx/html/static/js/main.*js)
OIDC_TRUSTED_DOMAINS="/usr/share/nginx/html/OidcTrustedDomains.js"
+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
+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, expect } 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;
+33
View File
@@ -0,0 +1,33 @@
import { test, expect } from '@playwright/test';
import {AddPeerModal} from '../pages/modals/add-peer-modal'
import {TopMenu} from '../pages/top-menu';
const URL = 'https://app.netbird.io/'
const localUrl = 'http://localhost:3000/'
let addPeerModal: AddPeerModal;
let topMenu: TopMenu;
test.beforeEach(async ({ page }) => {
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 }) => {
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();
});
+56
View File
@@ -0,0 +1,56 @@
import { test } from '@playwright/test';
import {AddPeerModal} from '../pages/modals/add-peer-modal'
import {PeersPage} from '../pages/peers-page'
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);
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 ({ }) {
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();
});
+166 -84
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",
@@ -58,6 +60,7 @@
"web-vitals": "^2.1.4"
},
"devDependencies": {
"@playwright/test": "^1.36.2",
"@types/react-syntax-highlighter": "^15.5.3"
}
},
@@ -204,9 +207,9 @@
}
},
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -237,9 +240,9 @@
}
},
"node_modules/@babel/eslint-parser/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -311,9 +314,9 @@
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -370,9 +373,9 @@
}
},
"node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -1706,9 +1709,9 @@
}
},
"node_modules/@babel/plugin-transform-runtime/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -1918,9 +1921,9 @@
}
},
"node_modules/@babel/preset-env/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -3087,6 +3090,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",
@@ -3385,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",
@@ -5219,9 +5259,9 @@
}
},
"node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -7467,9 +7507,9 @@
}
},
"node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -7540,9 +7580,9 @@
}
},
"node_modules/eslint-plugin-react/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -9512,9 +9552,9 @@
}
},
"node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -10800,9 +10840,9 @@
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
@@ -11712,6 +11752,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",
@@ -14712,9 +14764,9 @@
}
},
"node_modules/semver": {
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"dependencies": {
"lru-cache": "^6.0.0"
},
@@ -15831,9 +15883,9 @@
}
},
"node_modules/tough-cookie": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
"dependencies": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
@@ -16710,9 +16762,9 @@
}
},
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"engines": {
"node": ">=0.10.0"
}
@@ -17249,9 +17301,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -17271,9 +17323,9 @@
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -17328,9 +17380,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -17371,9 +17423,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -18237,9 +18289,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -18394,9 +18446,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -19234,6 +19286,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",
@@ -19434,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",
@@ -20854,9 +20930,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -22543,9 +22619,9 @@
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -22589,9 +22665,9 @@
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -23955,9 +24031,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -24942,9 +25018,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
}
}
},
@@ -25594,6 +25670,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",
@@ -27566,9 +27648,9 @@
}
},
"semver": {
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"requires": {
"lru-cache": "^6.0.0"
}
@@ -28430,9 +28512,9 @@
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
},
"tough-cookie": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
"requires": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
@@ -29069,9 +29151,9 @@
}
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA=="
},
"workbox-background-sync": {
"version": "6.5.4",
+3
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,6 +81,7 @@
]
},
"devDependencies": {
"@playwright/test": "^1.36.2",
"@types/react-syntax-highlighter": "^15.5.3"
}
}
+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,
},
});
+1 -12
View File
@@ -70,16 +70,7 @@ function App() {
return (
<>
<ConfigProvider
theme={{
token: {
borderRadius: 4,
colorPrimary: "#1890ff",
fontFamily: "Arial"
},
components: {Badge: {fontSizeSM: 20}},
}}
>
<Provider store={store}>
{!show && <SecureLoading padding="3em" width={50} height={50}/>}
{show &&
@@ -124,8 +115,6 @@ function App() {
</Layout>
}
</Provider>
</ConfigProvider>
</>
)
}
+60 -30
View File
@@ -50,7 +50,7 @@ interface FormPolicy {
}
const AccessControlEdit = () => {
const { optionRender, blueTagRender, grayTagRender } =
const { optionRender, blueTagRender, tagGroups, grayTagRender } =
useGetGroupTagHelpers();
const { getTokenSilently } = useGetTokenSilently();
@@ -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" },
@@ -81,7 +81,7 @@ const AccessControlEdit = () => {
biDirectional: false,
reverseDirectional: false,
});
const [tagGroups, setTagGroups] = useState([] as string[]);
// const [tagGroups, setTagGroups] = useState([] as string[]);
const [formPolicy, setFormPolicy] = useState({} as FormPolicy);
const [form] = Form.useForm();
const inputNameRef = useRef<any>(null);
@@ -99,9 +99,9 @@ const AccessControlEdit = () => {
useEffect(() => {
if (editDescription) inputDescriptionRef.current!.focus({ cursor: "end" });
}, [editDescription]);
useEffect(() => {
setTagGroups(groups?.map((g) => g.name) || []);
}, [groups]);
// useEffect(() => {
// setTagGroups(groups?.map((g) => g.name) || []);
// }, [groups]);
useEffect(() => {
if (!policy) return;
const fPolicy = {
@@ -115,10 +115,10 @@ const AccessControlEdit = () => {
ports: policy.rules[0].ports,
action: policy.rules[0].action,
tagSourceGroups: policy.rules[0].sources
? policy.rules[0].sources?.map((t) => t.name)
? policy.rules[0].sources?.map((t) => t.id || "")
: [],
tagDestinationGroups: policy.rules[0].destinations
? policy.rules[0].destinations?.map((t) => t.name)
? policy.rules[0].destinations?.map((t) => t.id || "")
: [],
} as FormPolicy;
setFormPolicy(fPolicy);
@@ -139,17 +139,21 @@ const AccessControlEdit = () => {
const createPolicyToSave = (): PolicyToSave => {
const sources =
groups
?.filter((g) => formPolicy.tagSourceGroups.includes(g.name))
?.filter((g) => formPolicy.tagSourceGroups.includes(g.id || ""))
.map((g) => g.id || "") || [];
const destinations =
groups
?.filter((g) => formPolicy.tagDestinationGroups.includes(g.name))
?.filter((g) => formPolicy.tagDestinationGroups.includes(g.id || ""))
.map((g) => g.id || "") || [];
const existingGroupsNames: any[] = groups?.map((g) => g.id);
const sourcesNoId = formPolicy.tagSourceGroups.filter(
(s) => !tagGroups.includes(s)
(s) => !existingGroupsNames.includes(s)
);
const destinationsNoId = formPolicy.tagDestinationGroups.filter(
(s) => !tagGroups.includes(s)
(s) => !existingGroupsNames.includes(s)
);
const groupsToSave = uniq([...sourcesNoId, ...destinationsNoId]);
return {
@@ -457,11 +461,8 @@ const AccessControlEdit = () => {
},
]}
/>
<Card
bordered={true}
// title={setupKey.name}
style={{ marginBottom: "7px" }}
>
<Card bordered={true} style={{ marginBottom: "7px" }}>
<div style={{ maxWidth: "550px" }}>
<Form
layout="vertical"
@@ -508,7 +509,6 @@ const AccessControlEdit = () => {
<Form.Item
name="name"
label=""
style={{ margin: "0" }}
rules={[
{
required: true,
@@ -532,7 +532,7 @@ const AccessControlEdit = () => {
{!editDescription ? (
<div
style={{
margin: "12px 0 30px",
margin: "0 0 39px",
lineHeight: "22px",
cursor: "pointer",
}}
@@ -551,7 +551,7 @@ const AccessControlEdit = () => {
<Form.Item
name="description"
label="Description"
style={{ marginTop: 24, fontWeight: "500" }}
style={{ marginTop: 10, fontWeight: "500" }}
>
<Input
placeholder="Add description..."
@@ -568,7 +568,7 @@ const AccessControlEdit = () => {
</Row>
</Header>
</Col>
<Col span={24}>
<Col span={24} style={{ marginBottom: "15px" }}>
<Form.Item name="enabled" label="">
<div
style={{
@@ -579,6 +579,7 @@ const AccessControlEdit = () => {
<Switch
onChange={handleChangeDisabled}
defaultChecked={policy.enabled}
size="small"
/>
<div>
<label
@@ -606,6 +607,7 @@ const AccessControlEdit = () => {
</div>
</Form.Item>
</Col>
<Col span={24}>
<Row gutter={15}>
<Col span={10}>
@@ -622,9 +624,16 @@ const AccessControlEdit = () => {
tagRender={blueTagRender}
onChange={handleChangeSource}
dropdownRender={dropDownRenderGroups}
optionFilterProp="serchValue"
>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
{tagGroups.map((m, index) => (
<Option
key={index}
value={m.id}
serchValue={m.name}
>
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
</Form.Item>
@@ -775,16 +784,23 @@ const AccessControlEdit = () => {
tagRender={blueTagRender}
onChange={handleChangeDestination}
dropdownRender={dropDownRenderGroups}
optionFilterProp="serchValue"
>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
{tagGroups.map((m, index) => (
<Option
key={index}
value={m.id}
serchValue={m.name}
>
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
</Form.Item>
</Col>
</Row>
</Col>
<Col span={24}>
<Col span={24} style={{ marginBottom: "15px" }}>
<Paragraph
type={"secondary"}
style={{ marginTop: "-15px", marginBottom: "30px" }}
@@ -793,7 +809,7 @@ const AccessControlEdit = () => {
protocol below
</Paragraph>
</Col>
<Col span={24}>
<Col span={24} style={{ marginBottom: "15px" }}>
<Row>
<Col span={10}>
<Form.Item
@@ -830,7 +846,14 @@ const AccessControlEdit = () => {
maxWidth: "260px",
fontWeight: "500",
}}
placeholder={<div color={"rgba(0,0,0,0.25)"} className="arimo-font">Select ports</div>}
placeholder={
<div
color={"rgba(0,0,0,0.25)"}
className="arimo-font"
>
Select ports
</div>
}
className="menlo-font"
value={formPolicyCopy}
disabled={true}
@@ -862,7 +885,14 @@ const AccessControlEdit = () => {
maxWidth: "260px",
fontWeight: "500",
}}
placeholder={<div color={"rgba(0,0,0,0.25)"} className="arimo-font">Select ports</div>}
placeholder={
<div
color={"rgba(0,0,0,0.25)"}
className="arimo-font"
>
Select ports
</div>
}
tagRender={grayTagRender}
onChange={handleChangePorts}
className="menlo-font"
@@ -890,7 +920,7 @@ const AccessControlEdit = () => {
justifyContent: "start",
padding: 0,
gap: "10px",
marginTop: "30px",
marginTop: "12px",
}}
key={0}
>
+52 -23
View File
@@ -50,8 +50,12 @@ interface FormPolicy {
}
const AccessControlNew = () => {
const { optionRender, grayTagRender, blueTagRender } =
useGetGroupTagHelpers();
const {
optionRender,
blueTagRender,
tagGroups,
grayTagRender,
} = useGetGroupTagHelpers();
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
const setupNewPolicyVisible = useSelector(
@@ -63,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" },
@@ -81,7 +85,7 @@ const AccessControlNew = () => {
biDirectional: true,
reverseDirectional: true,
});
const [tagGroups, setTagGroups] = useState([] as string[]);
// const [tagGroups, setTagGroups] = useState([] as string[]);
const [formPolicy, setFormPolicy] = useState({} as FormPolicy);
const [form] = Form.useForm();
const inputNameRef = useRef<any>(null);
@@ -93,9 +97,9 @@ const AccessControlNew = () => {
useEffect(() => {
if (editDescription) inputDescriptionRef.current!.focus({ cursor: "end" });
}, [editDescription]);
useEffect(() => {
setTagGroups(groups?.map((g) => g.name) || []);
}, [groups]);
// useEffect(() => {
// setTagGroups(groups?.map((g) => g.name) || []);
// }, [groups]);
useEffect(() => {
if (!policy) return;
const fPolicy = {
@@ -122,19 +126,26 @@ const AccessControlNew = () => {
const createPolicyToSave = (): PolicyToSave => {
const sources =
groups
?.filter((g) => formPolicy.tagSourceGroups.includes(g.name))
?.filter((g) => formPolicy.tagSourceGroups.includes(g.id || ""))
.map((g) => g.id || "") || [];
const destinations =
groups
?.filter((g) => formPolicy.tagDestinationGroups.includes(g.name))
?.filter((g) => formPolicy.tagDestinationGroups.includes(g.id || ""))
.map((g) => g.id || "") || [];
const existingGroupsNames: any[] = groups?.map((g) => g.id);
const sourcesNoId = formPolicy.tagSourceGroups.filter(
(s) => !tagGroups.includes(s)
(s) => !existingGroupsNames.includes(s)
);
const destinationsNoId = formPolicy.tagDestinationGroups.filter(
(s) => !tagGroups.includes(s)
(s) => !existingGroupsNames.includes(s)
);
const groupsToSave = uniq([...sourcesNoId, ...destinationsNoId]);
return {
id: formPolicy.id,
name: formPolicy.name,
@@ -456,18 +467,20 @@ const AccessControlNew = () => {
textAlign: "start",
whiteSpace: "pre-line",
fontSize: "18px",
margin: "0px",
fontWeight: "500",
}}
>
Create Rule
Create rule
</Paragraph>
<Paragraph
type={"secondary"}
style={{
textAlign: "start",
whiteSpace: "pre-line",
paddingBottom: "15px",
marginTop: "-20px",
fontSize: "14px",
paddingBottom: "25px",
marginBottom: "4px",
}}
>
Use this rule to restrict access to groups of resources
@@ -560,9 +573,12 @@ const AccessControlNew = () => {
tagRender={blueTagRender}
onChange={handleChangeSource}
dropdownRender={dropDownRenderGroups}
optionFilterProp="serchValue"
>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
</Form.Item>
@@ -713,9 +729,12 @@ const AccessControlNew = () => {
tagRender={blueTagRender}
onChange={handleChangeDestination}
dropdownRender={dropDownRenderGroups}
optionFilterProp="serchValue"
>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
</Form.Item>
@@ -767,6 +786,8 @@ const AccessControlNew = () => {
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
padding: "0 0 2px",
display: "inline-block",
}}
>
Ports
@@ -828,9 +849,16 @@ const AccessControlNew = () => {
className="menlo-font"
placeholder={
formPolicy.protocol === "all" ||
formPolicy.protocol === "icmp"
? "All"
: (<div color={"rgba(0,0,0,0.25)"} className="arimo-font">Select ports</div>)
formPolicy.protocol === "icmp" ? (
"All"
) : (
<div
color={"rgba(0,0,0,0.25)"}
className="arimo-font"
>
Select ports
</div>
)
}
tagRender={grayTagRender}
onChange={handleChangePorts}
@@ -859,6 +887,7 @@ const AccessControlNew = () => {
}}
>
<Switch
size="small"
onChange={handleChangeDisabled}
defaultChecked={true}
/>
@@ -890,7 +919,7 @@ const AccessControlNew = () => {
</Col>
<Col
span={24}
style={{ marginTop: "20px", marginBottom: "25px" }}
style={{ marginTop: "10px", marginBottom: "24px" }}
>
<Text type={"secondary"}>
Learn more about
@@ -900,7 +929,7 @@ const AccessControlNew = () => {
href="https://docs.netbird.io/how-to/manage-network-access"
>
{" "}
Access Controls
access controls
</a>
</Text>
</Col>
View File
Whitespace-only changes.
+130 -142
View File
@@ -32,6 +32,7 @@ import {
} from "../store/nameservers/types";
import { useGetGroupTagHelpers } from "../utils/groups";
import { useGetTokenSilently } from "../utils/token";
import { domainValidator } from "../utils/common";
const { Paragraph, Text } = Typography;
@@ -272,21 +273,6 @@ const NameServerGroupAdd = () => {
setEditDescription(status);
};
const domainRegex =
/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/;
const domainValidator = (_: RuleObject, domain: string) => {
if (domainRegex.test(domain)) {
return Promise.resolve();
}
setIsPrimary(false);
return Promise.reject(
new Error(
"Please enter a valid domain, e.g. example.com or intra.example.com"
)
);
};
const nameValidator = (_: RuleObject, value: string) => {
const found = nsGroupData.find(
(u) => u.name == value && u.id !== formNSGroup.id
@@ -331,121 +317,117 @@ const NameServerGroupAdd = () => {
{ add, remove }: any,
{ errors }: any
) => (
<Col>
<div style={{ width: "100%", maxWidth: "360px" }}>
<label
style={{
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
marginBottom: "10px",
display: "block",
}}
>
Nameservers
</label>
<div style={{ width: "100%", maxWidth: "360px" }}>
<label
style={{
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
marginBottom: "10px",
display: "block",
}}
>
Nameservers
</label>
{!!fields.length && (
<Row align="middle">
<Col span={4} style={{ textAlign: "left" }}>
<Typography.Text
style={{ color: "#818183", paddingLeft: "5px" }}
></Typography.Text>
</Col>
<Col span={10} style={{ textAlign: "left" }}>
<Typography.Text style={{ color: "#818183", paddingLeft: "5px" }}>
Nameserver IP
</Typography.Text>
</Col>
<Col span={4} style={{ textAlign: "left" }}>
<Typography.Text style={{ color: "#818183", paddingLeft: "5px" }}>
Port
</Typography.Text>
</Col>
<Col span={4} />
</Row>
)}
{fields.map((field, index) => {
return (
<Row key={index}>
<Col span={4} style={{ textAlign: "left" }}>
<Form.Item
style={{ margin: "3px" }}
name={[field.name, "ns_type"]}
rules={[
{ required: true, message: "Missing first protocol" },
]}
initialValue={"udp"}
>
<Select
disabled
style={{ width: "100%" }}
className="style-like-text"
>
<Option value="udp">UDP</Option>
</Select>
</Form.Item>
</Col>
<Col span={10} style={{ margin: "1px" }}>
<Form.Item
style={{ margin: "1px" }}
name={[field.name, "ip"]}
rules={[{ validator: ipValidator }]}
>
<Input
placeholder="e.g. X.X.X.X"
style={{ width: "100%" }}
autoComplete="off"
/>
</Form.Item>
</Col>
<Col span={4} style={{ textAlign: "center" }}>
<Form.Item
style={{ margin: "1px" }}
name={[field.name, "port"]}
rules={[{ required: true, message: "Missing port" }]}
initialValue={53}
>
<InputNumber placeholder="Port" style={{ width: "100%" }} />
</Form.Item>
</Col>
<Col
span={2}
style={{
textAlign: "center",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<MinusCircleOutlined onClick={() => remove(field.name)} />
</Col>
</Row>
);
})}
<Row>
<Col span={20}>
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
block
style={{
maxWidth: "270px",
marginTop: "5px",
}}
disabled={fields.length > 1}
icon={<PlusOutlined />}
>
Add Nameserver
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
{!!fields.length && (
<Row align="middle">
<Col span={4} style={{ textAlign: "left" }}>
<Typography.Text
style={{ color: "#818183", paddingLeft: "5px" }}
></Typography.Text>
</Col>
<Col span={10} style={{ textAlign: "left" }}>
<Typography.Text style={{ color: "#818183", paddingLeft: "5px" }}>
Nameserver IP
</Typography.Text>
</Col>
<Col span={4} style={{ textAlign: "left" }}>
<Typography.Text style={{ color: "#818183", paddingLeft: "5px" }}>
Port
</Typography.Text>
</Col>
<Col span={4} />
</Row>
</div>
</Col>
)}
{fields.map((field, index) => {
return (
<Row key={index}>
<Col span={4} style={{ textAlign: "left" }}>
<Form.Item
style={{ margin: "3px" }}
name={[field.name, "ns_type"]}
rules={[{ required: true, message: "Missing first protocol" }]}
initialValue={"udp"}
>
<Select
disabled
style={{ width: "100%" }}
className="style-like-text"
>
<Option value="udp">UDP</Option>
</Select>
</Form.Item>
</Col>
<Col span={10} style={{ margin: "1px" }}>
<Form.Item
style={{ margin: "1px" }}
name={[field.name, "ip"]}
rules={[{ validator: ipValidator }]}
>
<Input
placeholder="e.g. X.X.X.X"
style={{ width: "100%" }}
autoComplete="off"
/>
</Form.Item>
</Col>
<Col span={4} style={{ textAlign: "center" }}>
<Form.Item
style={{ margin: "1px" }}
name={[field.name, "port"]}
rules={[{ required: true, message: "Missing port" }]}
initialValue={53}
>
<InputNumber placeholder="Port" style={{ width: "100%" }} />
</Form.Item>
</Col>
<Col
span={2}
style={{
textAlign: "center",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<MinusCircleOutlined onClick={() => remove(field.name)} />
</Col>
</Row>
);
})}
<Row>
<Col span={20}>
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
block
style={{
maxWidth: "270px",
marginTop: "5px",
}}
disabled={fields.length > 1}
icon={<PlusOutlined />}
>
Add nameserver
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
</Col>
</Row>
</div>
);
// @ts-ignore
@@ -470,9 +452,9 @@ const NameServerGroupAdd = () => {
<Paragraph
type={"secondary"}
style={{
marginTop: "-2",
marginTop: "-4px",
fontWeight: "400",
marginBottom: "0",
marginBottom: "4px",
}}
>
Add domain if you want to have a specific one
@@ -556,18 +538,20 @@ const NameServerGroupAdd = () => {
textAlign: "start",
whiteSpace: "pre-line",
fontSize: "18px",
margin: "0px",
fontWeight: "500",
}}
>
Add Nameserver
Add nameserver
</Paragraph>
<Paragraph
type={"secondary"}
style={{
textAlign: "start",
whiteSpace: "pre-line",
paddingBottom: "0",
marginTop: "-20px",
fontSize: "14px",
paddingBottom: "25px",
marginBottom: "4px",
}}
>
Use this nameserver to resolve domains in your network
@@ -706,7 +690,7 @@ const NameServerGroupAdd = () => {
</Row>
</Header>
</Col>
<Col span={24} flex="auto">
<Col span={24}>
<Form.List
name="nameservers"
rules={[{ validator: formListValidator }]}
@@ -714,7 +698,7 @@ const NameServerGroupAdd = () => {
{renderNSList}
</Form.List>
</Col>
<Col span={24} flex="auto">
<Col span={24}>
<Form.List name="domains">{renderDomains}</Form.List>
</Col>
<Col span={24}>
@@ -730,9 +714,9 @@ const NameServerGroupAdd = () => {
<Paragraph
type={"secondary"}
style={{
marginTop: "-2",
marginTop: "-4px",
fontWeight: "400",
marginBottom: "0",
marginBottom: "4px",
}}
>
Advertise this route to peers that belong to the following
@@ -749,9 +733,12 @@ const NameServerGroupAdd = () => {
tagRender={blueTagRender}
onChange={handleChangeTags}
dropdownRender={dropDownRender}
optionFilterProp="serchValue"
>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name, m.id)}
</Option>
))}
</Select>
</Form.Item>
@@ -787,8 +774,9 @@ const NameServerGroupAdd = () => {
marginBottom: "0",
}}
>
Disable this server if you don't want it to apply
immediately
{formNSGroup.enabled
? "Disable this server if you don't want it to apply immediately"
: " Enable this server if you want it to apply immediately"}
</Paragraph>
</div>
</div>
@@ -796,7 +784,7 @@ const NameServerGroupAdd = () => {
</Col>
<Col
span={24}
style={{ marginTop: "10px", marginBottom: "20px" }}
style={{ marginTop: "10px", marginBottom: "24px" }}
>
<Text type={"secondary"}>
Learn more about
@@ -830,7 +818,7 @@ const NameServerGroupAdd = () => {
onClick={handleFormSubmit}
disabled={savedNSGroup.loading}
>
Create Nameserver
Create nameserver
</Button>
</Space>
</Col>
File diff suppressed because it is too large. Load diff
Loaded 20 of 61 files, more files were not shown because too many files have changed in this diff. Show more