Compare commits

...
30 Commits
Author SHA1 Message Date
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
Sarooj bukhari 09ae157be3 Re-work DNS layout (#222) 2023-07-10 09:03:27 +02:00
pascal-fischer cb89eeb921 Fix default value for expiration for setup keys (#221)
* fix initial value for setup keys so default works

* fix initial value for setup keys so default works
2023-07-07 12:40:51 +02:00
pascal-fischer 79446c0e77 remove formatted expiry logic and fix sent expires_in (#220) 2023-07-06 17:16:10 +02:00
Zoltan Papp 1f258e4e2c Update copyright title at the bottom of the page (#219) 2023-07-06 16:38:02 +02:00
50 changed files with 6236 additions and 3409 deletions

No files matched your search

+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"
+84 -84
View File
@@ -204,9 +204,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 +237,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 +311,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 +370,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 +1706,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 +1918,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"
}
@@ -5219,9 +5219,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 +7467,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 +7540,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 +9512,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 +10800,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"
}
@@ -14712,9 +14712,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 +15831,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 +16710,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 +17249,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 +17271,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 +17328,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 +17371,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 +18237,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 +18394,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=="
}
}
},
@@ -20854,9 +20854,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 +22543,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 +22589,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 +23955,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 +24942,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=="
}
}
},
@@ -27566,9 +27566,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 +28430,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 +29069,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",
+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>
+2 -2
View File
@@ -6,7 +6,7 @@ const { Footer } = Layout
export default () => {
return (
<Footer style={{ textAlign: 'center', bottom: "0"}}>
Copyright © 2022 <a href="https://netbird.io">NetBird Authors</a>
Copyright © 2023 <a href="https://netbird.io">NetBird Authors</a>
</Footer>
);
};
};
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+225 -167
View File
@@ -1,185 +1,243 @@
import React, {useEffect, useState} from 'react';
import {Link, useLocation} from 'react-router-dom';
import React, { useEffect, useState } from "react";
import { Link, useLocation } from "react-router-dom";
import logo from "../assets/logo.png";
import {Avatar, Button, Col, Dropdown, Grid, Menu, Row} from 'antd'
import {ItemType} from "antd/lib/menu/hooks/useItems";
import {AvatarSize} from "antd/es/avatar/SizeContext";
import {UserOutlined} from '@ant-design/icons';
import {useOidc, useOidcIdToken, useOidcUser} from '@axa-fr/react-oidc';
import {getConfig} from "../config";
import {User} from "../store/user/types";
import {useDispatch, useSelector} from "react-redux";
import {RootState} from "typesafe-actions";
import {actions as userActions} from "../store/user";
import {useGetTokenSilently} from "../utils/token";
import {actions as personalAccessTokenActions} from "../store/personal-access-token";
import { Avatar, Button, Col, Dropdown, Grid, Menu, Row } from "antd";
import { ItemType } from "antd/lib/menu/hooks/useItems";
import { AvatarSize } from "antd/es/avatar/SizeContext";
import { UserOutlined } from "@ant-design/icons";
import { useOidc, useOidcIdToken, useOidcUser } from "@axa-fr/react-oidc";
import { getConfig } from "../config";
import { User } from "../store/user/types";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "typesafe-actions";
import { actions as userActions } from "../store/user";
import { useGetTokenSilently } from "../utils/token";
import { actions as personalAccessTokenActions } from "../store/personal-access-token";
const {useBreakpoint} = Grid;
const { useBreakpoint } = Grid;
const Navbar = () => {
let location = useLocation();
const config = getConfig();
const { logout } = useOidc();
const {getTokenSilently} = useGetTokenSilently()
const dispatch = useDispatch()
let location = useLocation();
const config = getConfig();
const { logout } = useOidc();
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
const {oidcUser} = useOidcUser();
const {idTokenPayload} = useOidcIdToken()
const user = oidcUser;
const [currentUser, setCurrentUser] = useState({} as User)
const { oidcUser } = useOidcUser();
const { idTokenPayload } = useOidcIdToken();
const user = oidcUser;
const [currentUser, setCurrentUser] = useState({} as User);
const screens = useBreakpoint();
const screens = useBreakpoint();
const [hideMenuUser, setHideMenuUser] = useState(false)
const users = useSelector((state: RootState) => state.user.data)
const [isRefreshingUserState, setIsRefreshingUserState] = useState(false)
const [hideMenuUser, setHideMenuUser] = useState(false);
const users = useSelector((state: RootState) => state.user.data);
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 to="/activity">Activity</Link>), key: '/activity'},
{label: (<Link to="/settings">Settings</Link>), key: '/settings'}
] as ItemType[]
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 to="/activity">Activity</Link>, key: "/activity" },
{ label: <Link to="/settings">Settings</Link>, key: "/settings" },
] as ItemType[];
const userEmailKey = 'user-email'
const userLogoutKey = 'user-logout'
const userDividerKey = 'user-divider'
const adminOnlyTabs = ["/setup-keys", "/acls", "/routes", "/dns", "/activity", "/settings"]
const [menuItems, setMenuItems] = useState(items)
const logoutWithRedirect = () =>
logout("/", {client_id: config.clientId});
const userEmailKey = "user-email";
const userLogoutKey = "user-logout";
const userDividerKey = "user-divider";
const adminOnlyTabs = [
"/setup-keys",
"/acls",
"/routes",
"/dns",
"/activity",
"/settings",
];
const [menuItems, setMenuItems] = useState(items);
const logoutWithRedirect = () => {
let lRemove = [
"peerFilter",
"setupKeysFilter",
"accessControlFilter",
"routesFilter",
"nameServerFilter",
"userFilter",
"serviceUserFilter",
"activityFilter",
];
lRemove.forEach((element) => {
localStorage.removeItem(element);
});
logout("/", { client_id: config.clientId });
};
const openPersonalUserPage = () => {
dispatch(userActions.setUser({
id: currentUser.id,
email: currentUser.email,
role: currentUser.role,
auto_groups: currentUser.auto_groups ? currentUser.auto_groups : [],
name: currentUser.name,
is_current: currentUser.is_current,
is_service_user: currentUser.is_service_user,
} as User));
dispatch(userActions.setUserTabOpen("Users"));
dispatch(userActions.setEditUserPopupVisible(true));
}
useEffect(() => {
const fs = items.filter(m => showTab(m?.key?.toString(), currentUser) && m?.key !== userEmailKey && m?.key !== userLogoutKey && m?.key !== userDividerKey)
if (screens.xs === true) {
setHideMenuUser(false)
fs.push({type: 'divider', key: userDividerKey})
fs.push({
label: (
<Link to="#">{user?.name}</Link>
),
icon: createAvatar("small"),
key: userEmailKey
})
fs.push({
label: (<Button type="link" block onClick={logoutWithRedirect}>Logout</Button>),
key: userLogoutKey
})
setMenuItems([...fs])
return
}
setMenuItems([...fs])
setHideMenuUser(true)
}, [screens, currentUser])
useEffect(() => {
if (users.length === 0 && !isRefreshingUserState &&
window.location.pathname !== '/peers' &&
window.location.pathname !== '/users') {
setIsRefreshingUserState(true)
dispatch(userActions.getUsers.request({getAccessTokenSilently: getTokenSilently, payload: null}))
return
}
if (users.length === 0 && isRefreshingUserState) {
return
}
let runUser = oidcUser
if (!oidcUser) {
runUser = idTokenPayload
}
setIsRefreshingUserState(false)
if (runUser) {
const found = users.find(u => u.is_current ? u.is_current : runUser.sub ? u.id == runUser.sub : false)
if (found) {
setCurrentUser(found)
}
}
}, [users, oidcUser])
const showTab = (key: string | undefined, user: User | undefined) => {
if (!user) {
return false
}
if (user.role?.toLowerCase() === "admin") {
return true
}
return !adminOnlyTabs.find(t => t === key)
}
const menuUser = (
<Menu
items={[
{
label: (<Link to="/users" onClick={openPersonalUserPage}>{user?.email}</Link>),
key: '0',
},
{
label: (<Link to="/logout" onClick={logoutWithRedirect}>Logout</Link>),
key: '1',
}
]}
/>
const openPersonalUserPage = () => {
dispatch(
userActions.setUser({
id: currentUser.id,
email: currentUser.email,
role: currentUser.role,
auto_groups: currentUser.auto_groups ? currentUser.auto_groups : [],
name: currentUser.name,
is_current: currentUser.is_current,
is_service_user: currentUser.is_service_user,
} as User)
);
dispatch(userActions.setUserTabOpen("Users"));
dispatch(userActions.setEditUserPopupVisible(true));
};
const createAvatar = (size: AvatarSize) => {
return user?.picture ? (
<Avatar size={size} src={user?.picture} icon={<UserOutlined/>}/>
) : (
<Avatar size={size}>{(user?.name || '').slice(0, 1).toUpperCase()}</Avatar>
)
useEffect(() => {
const fs = items.filter(
(m) =>
showTab(m?.key?.toString(), currentUser) &&
m?.key !== userEmailKey &&
m?.key !== userLogoutKey &&
m?.key !== userDividerKey
);
if (screens.xs === true) {
setHideMenuUser(false);
fs.push({ type: "divider", key: userDividerKey });
fs.push({
label: <Link to="#">{user?.name}</Link>,
icon: createAvatar("small"),
key: userEmailKey,
});
fs.push({
label: (
<Button type="link" block onClick={logoutWithRedirect}>
Logout
</Button>
),
key: userLogoutKey,
});
setMenuItems([...fs]);
return;
}
setMenuItems([...fs]);
setHideMenuUser(true);
}, [screens, currentUser]);
useEffect(() => {
if (
users.length === 0 &&
!isRefreshingUserState &&
window.location.pathname !== "/peers" &&
window.location.pathname !== "/users"
) {
setIsRefreshingUserState(true);
dispatch(
userActions.getUsers.request({
getAccessTokenSilently: getTokenSilently,
payload: null,
})
);
return;
}
if (users.length === 0 && isRefreshingUserState) {
return;
}
let runUser = oidcUser;
if (!oidcUser) {
runUser = idTokenPayload;
}
setIsRefreshingUserState(false);
if (runUser) {
const found = users.find((u) =>
u.is_current ? u.is_current : runUser.sub ? u.id == runUser.sub : false
);
if (found) {
setCurrentUser(found);
}
}
}, [users, oidcUser]);
const showTab = (key: string | undefined, user: User | undefined) => {
if (!user) {
return false;
}
return (
<>
<Row justify="space-evenly" align="middle">
<Col flex="0 1 60px">
<Link id="logo" to="/">
<img
alt="logo"
style={{width: "55px"}}
src={logo}
/>
</Link>
</Col>
<Col flex="1 1 auto">
<div>
<Menu mode="horizontal" selectable={true} selectedKeys={[location.pathname]}
onSelect={(e) => {
dispatch(userActions.setUser(null as unknown as User));
dispatch(personalAccessTokenActions.resetPersonalAccessTokens(null))
}}
defaultSelectedKeys={[location.pathname]} items={menuItems}/>
</div>
</Col>
{hideMenuUser &&
<Col>
<Dropdown overlay={menuUser} placement="bottomRight" trigger={['click']}>
{createAvatar("large")}
</Dropdown>
</Col>
}
</Row>
</>
if (user.role?.toLowerCase() === "admin") {
return true;
}
return !adminOnlyTabs.find((t) => t === key);
};
const menuUser = (
<Menu
items={[
{
label: (
<Link to="/users" onClick={openPersonalUserPage}>
{user?.email}
</Link>
),
key: "0",
},
{
label: (
<Link to="/logout" onClick={logoutWithRedirect}>
Logout
</Link>
),
key: "1",
},
]}
/>
);
const createAvatar = (size: AvatarSize) => {
return user?.picture ? (
<Avatar size={size} src={user?.picture} icon={<UserOutlined />} />
) : (
<Avatar size={size}>
{(user?.name || "").slice(0, 1).toUpperCase()}
</Avatar>
);
};
return (
<>
<Row justify="space-evenly" align="middle">
<Col flex="0 1 60px">
<Link id="logo" to="/">
<img alt="logo" style={{ width: "55px" }} src={logo} />
</Link>
</Col>
<Col flex="1 1 auto">
<div>
<Menu
mode="horizontal"
selectable={true}
selectedKeys={[location.pathname]}
onSelect={(e) => {
dispatch(userActions.setUser(null as unknown as User));
dispatch(
personalAccessTokenActions.resetPersonalAccessTokens(null)
);
}}
defaultSelectedKeys={[location.pathname]}
items={menuItems}
/>
</div>
</Col>
{hideMenuUser && (
<Col>
<Dropdown
overlay={menuUser}
placement="bottomRight"
trigger={["click"]}
>
{createAvatar("large")}
</Dropdown>
</Col>
)}
</Row>
</>
);
};
export default Navbar;
File diff suppressed because it is too large. Load diff
+55 -54
View File
@@ -123,8 +123,7 @@ const RouteAddNew = (selectedPeer: any) => {
} else {
setNewRoute(false);
}
}, [route]);
}, [route]);
selectedPeer &&
selectedPeer.notPeerRoutes &&
@@ -362,54 +361,53 @@ const RouteAddNew = (selectedPeer: any) => {
}
};
const styleNotification = { marginTop: 85 };
const styleNotification = { marginTop: 85 };
const saveKey = "saving";
useEffect(() => {
if (savedRoute.loading) {
message.loading({
content: "Saving...",
key: saveKey,
duration: 0,
style: styleNotification,
});
} else if (savedRoute.success) {
message.success({
content: "Route has been successfully added.",
key: saveKey,
duration: 2,
style: styleNotification,
});
dispatch(routeActions.setSetupNewRouteVisible(false));
dispatch(routeActions.setSetupEditRouteVisible(false));
dispatch(routeActions.setSetupEditRoutePeerVisible(false));
dispatch(routeActions.setSavedRoute({ ...savedRoute, success: false }));
dispatch(routeActions.resetSavedRoute(null));
} else if (savedRoute.error) {
let errorMsg = "Failed to update network route";
switch (savedRoute.error.statusCode) {
case 403:
errorMsg =
"Failed to update network route. You might not have enough permissions.";
break;
default:
errorMsg = savedRoute.error.data.message
? savedRoute.error.data.message
: errorMsg;
break;
}
message.error({
content: errorMsg,
key: saveKey,
duration: 5,
style: styleNotification,
});
dispatch(routeActions.setSavedRoute({ ...savedRoute, error: null }));
dispatch(routeActions.resetSavedRoute(null));
const saveKey = "saving";
useEffect(() => {
if (savedRoute.loading) {
message.loading({
content: "Saving...",
key: saveKey,
duration: 0,
style: styleNotification,
});
} else if (savedRoute.success) {
message.success({
content: "Route has been successfully added.",
key: saveKey,
duration: 2,
style: styleNotification,
});
dispatch(routeActions.setSetupNewRouteVisible(false));
dispatch(routeActions.setSetupEditRouteVisible(false));
dispatch(routeActions.setSetupEditRoutePeerVisible(false));
dispatch(routeActions.setSavedRoute({ ...savedRoute, success: false }));
dispatch(routeActions.resetSavedRoute(null));
} else if (savedRoute.error) {
let errorMsg = "Failed to update network route";
switch (savedRoute.error.statusCode) {
case 403:
errorMsg =
"Failed to update network route. You might not have enough permissions.";
break;
default:
errorMsg = savedRoute.error.data.message
? savedRoute.error.data.message
: errorMsg;
break;
}
}, [savedRoute]);
message.error({
content: errorMsg,
key: saveKey,
duration: 5,
style: styleNotification,
});
dispatch(routeActions.setSavedRoute({ ...savedRoute, error: null }));
dispatch(routeActions.resetSavedRoute(null));
}
}, [savedRoute]);
return (
<>
{route && (
@@ -426,7 +424,7 @@ const RouteAddNew = (selectedPeer: any) => {
disabled={savedRoute.loading}
onClick={handleFormSubmit}
>
Add Route
Add route
</Button>
</Space>
}
@@ -455,7 +453,7 @@ const RouteAddNew = (selectedPeer: any) => {
marginBottom: "25px",
}}
>
Add Route
Add route
</Paragraph>
{!!selectedPeer.selectedPeer && (
@@ -734,9 +732,12 @@ const RouteAddNew = (selectedPeer: any) => {
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>
@@ -887,7 +888,7 @@ const RouteAddNew = (selectedPeer: any) => {
</Col>
<Col
span={24}
style={{ marginTop: "20px", marginBottom: "25px" }}
style={{ marginTop: "24px", marginBottom: "12px" }}
>
<Text type={"secondary"}>
Learn more about
@@ -897,7 +898,7 @@ const RouteAddNew = (selectedPeer: any) => {
href="https://docs.netbird.io/how-to/routing-traffic-to-private-networks"
>
{" "}
Network Routes
network routes
</a>
</Text>
</Col>
+52 -50
View File
@@ -73,7 +73,7 @@ const RoutePeerUpdate = () => {
if (!route) return;
const fRoute = {
...route,
groups: getGroupNamesFromIDs(route.groups),
groups: route.groups,
} as FormRoute;
setFormRoute(fRoute);
form.setFieldsValue(fRoute);
@@ -222,54 +222,53 @@ const RoutePeerUpdate = () => {
onCancel();
};
const styleNotification = { marginTop: 85 };
const styleNotification = { marginTop: 85 };
const saveKey = "saving";
useEffect(() => {
if (savedRoute.loading) {
message.loading({
content: "Saving...",
key: saveKey,
duration: 0,
style: styleNotification,
});
} else if (savedRoute.success) {
console.log("savedRoute", savedRoute);
message.success({
content: "Route has been successfully updated.",
key: saveKey,
duration: 2,
style: styleNotification,
});
dispatch(routeActions.setSetupNewRouteVisible(false));
dispatch(routeActions.setSetupEditRouteVisible(false));
dispatch(routeActions.setSetupEditRoutePeerVisible(false));
dispatch(routeActions.setSavedRoute({ ...savedRoute, success: false }));
dispatch(routeActions.resetSavedRoute(null));
} else if (savedRoute.error) {
let errorMsg = "Failed to update network route";
switch (savedRoute.error.statusCode) {
case 403:
errorMsg =
"Failed to update network route. You might not have enough permissions.";
break;
default:
errorMsg = savedRoute.error.data.message
? savedRoute.error.data.message
: errorMsg;
break;
}
message.error({
content: errorMsg,
key: saveKey,
duration: 5,
style: styleNotification,
});
dispatch(routeActions.setSavedRoute({ ...savedRoute, error: null }));
dispatch(routeActions.resetSavedRoute(null));
const saveKey = "saving";
useEffect(() => {
if (savedRoute.loading) {
message.loading({
content: "Saving...",
key: saveKey,
duration: 0,
style: styleNotification,
});
} else if (savedRoute.success) {
message.success({
content: "Route has been successfully updated.",
key: saveKey,
duration: 2,
style: styleNotification,
});
dispatch(routeActions.setSetupNewRouteVisible(false));
dispatch(routeActions.setSetupEditRouteVisible(false));
dispatch(routeActions.setSetupEditRoutePeerVisible(false));
dispatch(routeActions.setSavedRoute({ ...savedRoute, success: false }));
dispatch(routeActions.resetSavedRoute(null));
} else if (savedRoute.error) {
let errorMsg = "Failed to update network route";
switch (savedRoute.error.statusCode) {
case 403:
errorMsg =
"Failed to update network route. You might not have enough permissions.";
break;
default:
errorMsg = savedRoute.error.data.message
? savedRoute.error.data.message
: errorMsg;
break;
}
}, [savedRoute]);
message.error({
content: errorMsg,
key: saveKey,
duration: 5,
style: styleNotification,
});
dispatch(routeActions.setSavedRoute({ ...savedRoute, error: null }));
dispatch(routeActions.resetSavedRoute(null));
}
}, [savedRoute]);
return (
<>
<Container style={{ paddingTop: "40px", paddingBottom: "50px" }}>
@@ -292,7 +291,7 @@ const RoutePeerUpdate = () => {
requiredMark={false}
onValuesChange={onChange}
style={{ width: "100%", maxWidth: "600px" }}
className="route-form"
className="route-form edit-form-wrapper"
>
<Row gutter={16}>
<Col span={24}>
@@ -478,9 +477,12 @@ const RoutePeerUpdate = () => {
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>
+13 -10
View File
@@ -76,7 +76,7 @@ const RouteAddNew = () => {
if (!route) return;
const fRoute = {
...route,
groups: getGroupNamesFromIDs(route.groups),
groups: route.groups,
} as FormRoute;
setFormRoute(fRoute);
setPreviousRouteKey(fRoute.network_id + fRoute.network);
@@ -259,7 +259,6 @@ const RouteAddNew = () => {
style: styleNotification,
});
} else if (savedRoute.success) {
console.log("savedRoute", savedRoute);
message.success({
content: "Route has been successfully added.",
key: saveKey,
@@ -311,7 +310,7 @@ const RouteAddNew = () => {
disabled={savedRoute.loading}
onClick={handleFormSubmit}
>
Add Route
Add route
</Button>
</Space>
}
@@ -335,9 +334,7 @@ const RouteAddNew = () => {
textAlign: "start",
whiteSpace: "pre-line",
fontSize: "18px",
margin: "0px",
fontWeight: 500,
marginBottom: "0",
}}
>
Add new routing peer
@@ -345,9 +342,12 @@ const RouteAddNew = () => {
<Paragraph
type={"secondary"}
style={{
marginTop: "-2",
fontWeight: "400",
marginBottom: "25px",
textAlign: "start",
whiteSpace: "pre-line",
marginTop: "-23px",
fontSize: "14px",
paddingBottom: "25px",
marginBottom: "4px",
}}
>
When you add multiple routing peers, NetBird enables high
@@ -475,9 +475,12 @@ const RouteAddNew = () => {
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>
+148 -142
View File
@@ -7,11 +7,9 @@ import {
Divider,
Form,
Input,
InputNumber,
Row,
Select,
Breadcrumb,
Switch,
Tag,
Typography,
Card,
@@ -22,29 +20,33 @@ import {
SetupKey,
SetupKeyToSave,
} from "../store/setup-key/types";
import { formatDate, timeAgo } from "../utils/common";
import { formatDate } from "../utils/common";
import { RuleObject } from "antd/lib/form";
import { CustomTagProps } from "rc-select/lib/BaseSelect";
import { Group } from "../store/group/types";
import { useGetTokenSilently } from "../utils/token";
import { expiresInToSeconds, ExpiresInValue } from "../views/ExpiresInInput";
import moment from "moment";
import { Container } from "./Container";
import Paragraph from "antd/es/typography/Paragraph";
import { EditOutlined, LockOutlined } from "@ant-design/icons";
import { LockOutlined } from "@ant-design/icons";
import { actions as personalAccessTokenActions } from "../store/personal-access-token";
import { useGetGroupTagHelpers } from "../utils/groups";
const { Option } = Select;
const { Text } = Typography;
const ExpiresInDefault: ExpiresInValue = { number: 30, interval: "day" };
const customExpiresFormat = (value: Date): string | null => {
return formatDate(value);
};
const SetupKeyNew = () => {
const { optionRender, blueTagRender } = useGetGroupTagHelpers();
const SetupKeyNew = (props: any) => {
const { isGroupUpdateView, setShowGroupModal } = props;
const {
optionRender,
blueTagRender,
tagGroups,
getExistingAndToCreateGroupsLists,
setGroupTagFilterAll,
} = useGetGroupTagHelpers();
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
@@ -52,14 +54,18 @@ const SetupKeyNew = () => {
const savedSetupKey = useSelector(
(state: RootState) => state.setupKey.savedSetupKey
);
const groups = useSelector((state: RootState) => state.group.data);
const [form] = Form.useForm();
const [editName, setEditName] = useState(false);
const [tagGroups, setTagGroups] = useState([] as string[]);
const [formSetupKey, setFormSetupKey] = useState({} as FormSetupKey);
const inputNameRef = useRef<any>(null);
useEffect(() => {
setGroupTagFilterAll(true);
}, []);
useEffect(() => {
//Unmounting component clean
return () => {
@@ -73,12 +79,6 @@ const SetupKeyNew = () => {
inputNameRef.current!.focus({ cursor: "end" });
}, [editName]);
useEffect(() => {
setTagGroups(
groups?.filter((g) => g.name !== "All").map((g) => g.name) || []
);
}, [groups]);
useEffect(() => {
if (!setupKey) return;
@@ -94,33 +94,25 @@ const SetupKeyNew = () => {
const fSetupKey = {
...setupKey,
autoGroupNames: setupKey.auto_groups ? formKeyGroups : [],
expiresInFormatted: ExpiresInDefault,
autoGroupNames: setupKey.auto_groups || [],
exp: moment(setupKey.expires),
last: moment(setupKey.last_used),
} as FormSetupKey;
form.setFieldsValue(fSetupKey);
setFormSetupKey(fSetupKey);
}, [setupKey]);
const createSetupKeyToSave = (): SetupKeyToSave => {
const autoGroups =
groups
?.filter((g) => formSetupKey.autoGroupNames.includes(g.name))
.map((g) => g.id || "") || [];
// find groups that do not yet exist (newly added by the user)
const allGroupsNames: string[] = groups?.map((g) => g.name);
const groupsToCreate = formSetupKey.autoGroupNames.filter(
(s) => !allGroupsNames.includes(s)
let [existingGroups, groupsToCreate] = getExistingAndToCreateGroupsLists(
formSetupKey.autoGroupNames
);
const expiresIn = expiresInToSeconds(formSetupKey.expiresInFormatted);
const expiresIn = formSetupKey.expires_in * 24 * 3600; // the api expects seconds while the form returns days
return {
id: formSetupKey.id,
name: formSetupKey.name,
type: formSetupKey.type,
auto_groups: autoGroups,
auto_groups: existingGroups,
revoked: formSetupKey.revoked,
groupsToCreate: groupsToCreate,
expires_in: expiresIn,
@@ -169,6 +161,9 @@ const SetupKeyNew = () => {
);
setFormSetupKey({} as FormSetupKey);
setVisibleNewSetupKey(false);
if (setShowGroupModal) {
setShowGroupModal(false);
}
};
const onChange = (data: any) => {
@@ -265,116 +260,134 @@ const SetupKeyNew = () => {
return (
<>
<Breadcrumb
style={{ marginBottom: "25px" }}
items={[
{
title: <a onClick={onBreadcrumbUsersClick}>Setup Keys</a>,
},
{
title: setupKey.name,
},
]}
/>
<Card bordered={true} style={{ marginBottom: "7px", border: "none" }}>
{!isGroupUpdateView && (
<Breadcrumb
style={{ marginBottom: "25px" }}
items={[
{
title: <a onClick={onBreadcrumbUsersClick}>Setup Keys</a>,
},
{
title: setupKey.name,
},
]}
/>
)}
<Card
bordered={true}
className={isGroupUpdateView ? " noborderPadding" : ""}
style={{ marginBottom: "7px", border: "none" }}
>
<div style={{ maxWidth: "800px" }}>
<h3 style={{ fontSize: "22px", fontWeight: "500",marginBottom:"30px" }}>
{setupKey.name}
</h3>
{!isGroupUpdateView && (
<h3
style={{
fontSize: "22px",
fontWeight: "500",
marginBottom: "30px",
}}
>
{setupKey.name}
</h3>
)}
<Form
layout="vertical"
requiredMark={false}
form={form}
onValuesChange={onChange}
initialValues={{
expiresIn: ExpiresInDefault,
usage_limit: 1,
}}
>
<Row style={{ marginTop: "10px" }}>
<Col
xs={24}
sm={24}
md={11}
lg={11}
xl={11}
xxl={11}
span={11}
style={{ paddingRight: "70px" }}
>
<Paragraph
{!isGroupUpdateView && (
<Row style={{ marginTop: "10px" }}>
<Col
xs={24}
sm={24}
md={11}
lg={11}
xl={11}
xxl={11}
span={11}
style={{
whiteSpace: "pre-line",
fontWeight: "500",
margin: 0,
paddingRight: "70px",
}}
>
Key
<Tag
color={`${
formSetupKey.state === "valid" ? "green" : "red"
}`}
<Paragraph
style={{
marginLeft: "10px",
borderRadius: "2px",
whiteSpace: "pre-line",
fontWeight: "500",
margin: 0,
}}
>
{formSetupKey.state}
</Tag>
</Paragraph>
<Input
style={{ marginTop: "8px" }}
disabled
value={getFormKey(formSetupKey.key)}
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
/>
</Col>
Key
<Tag
color={`${
formSetupKey.state === "valid" ? "green" : "red"
}`}
style={{
marginLeft: "10px",
borderRadius: "2px",
fontWeight: "500",
}}
>
{formSetupKey.state}
</Tag>
</Paragraph>
<Input
style={{ marginTop: "8px" }}
disabled
value={getFormKey(formSetupKey.key)}
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
/>
</Col>
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
<Paragraph
style={{
whiteSpace: "pre-line",
margin: 0,
fontWeight: "500",
}}
>
<Col xs={24} sm={24} md={5} lg={5} xl={5} xxl={5} span={5}>
<Paragraph
style={{
whiteSpace: "pre-line",
margin: 0,
fontWeight: "500",
}}
></Paragraph>
{formSetupKey.type === "one-off" ? "One-off" : "Reusable"},
available uses
</Paragraph>
<Col>
<Input
disabled
value={
formSetupKey.type === "reusable" &&
formSetupKey.usage_limit === 0
? "unlimited"
: formSetupKey.usage_limit - formSetupKey.used_times
}
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
style={{ marginTop: "8px" }}
/>
>
<Paragraph
style={{
whiteSpace: "pre-line",
margin: 0,
fontWeight: "500",
}}
></Paragraph>
{formSetupKey.type === "one-off" ? "One-off" : "Reusable"},
available uses
</Paragraph>
<Col>
<Input
disabled
value={
formSetupKey.type === "reusable" &&
formSetupKey.usage_limit === 0
? "unlimited"
: formSetupKey.usage_limit - formSetupKey.used_times
}
suffix={<LockOutlined style={{ color: "#BFBFBF" }} />}
style={{ marginTop: "8px" }}
/>
</Col>
</Col>
</Col>
</Row>
<Row style={{ marginTop: "30px" }}>
</Row>
)}
<Row style={{ marginTop: `${isGroupUpdateView ? "0" : "39px"}` }}>
<Col
xs={24}
sm={24}
md={11}
lg={11}
xl={11}
xxl={11}
span={11}
style={{ paddingRight: "70px" }}
md={!isGroupUpdateView ? 11 : 24}
lg={!isGroupUpdateView ? 11 : 24}
xl={!isGroupUpdateView ? 11 : 24}
xxl={!isGroupUpdateView ? 11 : 24}
span={!isGroupUpdateView ? 11 : 24}
style={{
paddingRight: `${!isGroupUpdateView ? "70px" : "0"}`,
}}
>
<Paragraph
style={{
@@ -400,42 +413,34 @@ const SetupKeyNew = () => {
dropdownRender={dropDownRender}
// enabled only when we have a new key !setupkey.id or when the key is valid
disabled={!(!setupKey.id || setupKey.valid)}
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>
</Col>
<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: "40px", marginBottom: "28px" }}>
<Text type={"secondary"}>
Learn more about
<a
target="_blank"
rel="noreferrer"
href="https://docs.netbird.io/how-to/register-machines-using-setup-keys"
>
{" "}
Setup Keys
</a>
</Text>
{!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>
@@ -443,9 +448,10 @@ const SetupKeyNew = () => {
style={{
display: "flex",
flexDirection: "row",
justifyContent: "start",
justifyContent: `${!isGroupUpdateView ? "start" : "end"}`,
padding: 0,
gap: "10px",
marginTop: "24px",
}}
key={0}
>
+55 -76
View File
@@ -11,9 +11,7 @@ import {
Modal,
Row,
Select,
Space,
Switch,
Tag,
Typography,
} from "antd";
import { RootState } from "typesafe-actions";
@@ -23,23 +21,24 @@ import {
SetupKeyToSave,
} from "../store/setup-key/types";
import { RuleObject } from "antd/lib/form";
import { CustomTagProps } from "rc-select/lib/BaseSelect";
import { Group } from "../store/group/types";
import { useGetTokenSilently } from "../utils/token";
import { expiresInToSeconds, ExpiresInValue } from "../views/ExpiresInInput";
import moment from "moment";
import { Container } from "./Container";
import Paragraph from "antd/es/typography/Paragraph";
import { CheckOutlined, CopyOutlined } from "@ant-design/icons";
import { copyToClipboard } from "../utils/common";
import {useGetGroupTagHelpers} from "../utils/groups";
import { useGetGroupTagHelpers } from "../utils/groups";
const { Option } = Select;
const { Text } = Typography;
const ExpiresInDefault: ExpiresInValue = { number: 30, interval: "day" };
const SetupKeyNew = () => {
const { optionRender, blueTagRender } = useGetGroupTagHelpers();
const {
optionRender,
blueTagRender,
tagGroups,
getExistingAndToCreateGroupsLists,
setGroupTagFilterAll,
} = useGetGroupTagHelpers();
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
const setupNewKeyVisible = useSelector(
@@ -56,7 +55,6 @@ const SetupKeyNew = () => {
const [showPlainToken, setShowPlainToken] = useState(false);
const [plainToken, setPlainToken] = useState("");
const [tokenCopied, setTokenCopied] = useState(false);
const [tagGroups, setTagGroups] = useState([] as string[]);
const [formSetupKey, setFormSetupKey] = useState({} as FormSetupKey);
const inputNameRef = useRef<any>(null);
@@ -67,53 +65,21 @@ const SetupKeyNew = () => {
}, [editName]);
useEffect(() => {
setTagGroups(
groups?.filter((g) => g.name !== "All").map((g) => g.name) || []
);
}, [groups]);
useEffect(() => {
if (!setupKey) return;
const allGroups = new Map<string, Group>();
let formKeyGroups: string[] = [];
groups.forEach((g) => allGroups.set(g.id!, g));
if (setupKey.auto_groups) {
formKeyGroups = setupKey.auto_groups
.filter((g) => allGroups.get(g))
.map((g) => allGroups.get(g)!.name);
}
const fSetupKey = {
...setupKey,
autoGroupNames: setupKey.auto_groups ? formKeyGroups : [],
expiresInFormatted: ExpiresInDefault,
exp: moment(setupKey.expires),
last: moment(setupKey.last_used),
} as FormSetupKey;
form.setFieldsValue(fSetupKey);
setFormSetupKey(fSetupKey);
}, [setupKey]);
setGroupTagFilterAll(true);
}, []);
const createSetupKeyToSave = (): SetupKeyToSave => {
const autoGroups =
groups
?.filter((g) => formSetupKey.autoGroupNames.includes(g.name))
.map((g) => g.id || "") || [];
// find groups that do not yet exist (newly added by the user)
const allGroupsNames: string[] = groups?.map((g) => g.name);
const groupsToCreate = formSetupKey.autoGroupNames.filter(
(s) => !allGroupsNames.includes(s)
let [existingGroups, groupsToCreate] = getExistingAndToCreateGroupsLists(
formSetupKey.autoGroupNames || []
);
const expiresIn = expiresInToSeconds(formSetupKey.expiresInFormatted);
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,
type: formSetupKey.type,
auto_groups: autoGroups,
type: formSetupKey.type ? formSetupKey.type : "one-off",
auto_groups: existingGroups,
revoked: formSetupKey.revoked,
groupsToCreate: groupsToCreate,
expires_in: expiresIn,
@@ -183,12 +149,12 @@ const SetupKeyNew = () => {
type: "one-off",
key: "",
last_used: "",
expires: "",
expires: "7",
state: "valid",
auto_groups: [] as string[],
usage_limit: 0,
used_times: 0,
expires_in: 0,
expires_in: 7,
} as SetupKey)
);
setFormSetupKey({} as FormSetupKey);
@@ -254,25 +220,25 @@ const SetupKeyNew = () => {
);
const changesDetected = (): boolean => {
return (
return (
formSetupKey.name == null ||
formSetupKey.name !== setupKey.name ||
groupsChanged() ||
formSetupKey.usage_limit !== setupKey.usage_limit
formSetupKey?.usage_limit !== setupKey.usage_limit
);
};
const groupsChanged = (): boolean => {
if (
if (
setupKey &&
setupKey.auto_groups &&
formSetupKey.autoGroupNames.length !== setupKey.auto_groups.length
setupKey?.auto_groups &&
formSetupKey?.autoGroupNames &&
formSetupKey?.autoGroupNames.length !== setupKey?.auto_groups.length
) {
return true;
}
const formGroupIds =
groups
?.filter((g) => formSetupKey.autoGroupNames.includes(g.name))
?.filter((g) => formSetupKey?.autoGroupNames.includes(g.name))
.map((g) => g.id || "") || [];
return (
@@ -317,7 +283,7 @@ const SetupKeyNew = () => {
fontSize: "14px",
borderRadius: "2px",
}}
disabled={savedSetupKey.loading || !changesDetected()}
disabled={savedSetupKey.loading || !!!formSetupKey.name}
onClick={handleFormSubmit}
>
Create key
@@ -348,8 +314,7 @@ const SetupKeyNew = () => {
textAlign: "start",
whiteSpace: "pre-line",
fontSize: "18px",
margin: "0px",
fontWeight:"500"
fontWeight: "500",
}}
>
{showPlainToken
@@ -361,6 +326,10 @@ const SetupKeyNew = () => {
style={{
textAlign: "start",
whiteSpace: "pre-line",
marginTop: "-20px",
fontSize: "14px",
paddingBottom: "25px",
marginBottom: "4px",
}}
>
{showPlainToken
@@ -374,8 +343,8 @@ const SetupKeyNew = () => {
form={form}
onValuesChange={onChange}
initialValues={{
expiresIn: ExpiresInDefault,
usage_limit: 1,
expires_in: 7,
}}
>
<Row>
@@ -402,7 +371,7 @@ const SetupKeyNew = () => {
</Col>
</Row>
<Row style={{ marginTop: "20px" }} justify={"space-between"}>
<Row style={{ marginTop: "24px" }} justify={"space-between"}>
<Col span={18}>
<Paragraph
style={{
@@ -424,6 +393,7 @@ const SetupKeyNew = () => {
<Row justify={"end"}>
<Form.Item name="reusable" valuePropName="checked">
<Switch
size="small"
onChange={(checked) => {
setFormSetupKey({
...formSetupKey,
@@ -436,7 +406,7 @@ const SetupKeyNew = () => {
</Col>
</Row>
<Row style={{ marginTop: "10px" }}>
<Row style={{ marginTop: "16px" }}>
<Col span={24}>
<Paragraph
style={{
@@ -474,7 +444,7 @@ const SetupKeyNew = () => {
</Col>
</Row>
<Row style={{ marginTop: "20px" }}>
<Row style={{ marginTop: "24px" }}>
<Col span={24}>
<Paragraph
style={{
@@ -488,16 +458,23 @@ const SetupKeyNew = () => {
</Col>
<Col>
<Form.Item
name="expiresIn"
name="expires_in"
rules={[
{
type: "number",
min: 1,
max: 365,
message:
"The expiration should be set between 1 and 365 days",
},
{ required: true, message: "Please enter expiration date" },
]}
>
<InputNumber
defaultValue={7}
placeholder={`2`}
type="number"
addonAfter=" Days"
value={setupKey.expires_in}
style={{ width: "160px", marginTop: "5px" }}
/>
</Form.Item>
@@ -505,12 +482,12 @@ const SetupKeyNew = () => {
type={"secondary"}
style={{ marginTop: "-18px", marginBottom: 0 }}
>
Should be between 1 and 180 days
Should be between 1 and 365 days
</Paragraph>
</Col>
</Row>
<Row style={{ marginTop: "20px" }}>
<Row style={{ marginTop: "24px" }}>
<Col span={24}>
<Paragraph
style={{
@@ -530,25 +507,27 @@ const SetupKeyNew = () => {
<Form.Item
style={{ marginTop: "5px", marginBottom: 0 }}
name="autoGroupNames"
rules={[{ validator: selectValidator }]}
>
<Select
mode="tags"
style={{ width: "100%"}}
style={{ width: "100%" }}
placeholder="Associate groups with the key"
tagRender={blueTagRender}
dropdownRender={dropDownRender}
// enabled only when we have a new key !setupkey.id or when the key is valid
disabled={!(!setupKey.id || setupKey.valid)}
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>
<Row style={{ marginTop: "40px", marginBottom: "28px" }}>
<Row style={{ marginTop: "24px", marginBottom: "24px" }}>
<Text type={"secondary"}>
Learn more about
<a
+21
View File
@@ -0,0 +1,21 @@
import React, { useEffect, useState } from "react";
import { Modal } from "antd";
import SetupKeyNew from "./SetupKeyEdit";
export const UpdateKeyGroupModal = (props:any) => {
return (
<>
<Modal
closable={false}
open={true}
footer={[]}
onCancel={() => props.setShowGroupModal(false)}
width={450}
>
<SetupKeyNew
isGroupUpdateView={true}
setShowGroupModal={props.setShowGroupModal}
/>
</Modal>
</>
);
};
@@ -0,0 +1,21 @@
import React, { useEffect, useState } from "react";
import { Modal } from "antd";
import NameServerGroupUpdate from "./NameServerGroupUpdate";
export const UpdateNameServerGroupModal = (props:any) => {
return (
<>
<Modal
closable={false}
open={true}
footer={[]}
onCancel={() => props.setShowGroupModal(false)}
width={450}
>
<NameServerGroupUpdate
isGroupUpdateView={true}
setShowGroupModal={props.setShowGroupModal}
/>
</Modal>
</>
);
};
+21
View File
@@ -0,0 +1,21 @@
import React, { useEffect, useState } from "react";
import { Modal } from "antd";
import PeerUpdate from "./PeerUpdate";
export const UpdatePeerGroupModal = (props:any) => {
return (
<>
<Modal
closable={false}
open={true}
footer={[]}
onCancel={() => props.setShowGroupModal(false)}
width={450}
>
<PeerUpdate
isGroupUpdateView={true}
setShowGroupModal={props.setShowGroupModal}
/>
</Modal>
</>
);
};
+24
View File
@@ -0,0 +1,24 @@
import React, { useEffect, useState } from "react";
import { Modal } from "antd";
import UserEdit from "./UserEdit";
export const UpdateUsersGroupModal = (props: any) => {
return (
<>
<Modal
closable={false}
open={true}
footer={[]}
onCancel={() => props.setShowGroupModal(false)}
width={450}
>
{props.showGroupModal && (
<UserEdit
isGroupUpdateView={true}
setShowGroupModal={props.setShowGroupModal}
/>
)}
</Modal>
</>
);
};
File diff suppressed because it is too large. Load diff
Loaded 20 of 50 files, more files were not shown because too many files have changed in this diff. Show more