Compare commits

..
Author SHA1 Message Date
Sarooj Bukhari ee21c424a2 fix table jerks 2023-07-10 16:58:19 +05:00
Sarooj Bukhari 40cf40829c fix table jerks 2023-07-10 16:54:45 +05:00
Sarooj Bukhari 30cd602e41 update 2023-07-10 16:49:13 +05:00
Sarooj Bukhari a11511ecbf fix comments 2023-07-10 08:27:48 +05:00
Sarooj Bukhari 2ac5504bee fix comments 2023-07-10 08:26:18 +05:00
braginini f6476ecf05 All nameservers by default in the table 2023-07-09 11:31:48 +02:00
Sarooj Bukhari c8108ef01f fix delete issue 2023-07-07 20:11:06 +05:00
Sarooj Bukhari ad4e54129a fix delete issue 2023-07-07 20:07:00 +05:00
Sarooj Bukhari 57318de4c6 fix issue of CLA 2023-07-07 19:17:58 +05:00
Sarooj Bukhari 70c2f973ef fix issue of CLA 2023-07-07 19:15:25 +05:00
Sarooj Bukhari 3bbe1079af work on DNS layout 2023-07-07 19:14:54 +05:00
Sarooj Bukhari 923c00b70c work on DNS layout 2023-07-07 18:31:31 +05:00
29 changed files with 2202 additions and 2743 deletions

No files matched your search

+84 -84
View File
@@ -204,9 +204,9 @@
}
},
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -237,9 +237,9 @@
}
},
"node_modules/@babel/eslint-parser/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -311,9 +311,9 @@
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -370,9 +370,9 @@
}
},
"node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -1706,9 +1706,9 @@
}
},
"node_modules/@babel/plugin-transform-runtime/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -1918,9 +1918,9 @@
}
},
"node_modules/@babel/preset-env/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -5219,9 +5219,9 @@
}
},
"node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -7467,9 +7467,9 @@
}
},
"node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -7540,9 +7540,9 @@
}
},
"node_modules/eslint-plugin-react/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -9512,9 +9512,9 @@
}
},
"node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -10800,9 +10800,9 @@
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"bin": {
"semver": "bin/semver.js"
}
@@ -14712,9 +14712,9 @@
}
},
"node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
"dependencies": {
"lru-cache": "^6.0.0"
},
@@ -15831,9 +15831,9 @@
}
},
"node_modules/tough-cookie": {
"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==",
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
"dependencies": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
@@ -16710,9 +16710,9 @@
}
},
"node_modules/word-wrap": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"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==",
"engines": {
"node": ">=0.10.0"
}
@@ -17249,9 +17249,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -17271,9 +17271,9 @@
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="
},
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -17328,9 +17328,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -17371,9 +17371,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -18237,9 +18237,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -18394,9 +18394,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -20854,9 +20854,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -22543,9 +22543,9 @@
}
},
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -22589,9 +22589,9 @@
}
},
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -23955,9 +23955,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -24942,9 +24942,9 @@
},
"dependencies": {
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
@@ -27566,9 +27566,9 @@
}
},
"semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
"requires": {
"lru-cache": "^6.0.0"
}
@@ -28430,9 +28430,9 @@
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
},
"tough-cookie": {
"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==",
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
"requires": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
@@ -29069,9 +29069,9 @@
}
},
"word-wrap": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA=="
"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=="
},
"workbox-background-sync": {
"version": "6.5.4",
+29 -57
View File
@@ -50,7 +50,7 @@ interface FormPolicy {
}
const AccessControlEdit = () => {
const { optionRender, blueTagRender, tagGroups, grayTagRender } =
const { optionRender, blueTagRender, grayTagRender } =
useGetGroupTagHelpers();
const { getTokenSilently } = useGetTokenSilently();
@@ -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.id || "")
? policy.rules[0].sources?.map((t) => t.name)
: [],
tagDestinationGroups: policy.rules[0].destinations
? policy.rules[0].destinations?.map((t) => t.id || "")
? policy.rules[0].destinations?.map((t) => t.name)
: [],
} as FormPolicy;
setFormPolicy(fPolicy);
@@ -139,21 +139,17 @@ const AccessControlEdit = () => {
const createPolicyToSave = (): PolicyToSave => {
const sources =
groups
?.filter((g) => formPolicy.tagSourceGroups.includes(g.id || ""))
?.filter((g) => formPolicy.tagSourceGroups.includes(g.name))
.map((g) => g.id || "") || [];
const destinations =
groups
?.filter((g) => formPolicy.tagDestinationGroups.includes(g.id || ""))
?.filter((g) => formPolicy.tagDestinationGroups.includes(g.name))
.map((g) => g.id || "") || [];
const existingGroupsNames: any[] = groups?.map((g) => g.id);
const sourcesNoId = formPolicy.tagSourceGroups.filter(
(s) => !existingGroupsNames.includes(s)
(s) => !tagGroups.includes(s)
);
const destinationsNoId = formPolicy.tagDestinationGroups.filter(
(s) => !existingGroupsNames.includes(s)
(s) => !tagGroups.includes(s)
);
const groupsToSave = uniq([...sourcesNoId, ...destinationsNoId]);
return {
@@ -461,7 +457,11 @@ const AccessControlEdit = () => {
},
]}
/>
<Card bordered={true} style={{ marginBottom: "7px" }}>
<Card
bordered={true}
// title={setupKey.name}
style={{ marginBottom: "7px" }}
>
<div style={{ maxWidth: "550px" }}>
<Form
layout="vertical"
@@ -508,6 +508,7 @@ const AccessControlEdit = () => {
<Form.Item
name="name"
label=""
style={{ margin: "0" }}
rules={[
{
required: true,
@@ -531,7 +532,7 @@ const AccessControlEdit = () => {
{!editDescription ? (
<div
style={{
margin: "0 0 39px",
margin: "12px 0 30px",
lineHeight: "22px",
cursor: "pointer",
}}
@@ -550,7 +551,7 @@ const AccessControlEdit = () => {
<Form.Item
name="description"
label="Description"
style={{ marginTop: 10, fontWeight: "500" }}
style={{ marginTop: 24, fontWeight: "500" }}
>
<Input
placeholder="Add description..."
@@ -567,7 +568,7 @@ const AccessControlEdit = () => {
</Row>
</Header>
</Col>
<Col span={24} style={{ marginBottom: "15px" }}>
<Col span={24}>
<Form.Item name="enabled" label="">
<div
style={{
@@ -578,7 +579,6 @@ const AccessControlEdit = () => {
<Switch
onChange={handleChangeDisabled}
defaultChecked={policy.enabled}
size="small"
/>
<div>
<label
@@ -622,16 +622,9 @@ const AccessControlEdit = () => {
tagRender={blueTagRender}
onChange={handleChangeSource}
dropdownRender={dropDownRenderGroups}
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option
key={index}
value={m.id}
serchValue={m.name}
>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
@@ -782,23 +775,16 @@ const AccessControlEdit = () => {
tagRender={blueTagRender}
onChange={handleChangeDestination}
dropdownRender={dropDownRenderGroups}
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option
key={index}
value={m.id}
serchValue={m.name}
>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
</Col>
</Row>
</Col>
<Col span={24} style={{ marginBottom: "15px" }}>
<Col span={24}>
<Paragraph
type={"secondary"}
style={{ marginTop: "-15px", marginBottom: "30px" }}
@@ -807,7 +793,7 @@ const AccessControlEdit = () => {
protocol below
</Paragraph>
</Col>
<Col span={24} style={{ marginBottom: "15px" }}>
<Col span={24}>
<Row>
<Col span={10}>
<Form.Item
@@ -844,14 +830,7 @@ 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}
@@ -883,14 +862,7 @@ 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"
@@ -918,7 +890,7 @@ const AccessControlEdit = () => {
justifyContent: "start",
padding: 0,
gap: "10px",
marginTop: "12px",
marginTop: "30px",
}}
key={0}
>
+22 -51
View File
@@ -50,12 +50,8 @@ interface FormPolicy {
}
const AccessControlNew = () => {
const {
optionRender,
blueTagRender,
tagGroups,
grayTagRender,
} = useGetGroupTagHelpers();
const { optionRender, grayTagRender, blueTagRender } =
useGetGroupTagHelpers();
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
const setupNewPolicyVisible = useSelector(
@@ -85,7 +81,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);
@@ -97,9 +93,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 = {
@@ -126,26 +122,19 @@ const AccessControlNew = () => {
const createPolicyToSave = (): PolicyToSave => {
const sources =
groups
?.filter((g) => formPolicy.tagSourceGroups.includes(g.id || ""))
?.filter((g) => formPolicy.tagSourceGroups.includes(g.name))
.map((g) => g.id || "") || [];
const destinations =
groups
?.filter((g) => formPolicy.tagDestinationGroups.includes(g.id || ""))
?.filter((g) => formPolicy.tagDestinationGroups.includes(g.name))
.map((g) => g.id || "") || [];
const existingGroupsNames: any[] = groups?.map((g) => g.id);
const sourcesNoId = formPolicy.tagSourceGroups.filter(
(s) => !existingGroupsNames.includes(s)
(s) => !tagGroups.includes(s)
);
const destinationsNoId = formPolicy.tagDestinationGroups.filter(
(s) => !existingGroupsNames.includes(s)
(s) => !tagGroups.includes(s)
);
const groupsToSave = uniq([...sourcesNoId, ...destinationsNoId]);
return {
id: formPolicy.id,
name: formPolicy.name,
@@ -467,20 +456,18 @@ 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",
marginTop: "-20px",
fontSize: "14px",
paddingBottom: "25px",
marginBottom: "4px",
paddingBottom: "15px",
}}
>
Use this rule to restrict access to groups of resources
@@ -573,12 +560,9 @@ const AccessControlNew = () => {
tagRender={blueTagRender}
onChange={handleChangeSource}
dropdownRender={dropDownRenderGroups}
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
@@ -729,12 +713,9 @@ const AccessControlNew = () => {
tagRender={blueTagRender}
onChange={handleChangeDestination}
dropdownRender={dropDownRenderGroups}
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
@@ -786,8 +767,6 @@ const AccessControlNew = () => {
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
padding: "0 0 2px",
display: "inline-block",
}}
>
Ports
@@ -849,16 +828,9 @@ 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}
@@ -887,7 +859,6 @@ const AccessControlNew = () => {
}}
>
<Switch
size="small"
onChange={handleChangeDisabled}
defaultChecked={true}
/>
@@ -919,7 +890,7 @@ const AccessControlNew = () => {
</Col>
<Col
span={24}
style={{ marginTop: "10px", marginBottom: "24px" }}
style={{ marginTop: "20px", marginBottom: "25px" }}
>
<Text type={"secondary"}>
Learn more about
@@ -929,7 +900,7 @@ const AccessControlNew = () => {
href="https://docs.netbird.io/how-to/manage-network-access"
>
{" "}
access controls
Access Controls
</a>
</Text>
</Col>
+123 -125
View File
@@ -331,117 +331,121 @@ const NameServerGroupAdd = () => {
{ add, remove }: any,
{ errors }: any
) => (
<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>
<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>
{!!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}>
{!!fields.length && (
<Row align="middle">
<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>
<Typography.Text
style={{ color: "#818183", paddingLeft: "5px" }}
></Typography.Text>
</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 span={10} style={{ textAlign: "left" }}>
<Typography.Text style={{ color: "#818183", paddingLeft: "5px" }}>
Nameserver IP
</Typography.Text>
</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 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>
</Col>
</Row>
</div>
<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>
</Col>
);
// @ts-ignore
@@ -466,9 +470,9 @@ const NameServerGroupAdd = () => {
<Paragraph
type={"secondary"}
style={{
marginTop: "-4px",
marginTop: "-2",
fontWeight: "400",
marginBottom: "4px",
marginBottom: "0",
}}
>
Add domain if you want to have a specific one
@@ -552,20 +556,18 @@ 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",
marginTop: "-20px",
fontSize: "14px",
paddingBottom: "25px",
marginBottom: "4px",
paddingBottom: "0",
}}
>
Use this nameserver to resolve domains in your network
@@ -704,7 +706,7 @@ const NameServerGroupAdd = () => {
</Row>
</Header>
</Col>
<Col span={24}>
<Col span={24} flex="auto">
<Form.List
name="nameservers"
rules={[{ validator: formListValidator }]}
@@ -712,7 +714,7 @@ const NameServerGroupAdd = () => {
{renderNSList}
</Form.List>
</Col>
<Col span={24}>
<Col span={24} flex="auto">
<Form.List name="domains">{renderDomains}</Form.List>
</Col>
<Col span={24}>
@@ -728,9 +730,9 @@ const NameServerGroupAdd = () => {
<Paragraph
type={"secondary"}
style={{
marginTop: "-4px",
marginTop: "-2",
fontWeight: "400",
marginBottom: "4px",
marginBottom: "0",
}}
>
Advertise this route to peers that belong to the following
@@ -747,12 +749,9 @@ const NameServerGroupAdd = () => {
tagRender={blueTagRender}
onChange={handleChangeTags}
dropdownRender={dropDownRender}
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
@@ -788,9 +787,8 @@ const NameServerGroupAdd = () => {
marginBottom: "0",
}}
>
{formNSGroup.enabled
? "Disable this server if you don't want it to apply immediately"
: " Enable this server if you want it to apply immediately"}
Disable this server if you don't want it to apply
immediately
</Paragraph>
</div>
</div>
@@ -798,7 +796,7 @@ const NameServerGroupAdd = () => {
</Col>
<Col
span={24}
style={{ marginTop: "10px", marginBottom: "24px" }}
style={{ marginTop: "10px", marginBottom: "20px" }}
>
<Text type={"secondary"}>
Learn more about
@@ -832,7 +830,7 @@ const NameServerGroupAdd = () => {
onClick={handleFormSubmit}
disabled={savedNSGroup.loading}
>
Create nameserver
Create Nameserver
</Button>
</Space>
</Col>
+168 -168
View File
@@ -43,6 +43,7 @@ const NameServerGroupUpdate = () => {
optionRender,
tagGroups,
getExistingAndToCreateGroupsLists,
getGroupNamesFromIDs,
selectValidator,
} = useGetGroupTagHelpers();
const dispatch = useDispatch();
@@ -95,7 +96,7 @@ const NameServerGroupUpdate = () => {
let newFormGroup = {
...nsGroup,
groups: nsGroup.groups,
groups: getGroupNamesFromIDs(nsGroup.groups),
} as formNSGroup;
setFormNSGroup(newFormGroup);
form.setFieldsValue(newFormGroup);
@@ -312,161 +313,117 @@ const NameServerGroupUpdate = () => {
{ add, remove }: any,
{ errors }: any
) => (
<Row>
<Col span={24} style={{ marginBottom: "15px" }}>
<Form.Item name="enabled" label="">
<div
style={{
display: "flex",
gap: "15px",
}}
>
<Switch
onChange={handleChangeDisabled}
defaultChecked={formNSGroup.enabled}
size="small"
checked={formNSGroup.enabled}
/>
<div>
<label
style={{
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
}}
>
Enabled
</label>
<Paragraph
type={"secondary"}
style={{
marginTop: "-2",
fontWeight: "400",
marginBottom: "0",
}}
>
{formNSGroup.enabled
? "Disable this server if you don't want the configuration to apply immediately"
: " Enable this server if you want the configuration to apply immediately"}
</Paragraph>
</div>
</div>
</Form.Item>
</Col>
<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>
<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>
{!!fields.length && (
<Row align="middle">
<Col span={4} style={{ textAlign: "left" }}>
<Text style={{ color: "#818183", paddingLeft: "5px" }}></Text>
</Col>
<Col span={10} style={{ textAlign: "left" }}>
<Text style={{ color: "#818183", paddingLeft: "5px" }}>
Nameserver IP
</Text>
</Col>
<Col span={4} style={{ textAlign: "left" }}>
<Text style={{ color: "#818183", paddingLeft: "5px" }}>
Port
</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" }}>
<Text style={{ color: "#818183", paddingLeft: "5px" }}></Text>
</Col>
<Col span={10} style={{ textAlign: "left" }}>
<Text style={{ color: "#818183", paddingLeft: "5px" }}>
Nameserver IP
</Text>
</Col>
<Col span={4} style={{ textAlign: "left" }}>
<Text style={{ color: "#818183", paddingLeft: "5px" }}>Port</Text>
</Col>
<Col span={4} />
</Row>
</div>
</Col>
</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>
</Col>
</Row>
</div>
</Col>
);
// @ts-ignore
@@ -491,13 +448,24 @@ const NameServerGroupUpdate = () => {
<Paragraph
type={"secondary"}
style={{
marginTop: "-2",
fontWeight: "400",
marginBottom: "10px",
marginBottom: "0",
}}
>
Add domain if you want to have a specific one
</Paragraph>
</Col>
{/* <Col>
<Tooltip
title="Only queries to domains specified here will be resolved by these nameservers."
className={"ant-form-item-tooltip"}
>
<QuestionCircleOutlined
style={{ color: "rgba(0, 0, 0, 0.45)", cursor: "help" }}
/>
</Tooltip>
</Col> */}
</Space>
</Row>
{fields.map((field, index) => {
@@ -663,7 +631,7 @@ const NameServerGroupUpdate = () => {
className={
"access-control input-text ant-drawer-subtitle"
}
style={{ margin: "0 0 39px 0px" }}
style={{ marginTop: "0" }}
onClick={() => toggleEditDescription(true)}
>
{formNSGroup.description &&
@@ -673,7 +641,7 @@ const NameServerGroupUpdate = () => {
</div>
) : (
<Row>
<Col span={8} style={{ marginBottom: "15px" }}>
<Col span={8}>
<div
style={{ lineHeight: "15px", marginTop: "24px" }}
>
@@ -708,8 +676,46 @@ const NameServerGroupUpdate = () => {
</Row>
</Header>
</Col>
<Col span={24} style={{ marginBottom: "15px" }}>
<Col span={24}>
<Form.Item name="enabled" label="">
<div
style={{
display: "flex",
gap: "15px",
}}
>
<Switch
onChange={handleChangeDisabled}
defaultChecked={formNSGroup.enabled}
size="small"
checked={formNSGroup.enabled}
/>
<div>
<label
style={{
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
}}
>
Enabled
</label>
<Paragraph
type={"secondary"}
style={{
marginTop: "-2",
fontWeight: "400",
marginBottom: "0",
}}
>
Disable this server if you don't want it to apply
immediately
</Paragraph>
</div>
</div>
</Form.Item>
</Col>
<Col span={24}>
<Form.List
name="nameservers"
rules={[{ validator: formListValidator }]}
@@ -718,17 +724,15 @@ const NameServerGroupUpdate = () => {
</Form.List>
</Col>
<Col span={24} style={{ marginBottom: "15px" }}>
<Col span={24}>
<Form.List name="domains">{renderDomains}</Form.List>
</Col>
<Col span={24} style={{ marginBottom: "15px" }}>
<Col span={24}>
<label
style={{
color: "rgba(0, 0, 0, 0.88)",
fontSize: "14px",
fontWeight: "500",
marginBottom: "5px",
display: "block",
}}
>
Distribution groups
@@ -745,17 +749,13 @@ const NameServerGroupUpdate = () => {
tagRender={blueTagRender}
onChange={handleChangeTags}
dropdownRender={dropDownRender}
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
</Col>
<Col
style={{
width: "100%",
+169 -227
View File
@@ -1,243 +1,185 @@
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 = () => {
let lRemove = [
"peerFilter",
"setupKeysFilter",
"accessControlFilter",
"routesFilter",
"nameServerFilter",
"userFilter",
"serviceUserFilter",
"activityFilter",
];
lRemove.forEach((element) => {
localStorage.removeItem(element);
});
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 = () =>
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)
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',
}
]}
/>
);
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
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>
</>
);
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 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;
+26 -47
View File
@@ -54,7 +54,7 @@ const PeerUpdate = () => {
const { getTokenSilently } = useGetTokenSilently();
const { Column } = Table;
const { confirm } = Modal;
const { optionRender, tagGroups, blueTagRender } = useGetGroupTagHelpers();
const { optionRender } = useGetGroupTagHelpers();
const dispatch = useDispatch();
const groups = useSelector((state: RootState) => state.group.data);
@@ -76,6 +76,7 @@ const PeerUpdate = () => {
const setupNewRouteVisible = useSelector(
(state: RootState) => state.route.setupNewRouteVisible
);
const [tagGroups, setTagGroups] = useState([] as string[]);
const [selectedTagGroups, setSelectedTagGroups] = useState([] as string[]);
const [peerGroups, setPeerGroups] = useState([] as GroupPeer[]);
const inputNameRef = useRef<any>(null);
@@ -159,10 +160,10 @@ const PeerUpdate = () => {
const gs = peer?.groups?.map(
(g) => ({ id: g?.id || "", name: g.name } as GroupPeer)
) as GroupPeer[];
const gs_name = gs?.map((g) => g.id) as string[];
const gs_name = gs?.map((g) => g.name) as string[];
setPeerGroups(gs);
setSelectedTagGroups(gs_name);
const fPeer = {
const fPeer = {
...peer,
name: formPeer.name ? formPeer.name : peer.name,
groupsNames: gs_name,
@@ -176,6 +177,9 @@ const PeerUpdate = () => {
form.setFieldsValue(fPeer);
}, [peer]);
useEffect(() => {
setTagGroups(groups?.map((g) => g.name) || []);
}, [groups]);
useEffect(() => {}, [users]);
@@ -198,19 +202,18 @@ const PeerUpdate = () => {
useEffect(() => {
const groupsToRemove = peerGroups
.filter((pg) => !selectedTagGroups.includes(pg.id))
.filter((pg) => !selectedTagGroups.includes(pg.name))
.map((g) => g.id);
const groupsToAdd = (groups as Group[])
.filter(
(g) =>
selectedTagGroups.includes(g.id || "") &&
selectedTagGroups.includes(g.name) &&
!groupsToRemove.includes(g.id || "") &&
!peerGroups.find((pg) => pg.id === g.id)
)
.map((g) => g.id) as string[];
const groupsNoId = selectedTagGroups.filter(
(stg) => !groups.find((g) => g.id === stg)
(stg) => !groups.find((g) => g.name === stg)
);
setPeerGroupsToSave({
...peerGroupsToSave,
@@ -227,9 +230,9 @@ const PeerUpdate = () => {
event.preventDefault();
event.stopPropagation();
};
const groupName = getGroupNameFromID(value);
let tagClosable = true;
if (groupName[0] === "All") {
if (value === "All") {
tagClosable = false;
}
@@ -241,20 +244,11 @@ const PeerUpdate = () => {
onClose={onClose}
style={{ marginRight: 3 }}
>
{groupName && groupName.length ? groupName[0] : value}
{value}
</Tag>
);
};
const getGroupNameFromID = (groupID: string) => {
if (!groupID) {
return "";
}
return (
groups?.filter((g) => groupID === g.id).map((g) => g.name || "") || []
);
};
const dropDownRender = (menu: React.ReactElement) => (
<>
{menu}
@@ -334,7 +328,7 @@ const PeerUpdate = () => {
const handleChangeTags = (value: string[]) => {
let validatedValues: string[] = [];
value.forEach(function (v: any) {
value.forEach(function (v) {
if (v.trim().length) {
validatedValues.push(v);
}
@@ -342,17 +336,6 @@ const PeerUpdate = () => {
setSelectedTagGroups(validatedValues);
};
const getGroupNamesFromIDs = (groupIDList: string[]): string[] => {
if (!groupIDList) {
return [];
}
return (
groups
?.filter((g) => groupIDList.includes(g.id!))
.map((g) => g.name || "") || []
);
};
const nameValidator = (_: RuleObject, value: string) => {
let punyName = punycode.toASCII(value.toLowerCase());
let domain = "";
@@ -495,8 +478,7 @@ const PeerUpdate = () => {
return Promise.reject(new Error("Please enter ate least one group"));
}
const val = getGroupNamesFromIDs(value);
val.forEach(function (v: string) {
value.forEach(function (v: string) {
if (!v.trim().length) {
hasSpaceNamed.push(v);
}
@@ -764,7 +746,7 @@ const PeerUpdate = () => {
</Col>
</Row>
<Row gutter={30} style={{ marginTop: "25px" }}>
<Col lg={4} md={24}>
<Col span={4}>
<Form.Item
name="ip"
label={
@@ -809,7 +791,7 @@ const PeerUpdate = () => {
/>
</Form.Item>
</Col>
<Col lg={5} md={24}>
<Col span={5}>
<Form.Item
name="dns_label"
label="Domain name"
@@ -824,7 +806,7 @@ const PeerUpdate = () => {
/>
</Form.Item>
</Col>
<Col lg={4} md={24}>
<Col span={4}>
<Form.Item
name="last_seen"
label="Last seen"
@@ -879,13 +861,13 @@ const PeerUpdate = () => {
</div>
</Form.Item>
</Col>
<Col md={24} lg={8}>
<Col span={8}>
<Paragraph
style={{
whiteSpace: "pre-line",
margin: 0,
fontWeight: "500",
}}
style={{
whiteSpace: "pre-line",
margin: 0,
fontWeight: "500",
}}
>
Groups
</Paragraph>
@@ -904,12 +886,9 @@ const PeerUpdate = () => {
tagRender={tagRender}
dropdownRender={dropDownRender}
onChange={handleChangeTags}
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
+54 -55
View File
@@ -123,7 +123,8 @@ const RouteAddNew = (selectedPeer: any) => {
} else {
setNewRoute(false);
}
}, [route]);
}, [route]);
selectedPeer &&
selectedPeer.notPeerRoutes &&
@@ -361,53 +362,54 @@ const RouteAddNew = (selectedPeer: any) => {
}
};
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;
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));
}
message.error({
content: errorMsg,
key: saveKey,
duration: 5,
style: styleNotification,
});
dispatch(routeActions.setSavedRoute({ ...savedRoute, error: null }));
dispatch(routeActions.resetSavedRoute(null));
}
}, [savedRoute]);
}, [savedRoute]);
return (
<>
{route && (
@@ -424,7 +426,7 @@ const RouteAddNew = (selectedPeer: any) => {
disabled={savedRoute.loading}
onClick={handleFormSubmit}
>
Add route
Add Route
</Button>
</Space>
}
@@ -453,7 +455,7 @@ const RouteAddNew = (selectedPeer: any) => {
marginBottom: "25px",
}}
>
Add route
Add Route
</Paragraph>
{!!selectedPeer.selectedPeer && (
@@ -732,12 +734,9 @@ const RouteAddNew = (selectedPeer: any) => {
tagRender={blueTagRender}
onChange={handleChangeTags}
dropdownRender={dropDownRender}
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
@@ -888,7 +887,7 @@ const RouteAddNew = (selectedPeer: any) => {
</Col>
<Col
span={24}
style={{ marginTop: "24px", marginBottom: "12px" }}
style={{ marginTop: "20px", marginBottom: "25px" }}
>
<Text type={"secondary"}>
Learn more about
@@ -898,7 +897,7 @@ const RouteAddNew = (selectedPeer: any) => {
href="https://docs.netbird.io/how-to/routing-traffic-to-private-networks"
>
{" "}
network routes
Network Routes
</a>
</Text>
</Col>
+49 -52
View File
@@ -73,7 +73,7 @@ const RoutePeerUpdate = () => {
if (!route) return;
const fRoute = {
...route,
groups: route.groups,
groups: getGroupNamesFromIDs(route.groups),
} as FormRoute;
setFormRoute(fRoute);
form.setFieldsValue(fRoute);
@@ -222,53 +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) {
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;
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;
}
message.error({
content: errorMsg,
key: saveKey,
duration: 5,
style: styleNotification,
});
dispatch(routeActions.setSavedRoute({ ...savedRoute, error: null }));
dispatch(routeActions.resetSavedRoute(null));
}
message.error({
content: errorMsg,
key: saveKey,
duration: 5,
style: styleNotification,
});
dispatch(routeActions.setSavedRoute({ ...savedRoute, error: null }));
dispatch(routeActions.resetSavedRoute(null));
}
}, [savedRoute]);
}, [savedRoute]);
return (
<>
<Container style={{ paddingTop: "40px", paddingBottom: "50px" }}>
@@ -291,7 +291,7 @@ const RoutePeerUpdate = () => {
requiredMark={false}
onValuesChange={onChange}
style={{ width: "100%", maxWidth: "600px" }}
className="route-form edit-form-wrapper"
className="route-form"
>
<Row gutter={16}>
<Col span={24}>
@@ -477,12 +477,9 @@ const RoutePeerUpdate = () => {
tagRender={blueTagRender}
onChange={handleChangeTags}
dropdownRender={dropDownRender}
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
+9 -13
View File
@@ -76,7 +76,7 @@ const RouteAddNew = () => {
if (!route) return;
const fRoute = {
...route,
groups: route.groups,
groups: getGroupNamesFromIDs(route.groups),
} as FormRoute;
setFormRoute(fRoute);
setPreviousRouteKey(fRoute.network_id + fRoute.network);
@@ -310,7 +310,7 @@ const RouteAddNew = () => {
disabled={savedRoute.loading}
onClick={handleFormSubmit}
>
Add route
Add Route
</Button>
</Space>
}
@@ -334,7 +334,9 @@ const RouteAddNew = () => {
textAlign: "start",
whiteSpace: "pre-line",
fontSize: "18px",
margin: "0px",
fontWeight: 500,
marginBottom: "0",
}}
>
Add new routing peer
@@ -342,12 +344,9 @@ const RouteAddNew = () => {
<Paragraph
type={"secondary"}
style={{
textAlign: "start",
whiteSpace: "pre-line",
marginTop: "-23px",
fontSize: "14px",
paddingBottom: "25px",
marginBottom: "4px",
marginTop: "-2",
fontWeight: "400",
marginBottom: "25px",
}}
>
When you add multiple routing peers, NetBird enables high
@@ -475,12 +474,9 @@ const RouteAddNew = () => {
tagRender={blueTagRender}
onChange={handleChangeTags}
dropdownRender={dropDownRender}
optionFilterProp="serchValue"
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
+44 -34
View File
@@ -7,9 +7,11 @@ import {
Divider,
Form,
Input,
InputNumber,
Row,
Select,
Breadcrumb,
Switch,
Tag,
Typography,
Card,
@@ -20,14 +22,15 @@ import {
SetupKey,
SetupKeyToSave,
} from "../store/setup-key/types";
import { formatDate } from "../utils/common";
import { formatDate, timeAgo } from "../utils/common";
import { RuleObject } from "antd/lib/form";
import { CustomTagProps } from "rc-select/lib/BaseSelect";
import { Group } from "../store/group/types";
import { useGetTokenSilently } from "../utils/token";
import moment from "moment";
import { Container } from "./Container";
import Paragraph from "antd/es/typography/Paragraph";
import { LockOutlined } from "@ant-design/icons";
import { EditOutlined, LockOutlined } from "@ant-design/icons";
import { actions as personalAccessTokenActions } from "../store/personal-access-token";
import { useGetGroupTagHelpers } from "../utils/groups";
@@ -39,13 +42,7 @@ const customExpiresFormat = (value: Date): string | null => {
};
const SetupKeyNew = () => {
const {
optionRender,
blueTagRender,
tagGroups,
getExistingAndToCreateGroupsLists,
setGroupTagFilterAll,
} = useGetGroupTagHelpers();
const { optionRender, blueTagRender } = useGetGroupTagHelpers();
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
@@ -53,18 +50,14 @@ 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 [formSetupKey, setFormSetupKey] = useState({} as FormSetupKey);
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 () => {
@@ -78,6 +71,12 @@ 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;
@@ -93,25 +92,32 @@ const SetupKeyNew = () => {
const fSetupKey = {
...setupKey,
autoGroupNames: setupKey.auto_groups || [],
autoGroupNames: setupKey.auto_groups ? formKeyGroups : [],
exp: moment(setupKey.expires),
last: moment(setupKey.last_used),
} as FormSetupKey;
form.setFieldsValue(fSetupKey);
setFormSetupKey(fSetupKey);
}, [setupKey]);
const createSetupKeyToSave = (): SetupKeyToSave => {
let [existingGroups, groupsToCreate] = getExistingAndToCreateGroupsLists(
formSetupKey.autoGroupNames
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)
);
const expiresIn = formSetupKey.expires_in * 24 * 3600; // the api expects seconds while the form returns days
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: existingGroups,
auto_groups: autoGroups,
revoked: formSetupKey.revoked,
groupsToCreate: groupsToCreate,
expires_in: expiresIn,
@@ -269,13 +275,7 @@ const SetupKeyNew = () => {
/>
<Card bordered={true} style={{ marginBottom: "7px", border: "none" }}>
<div style={{ maxWidth: "800px" }}>
<h3
style={{
fontSize: "22px",
fontWeight: "500",
marginBottom: "30px",
}}
>
<h3 style={{ fontSize: "22px", fontWeight: "500",marginBottom:"30px" }}>
{setupKey.name}
</h3>
<Form
@@ -361,7 +361,7 @@ const SetupKeyNew = () => {
</Col>
</Row>
<Row style={{ marginTop: "39px" }}>
<Row style={{ marginTop: "30px" }}>
<Col
xs={24}
sm={24}
@@ -396,12 +396,9 @@ 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, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
@@ -422,6 +419,20 @@ const SetupKeyNew = () => {
</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>
</Row>
</Form>
</div>
<Container
@@ -431,7 +442,6 @@ const SetupKeyNew = () => {
justifyContent: "start",
padding: 0,
gap: "10px",
marginTop: "24px",
}}
key={0}
>
+57 -31
View File
@@ -11,7 +11,9 @@ import {
Modal,
Row,
Select,
Space,
Switch,
Tag,
Typography,
} from "antd";
import { RootState } from "typesafe-actions";
@@ -21,24 +23,21 @@ 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 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 SetupKeyNew = () => {
const {
optionRender,
blueTagRender,
tagGroups,
getExistingAndToCreateGroupsLists,
setGroupTagFilterAll,
} = useGetGroupTagHelpers();
const { optionRender, blueTagRender } = useGetGroupTagHelpers();
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
const setupNewKeyVisible = useSelector(
@@ -55,6 +54,7 @@ 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);
@@ -65,19 +65,52 @@ const SetupKeyNew = () => {
}, [editName]);
useEffect(() => {
setGroupTagFilterAll(true);
}, []);
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 : [],
exp: moment(setupKey.expires),
last: moment(setupKey.last_used),
} as FormSetupKey;
form.setFieldsValue(fSetupKey);
setFormSetupKey(fSetupKey);
}, [setupKey]);
const createSetupKeyToSave = (): SetupKeyToSave => {
let [existingGroups, groupsToCreate] = getExistingAndToCreateGroupsLists(
formSetupKey.autoGroupNames
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)
);
const expiresIn = formSetupKey.expires_in * 24 * 3600; // the api expects seconds we have days
const expiresIn = formSetupKey.expires_in * 24 * 3600 // the api expects seconds we have days
return {
id: formSetupKey.id,
name: formSetupKey.name,
type: formSetupKey.type,
auto_groups: existingGroups,
auto_groups: autoGroups,
revoked: formSetupKey.revoked,
groupsToCreate: groupsToCreate,
expires_in: expiresIn,
@@ -312,7 +345,8 @@ const SetupKeyNew = () => {
textAlign: "start",
whiteSpace: "pre-line",
fontSize: "18px",
fontWeight: "500",
margin: "0px",
fontWeight:"500"
}}
>
{showPlainToken
@@ -324,10 +358,6 @@ const SetupKeyNew = () => {
style={{
textAlign: "start",
whiteSpace: "pre-line",
marginTop: "-20px",
fontSize: "14px",
paddingBottom: "25px",
marginBottom: "4px",
}}
>
{showPlainToken
@@ -368,7 +398,7 @@ const SetupKeyNew = () => {
</Col>
</Row>
<Row style={{ marginTop: "24px" }} justify={"space-between"}>
<Row style={{ marginTop: "20px" }} justify={"space-between"}>
<Col span={18}>
<Paragraph
style={{
@@ -390,7 +420,6 @@ const SetupKeyNew = () => {
<Row justify={"end"}>
<Form.Item name="reusable" valuePropName="checked">
<Switch
size="small"
onChange={(checked) => {
setFormSetupKey({
...formSetupKey,
@@ -403,7 +432,7 @@ const SetupKeyNew = () => {
</Col>
</Row>
<Row style={{ marginTop: "16px" }}>
<Row style={{ marginTop: "10px" }}>
<Col span={24}>
<Paragraph
style={{
@@ -441,7 +470,7 @@ const SetupKeyNew = () => {
</Col>
</Row>
<Row style={{ marginTop: "24px" }}>
<Row style={{ marginTop: "20px" }}>
<Col span={24}>
<Paragraph
style={{
@@ -476,7 +505,7 @@ const SetupKeyNew = () => {
</Col>
</Row>
<Row style={{ marginTop: "24px" }}>
<Row style={{ marginTop: "20px" }}>
<Col span={24}>
<Paragraph
style={{
@@ -500,24 +529,21 @@ const SetupKeyNew = () => {
>
<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, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
</Col>
</Row>
<Row style={{ marginTop: "24px", marginBottom: "24px" }}>
<Row style={{ marginTop: "40px", marginBottom: "28px" }}>
<Text type={"secondary"}>
Learn more about
<a
File diff suppressed because it is too large. Load diff
+3 -12
View File
@@ -177,18 +177,9 @@ const AddPATPopup = () => {
</Form.Item>
<Paragraph type={"secondary"} style={{fontSize: "14px", marginTop: "-18px"}}>Should be between 1 and 365 days</Paragraph>
</Col>
<Col span={24} style={{marginTop: "15px"}}>
<Text type={"secondary"}>
Learn more about
<a
target="_blank"
rel="noreferrer"
href="https://docs.netbird.io/how-to/access-netbird-public-api"
>
{" "}
access tokens
</a>
</Text>
<Col span={24}>
<Button icon={<QuestionCircleFilled/>} type="link" target="_blank" disabled={true} style={{marginTop: "20px", marginBottom: "20px"}}
href="https://docs.netbird.io/how-to/access-netbird-public-api">Learn more about personal access tokens</Button>
</Col>
</Row>
</Form>}
+34 -35
View File
@@ -8,10 +8,11 @@ import {
Row,
Select,
Space,
Tag,
Typography,
} from "antd";
import { Container } from "../Container";
import React, { useEffect, useRef } from "react";
import React, { useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "typesafe-actions";
import { useGetTokenSilently } from "../../utils/token";
@@ -27,8 +28,7 @@ const { Title, Text, Paragraph } = Typography;
const { Option } = Select;
const InviteUserPopup = () => {
const { optionRender, blueTagRender, tagGroups, handleChangeTags } =
useGetGroupTagHelpers();
const { optionRender, blueTagRender } = useGetGroupTagHelpers();
const { getTokenSilently } = useGetTokenSilently();
const dispatch = useDispatch();
@@ -48,16 +48,19 @@ const InviteUserPopup = () => {
const [form] = Form.useForm();
const inputNameRef = useRef<any>(null);
const [tagGroups, setTagGroups] = useState([] as string[]);
const [selectedTagGroups, setSelectedTagGroups] = useState([] as string[]);
const createUserToSave = (values: any): UserToSave => {
const autoGroups =
groups
?.filter(
(g) =>
values.autoGroupsNames && values.autoGroupsNames.includes(g.id)
values.autoGroupsNames && values.autoGroupsNames.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.id || "");
const allGroupsNames: string[] = groups?.map((g) => g.name);
const groupsToCreate =
values.autoGroupsNames?.filter(
(s: string) => !allGroupsNames.includes(s)
@@ -127,15 +130,15 @@ const InviteUserPopup = () => {
return Promise.resolve();
};
// const handleChangeTags = (value: string[]) => {
// let validatedValues: string[] = [];
// value.forEach(function (v) {
// if (v.trim().length) {
// validatedValues.push(v);
// }
// });
// setSelectedTagGroups(validatedValues);
// };
const handleChangeTags = (value: string[]) => {
let validatedValues: string[] = [];
value.forEach(function (v) {
if (v.trim().length) {
validatedValues.push(v);
}
});
setSelectedTagGroups(validatedValues);
};
const dropDownRender = (menu: React.ReactElement) => (
<>
@@ -165,11 +168,11 @@ const InviteUserPopup = () => {
</>
);
// useEffect(() => {
// setTagGroups(
// groups?.filter((g) => g.name != "All").map((g) => g.name) || []
// );
// }, [groups]);
useEffect(() => {
setTagGroups(
groups?.filter((g) => g.name != "All").map((g) => g.name) || []
);
}, [groups]);
useEffect(() => {
dispatch(
@@ -331,29 +334,25 @@ const InviteUserPopup = () => {
placeholder="Associate groups with the user"
tagRender={blueTagRender}
onChange={handleChangeTags}
optionFilterProp="serchValue"
dropdownRender={dropDownRender}
>
{tagGroups.map((m, index) => (
<Option key={index} value={m.id} serchValue={m.name}>
{optionRender(m.name)}
</Option>
{tagGroups.map((m) => (
<Option key={m}>{optionRender(m)}</Option>
))}
</Select>
</Form.Item>
</Col>
<Col span={24}>
<Text type={"secondary"}>
Learn more about
<a
target="_blank"
rel="noreferrer"
href="https://docs.netbird.io/how-to/add-users-to-your-network"
>
{" "}
user management
</a>
</Text>
<Button
icon={<QuestionCircleFilled />}
type="link"
target="_blank"
disabled={true}
style={{ marginTop: "20px", marginBottom: "20px" }}
href="https://docs.netbird.io/how-to/access-netbird-public-api"
>
Learn more about user
</Button>
</Col>
</Row>
</Form>
+1 -10
View File
@@ -433,7 +433,7 @@ ul.ant-list-items {
}
.route-form .ant-form-item {
margin-bottom: 24px;
margin-bottom: 20px;
}
.nb-code {
@@ -467,13 +467,4 @@ ul.ant-list-items {
.style-like-text .ant-select-arrow {
display: none !important;
}
.ant-spin-nested-loading .ant-spin-spinning {
min-height: 300px;
}
.route-form.edit-form-wrapper .ant-form-item{
margin-bottom: 39px;
}
-21
View File
@@ -1,21 +0,0 @@
export const storeFilterState = (page, filterName, filterValue) => {
let filterStateObj = {}
const getValue = localStorage.getItem(page)
if (getValue) {
filterStateObj = JSON.parse(getValue)
}
filterStateObj[filterName] = filterValue
localStorage.setItem(page, JSON.stringify(filterStateObj))
}
export const getFilterState = (page, filterName) => {
const getFilterObject = JSON.parse(localStorage.getItem(page))
if (getFilterObject) {
return getFilterObject[filterName]
}
return null
}
+134 -166
View File
@@ -1,182 +1,150 @@
import { CustomTagProps } from "rc-select/lib/BaseSelect";
import React, { useEffect, useState } from "react";
import { Col, Divider, Row, Tag } from "antd";
import { useSelector } from "react-redux";
import { RootState } from "typesafe-actions";
import { RuleObject } from "antd/lib/form";
import {CustomTagProps} from "rc-select/lib/BaseSelect";
import React, {useEffect, useState} from "react";
import {Col, Divider, Row, Tag} from "antd";
import {useSelector} from "react-redux";
import {RootState} from "typesafe-actions";
import {RuleObject} from "antd/lib/form";
export const useGetGroupTagHelpers = () => {
const groups = useSelector((state: RootState) => state.group.data);
const [tagGroups, setTagGroups] = useState([] as any[]);
const [groupTagFilterAll, setGroupTagFilterAll] = useState(false);
const [selectedTagGroups, setSelectedTagGroups] = useState([] as string[]);
const groups = useSelector((state: RootState) => state.group.data)
const blueTagRender = (props: CustomTagProps) => {
return tagRender(props, "blue");
};
const grayTagRender = (props: CustomTagProps) => {
return tagRender(props, "");
};
const [tagGroups, setTagGroups] = useState([] as string[])
const [groupTagFilterAll, setGroupTagFilterAll] = useState(false)
const [selectedTagGroups, setSelectedTagGroups] = useState([] as string[])
const tagRender = (props: CustomTagProps, color: string) => {
const { value, closable, onClose } = props;
const onPreventMouseDown = (event: React.MouseEvent<HTMLSpanElement>) => {
event.preventDefault();
event.stopPropagation();
const blueTagRender = (props: CustomTagProps) => {
return tagRender(props, "blue")
}
const grayTagRender = (props: CustomTagProps) => {
return tagRender(props, "")
}
const tagRender = (props: CustomTagProps, color: string) => {
const {value, closable, onClose} = props;
const onPreventMouseDown = (event: React.MouseEvent<HTMLSpanElement>) => {
event.preventDefault();
event.stopPropagation();
};
return (
<Tag
color={color}
onMouseDown={onPreventMouseDown}
closable={closable}
onClose={onClose}
style={{marginRight: 3}}
>
{value}
</Tag>
);
}
const handleChangeTags = (value: string[]) => {
let validatedValues: string[] = []
value.forEach(function (v) {
if (v.trim().length) {
validatedValues.push(v)
}
})
setSelectedTagGroups(validatedValues)
};
const groupName = getGroupNameFromID(value);
return (
<Tag
color={color}
onMouseDown={onPreventMouseDown}
closable={closable}
onClose={onClose}
style={{ marginRight: 3 }}
>
{groupName && groupName.length ? groupName[0] : value}
</Tag>
);
};
const handleChangeTags = (value: string[]) => {
const groupsName = getGroupNamesFromIDs(value);
let validatedValues: string[] = [];
groupsName.forEach(function (v) {
if (v.trim().length) {
validatedValues.push(v);
}
});
setSelectedTagGroups(validatedValues);
};
const dropDownRender = (menu: React.ReactElement) => (
<>
{menu}
<Divider style={{margin: '8px 0'}}/>
<Row style={{padding: '0 8px 4px'}}>
<Col flex="auto">
<span style={{color: "#9CA3AF"}}>Add new group by pressing "Enter"</span>
</Col>
<Col flex="none">
<svg width="14" height="12" viewBox="0 0 14 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M1.70455 7.19176V5.89915H10.3949C10.7727 5.89915 11.1174 5.80634 11.429 5.62074C11.7405 5.43513 11.9875 5.18655 12.1697 4.875C12.3554 4.56345 12.4482 4.21875 12.4482 3.84091C12.4482 3.46307 12.3554 3.12003 12.1697 2.81179C11.9841 2.50024 11.7356 2.25166 11.424 2.06605C11.1158 1.88044 10.7727 1.78764 10.3949 1.78764H9.83807V0.5H10.3949C11.0114 0.5 11.5715 0.650805 12.0753 0.952414C12.5791 1.25402 12.9818 1.65672 13.2834 2.16051C13.585 2.6643 13.7358 3.22443 13.7358 3.84091C13.7358 4.30161 13.648 4.73414 13.4723 5.13849C13.3 5.54285 13.0613 5.89915 12.7564 6.20739C12.4515 6.51562 12.0968 6.75758 11.6925 6.93324C11.2881 7.10559 10.8556 7.19176 10.3949 7.19176H1.70455ZM4.90128 11.0646L0.382102 6.54545L4.90128 2.02628L5.79119 2.91619L2.15696 6.54545L5.79119 10.1747L4.90128 11.0646Z"
fill="#9CA3AF"/>
</svg>
</Col>
</Row>
</>
)
const dropDownRender = (menu: React.ReactElement) => (
<>
{menu}
<Divider style={{ margin: "8px 0" }} />
<Row style={{ padding: "0 8px 4px" }}>
<Col flex="auto">
<span style={{ color: "#9CA3AF" }}>
Add new group by pressing "Enter"
</span>
</Col>
<Col flex="none">
<svg
width="14"
height="12"
viewBox="0 0 14 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.70455 7.19176V5.89915H10.3949C10.7727 5.89915 11.1174 5.80634 11.429 5.62074C11.7405 5.43513 11.9875 5.18655 12.1697 4.875C12.3554 4.56345 12.4482 4.21875 12.4482 3.84091C12.4482 3.46307 12.3554 3.12003 12.1697 2.81179C11.9841 2.50024 11.7356 2.25166 11.424 2.06605C11.1158 1.88044 10.7727 1.78764 10.3949 1.78764H9.83807V0.5H10.3949C11.0114 0.5 11.5715 0.650805 12.0753 0.952414C12.5791 1.25402 12.9818 1.65672 13.2834 2.16051C13.585 2.6643 13.7358 3.22443 13.7358 3.84091C13.7358 4.30161 13.648 4.73414 13.4723 5.13849C13.3 5.54285 13.0613 5.89915 12.7564 6.20739C12.4515 6.51562 12.0968 6.75758 11.6925 6.93324C11.2881 7.10559 10.8556 7.19176 10.3949 7.19176H1.70455ZM4.90128 11.0646L0.382102 6.54545L4.90128 2.02628L5.79119 2.91619L2.15696 6.54545L5.79119 10.1747L4.90128 11.0646Z"
fill="#9CA3AF"
/>
</svg>
</Col>
</Row>
</>
);
const optionRender = (label: string) => {
let peersCount = "";
const g = groups.find((_g) => _g.name === label);
if (g)
peersCount = ` - ${g.peers_count || 0} ${
!g.peers_count || parseInt(g.peers_count) !== 1 ? "peers" : "peer"
} `;
return (
<div>
<Tag color="blue" style={{ marginRight: 3}}>
{label}
</Tag>
<span style={{ fontSize: ".85em" }}>{peersCount}</span>
</div>
);
};
const optionRender = (label: string) => {
let peersCount = "";
const g = groups.find((_g) => _g.name === label);
if (g)
peersCount = ` - ${g.peers_count || 0} ${
!g.peers_count || parseInt(g.peers_count) !== 1 ? "peers" : "peer"
} `;
return (
<div>
<Tag color="blue" style={{ marginRight: 3 }}>
{label}
</Tag>
<span style={{ fontSize: ".85em" }}>{peersCount}</span>
</div>
);
};
const getExistingAndToCreateGroupsLists = (
groupIDsList: string[]
): [string[], string[]] => {
const groupIDList =
groups
?.filter((g) => groupIDsList.includes(g.id || ""))
.map((g) => g.id || "") || [];
// find groups that do not yet exist (newly added by the user)
const existingGroupsNames: any[] = groups?.map((g) => g.id);
const groupNameListToCreate = groupIDsList.filter(
(s) => !existingGroupsNames.includes(s)
);
return [groupIDList, groupNameListToCreate];
};
const getGroupNamesFromIDs = (groupIDList: string[]): string[] => {
if (!groupIDList) {
return [];
}
return (
groups
?.filter((g) => groupIDList.includes(g.id!))
.map((g) => g.name || "") || []
);
};
const getGroupNameFromID = (groupID: string) => {
if (!groupID) {
return "";
}
return (
groups?.filter((g) => groupID === g.id).map((g) => g.name || "") || []
);
};
const selectValidator = (obj: RuleObject, value: string[]) => {
if (!value.length) {
return Promise.reject(new Error("Please enter at least one group"));
const getExistingAndToCreateGroupsLists = (groupNameList: string[]): [string[], string[]] => {
const groupIDList = groups?.filter(g => groupNameList.includes(g.name)).map(g => g.id || '') || []
// find groups that do not yet exist (newly added by the user)
const existingGroupsNames: string[] = groups?.map(g => g.name);
const groupNameListToCreate = groupNameList.filter(s => !existingGroupsNames.includes(s))
return [groupIDList, groupNameListToCreate]
}
return selectValidatorEmptyStrings(obj, value);
};
const getGroupNamesFromIDs = (groupIDList: string[]): string[] => {
if (!groupIDList) {
return []
}
const selectValidatorEmptyStrings = (_: RuleObject, value: string[]) => {
let hasSpaceNamed = [];
value.forEach(function (v: string) {
if (!v.trim().length) {
hasSpaceNamed.push(v);
}
});
if (hasSpaceNamed.length) {
return Promise.reject(
new Error("Group names with just spaces are not allowed")
);
return groups?.filter(g => groupIDList.includes(g.id!)).map(g => g.name || '') || []
}
return Promise.resolve();
};
const selectValidator = (obj: RuleObject, value: string[]) => {
if (!value.length) {
return Promise.reject(new Error("Please enter at least one group"))
}
useEffect(() => {
if (groupTagFilterAll) {
setTagGroups(groups?.filter((g) => g.name !== "All").map((g) => g) || []);
} else {
setTagGroups(groups);
return selectValidatorEmptyStrings(obj,value)
}
}, [groups, groupTagFilterAll]);
return {
tagRender,
blueTagRender,
grayTagRender,
handleChangeTags,
dropDownRender,
optionRender,
tagGroups,
selectedTagGroups,
groupTagFilterAll,
setGroupTagFilterAll,
getExistingAndToCreateGroupsLists,
getGroupNamesFromIDs,
selectValidator,
selectValidatorEmptyStrings,
};
};
const selectValidatorEmptyStrings = (_: RuleObject, value: string[]) => {
let hasSpaceNamed = []
value.forEach(function (v: string) {
if (!v.trim().length) {
hasSpaceNamed.push(v)
}
})
if (hasSpaceNamed.length) {
return Promise.reject(new Error("Group names with just spaces are not allowed"))
}
return Promise.resolve()
}
useEffect(() => {
if (groupTagFilterAll) {
setTagGroups(groups?.filter(g => g.name != "All").map(g => g.name) || [])
} else {
setTagGroups(groups?.map(g => g.name) || [])
}
}, [groups])
return {
tagRender,
blueTagRender,
grayTagRender,
handleChangeTags,
dropDownRender,
optionRender,
tagGroups,
selectedTagGroups,
setGroupTagFilterAll,
getExistingAndToCreateGroupsLists,
getGroupNamesFromIDs,
selectValidator,
selectValidatorEmptyStrings
}
}
+19 -20
View File
@@ -1,25 +1,24 @@
import { useState } from "react";
import { storeFilterState } from "./filterState";
import {useState} from "react";
export const usePageSizeHelpers = () => {
const [pageSize, setPageSize] = useState(10);
const onChangePageSize = (value: string, pageName: string) => {
setPageSize(parseInt(value.toString()));
storeFilterState(pageName, "pageSize", parseInt(value.toString()));
};
const [pageSize, setPageSize] = useState(10);
const pageSizeOptions = [
{ label: "10", value: "10" },
{ label: "25", value: "25" },
{ label: "50", value: "50" },
{ label: "100", value: "100" },
{ label: "1000", value: "1000" },
];
const onChangePageSize = (value: string) => {
setPageSize(parseInt(value.toString()))
}
return {
onChangePageSize,
pageSize,
pageSizeOptions,
};
};
const pageSizeOptions = [
{label: "10", value: "10"},
{label: "25", value: "25"},
{label: "50", value: "50"},
{label: "100", value: "100"},
{label: "1000", value: "1000"}
]
return {
onChangePageSize,
pageSize,
pageSizeOptions
}
}
+26 -52
View File
@@ -23,7 +23,6 @@ import {
} from "antd";
import { Container } from "../components/Container";
import { useDispatch, useSelector } from "react-redux";
import { storeFilterState, getFilterState } from "../utils/filterState";
import { RootState } from "typesafe-actions";
import { Policy } from "../store/policy/types";
import { actions as policyActions } from "../store/policy";
@@ -123,25 +122,6 @@ export const AccessControl = () => {
};
}, []);
useEffect(() => {
if (!loading) {
const quickFilter = getFilterState("accessControlFilter", "quickFilter");
if (quickFilter) setOptionAllEnable(quickFilter);
const searchText = getFilterState("accessControlFilter", "search");
if (searchText) setTextToSearch(searchText);
const pageSize = getFilterState("accessControlFilter", "pageSize");
if (pageSize) onChangePageSize(pageSize, "accessControlFilter");
if (quickFilter || searchText || pageSize) {
setDataTable(transformDataTable(filterDataTable(searchText)));
} else {
setDataTable(sortBy(transformDataTable(filterDataTable("")), "name"));
}
}
}, [loading, policies]);
const transformDataTable = (d: Policy[]): PolicyDataTable[] => {
return d.map((policy) => {
const sourceLabel = getSourceDestinationLabel(
@@ -189,32 +169,14 @@ export const AccessControl = () => {
setShowTutorial(false);
} else {
setShowTutorial(isShowTutorial(policies));
setDataTable(sortBy(transformDataTable(filterDataTable()), "name"));
}
}, [policies]);
useEffect(() => {
setDataTable(transformDataTable(filterDataTable("")));
setDataTable(transformDataTable(filterDataTable()));
}, [textToSearch, optionAllEnable]);
const filterDataTable = (searchText: string): Policy[] => {
const t = searchText
? searchText.toLowerCase().trim()
: textToSearch.toLowerCase().trim();
let f: Policy[] = filter(
policies,
(f: Policy) =>
f.name.toLowerCase().includes(t) ||
f.description.toLowerCase().includes(t) ||
t === ""
) as Policy[];
if (optionAllEnable == "enabled") {
f = filter(f, (f: Policy) => f.enabled);
} else if (optionAllEnable == "disabled") {
f = filter(f, (f: Policy) => !f.enabled);
}
return f;
};
const styleNotification = { marginTop: 85 };
const saveKey = "saving";
@@ -281,17 +243,15 @@ export const AccessControl = () => {
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
setTextToSearch(e.target.value);
storeFilterState("accessControlFilter", "search", e.target.value);
};
// const searchDataTable = () => {
// const data = filterDataTable();
// setDataTable(transformDataTable(data));
// };
const searchDataTable = () => {
const data = filterDataTable();
setDataTable(transformDataTable(data));
};
const onChangeAllEnabled = ({ target: { value } }: RadioChangeEvent) => {
setOptionAllEnable(value);
storeFilterState("accessControlFilter", "quickFilter", value);
};
const showConfirmDelete = (record: PolicyDataTable) => {
@@ -350,6 +310,23 @@ export const AccessControl = () => {
});
};
const filterDataTable = (): Policy[] => {
const t = textToSearch.toLowerCase().trim();
let f: Policy[] = filter(
policies,
(f: Policy) =>
f.name.toLowerCase().includes(t) ||
f.description.toLowerCase().includes(t) ||
t === ""
) as Policy[];
if (optionAllEnable == "enabled") {
f = filter(f, (f: Policy) => f.enabled);
} else if (optionAllEnable == "disabled") {
f = filter(f, (f: Policy) => !f.enabled);
}
return f;
};
const onClickAddNewPolicy = () => {
dispatch(policyActions.setSetupNewPolicyVisible(true));
dispatch(
@@ -618,7 +595,7 @@ export const AccessControl = () => {
<Input
allowClear
value={textToSearch}
// onPressEnter={searchDataTable}
onPressEnter={searchDataTable}
placeholder="Search by name and description..."
onChange={onChangeTextToSearch}
/>
@@ -644,9 +621,7 @@ export const AccessControl = () => {
<Select
value={pageSize.toString()}
options={pageSizeOptions}
onChange={(value) => {
onChangePageSize(value, "accessControlFilter");
}}
onChange={onChangePageSize}
className="select-rows-per-page-en"
disabled={showTutorial}
/>
@@ -669,7 +644,7 @@ export const AccessControl = () => {
disabled={savedPolicy.loading}
onClick={onClickAddNewPolicy}
>
Add rule
Add Rule
</Button>
</Col>
</Row>
@@ -747,7 +722,6 @@ export const AccessControl = () => {
}`}
showSorterTooltip={false}
scroll={{ x: true }}
style={{ minHeight: "300px" }}
loading={tableSpin(loading)}
dataSource={dataTable}
>
Loaded 20 of 29 files, more files were not shown because too many files have changed in this diff. Show more