You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ji...@apache.org on 2024/11/18 00:53:06 UTC
(ambari) branch frontend-refactor updated: AMBARI-26167: Ambari Admin React Implementation: Add Users Page (#3879)
This is an automated email from the ASF dual-hosted git repository.
jialiang pushed a commit to branch frontend-refactor
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/frontend-refactor by this push:
new cde2331353 AMBARI-26167: Ambari Admin React Implementation: Add Users Page (#3879)
cde2331353 is described below
commit cde2331353ba8534d8e41486d3a09412a8cca9a2
Author: Himanshu Maurya <54...@users.noreply.github.com>
AuthorDate: Mon Nov 18 06:23:01 2024 +0530
AMBARI-26167: Ambari Admin React Implementation: Add Users Page (#3879)
---
.../main/resources/ui/ambari-admin/package.json | 14 +-
.../ambari-admin/src/__mocks__/mockGroupsList.ts | 408 +++++
.../ui/ambari-admin/src/__mocks__/mockRbacData.ts | 1598 ++++++++++++++++++++
.../ui/ambari-admin/src/__mocks__/mockUsersList.ts | 919 +++++++++++
.../ui/ambari-admin/src/screens/Users/AddUser.tsx | 428 ++++++
.../src/screens/Users/RoleBasedAccessControl.tsx | 244 +++
.../src/screens/Users/WarningModal.tsx | 69 +
.../ui/ambari-admin/src/screens/Users/constants.ts | 38 +
.../ui/ambari-admin/src/screens/Users/index.tsx | 9 +
.../ui/ambari-admin/src/styles/custom.scss | 14 +
.../ui/ambari-admin/src/tests/AddUser.test.tsx | 302 ++++
.../src/tests/ListUsersGroups.test.tsx | 441 ++++++
.../resources/ui/ambari-admin/vitest.config.ts | 30 +
13 files changed, 4512 insertions(+), 2 deletions(-)
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/package.json b/ambari-admin/src/main/resources/ui/ambari-admin/package.json
index 8582b819de..748f339008 100644
--- a/ambari-admin/src/main/resources/ui/ambari-admin/package.json
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/package.json
@@ -7,7 +7,9 @@
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
- "preview": "vite preview"
+ "preview": "vite preview",
+ "test": "vitest",
+ "coverage": "vitest run --coverage"
},
"dependencies": {
"@fortawesome/free-solid-svg-icons": "^6.6.0",
@@ -16,6 +18,7 @@
"@types/lodash": "^4.17.12",
"axios": "^1.7.7",
"bootstrap": "^5.3.3",
+ "history": "^5.3.0",
"lodash": "^4.17.21",
"path": "^0.12.7",
"react": "^18.3.1",
@@ -28,17 +31,24 @@
},
"devDependencies": {
"@eslint/js": "^9.11.1",
+ "@testing-library/dom": "^10.4.0",
+ "@testing-library/jest-dom": "^6.6.3",
+ "@testing-library/react": "^16.0.1",
"@types/axios": "^0.14.4",
+ "@types/history": "^5.0.0",
"@types/react": "^18.3.10",
"@types/react-dom": "^18.3.0",
"@types/react-router-dom": "^5.3.3",
"@vitejs/plugin-react": "^4.3.2",
+ "@vitest/coverage-istanbul": "^2.1.1",
"eslint": "^9.11.1",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.12",
"globals": "^15.9.0",
+ "jsdom": "^25.0.1",
"typescript": "^5.5.3",
"typescript-eslint": "^8.7.0",
- "vite": "^5.4.8"
+ "vite": "^5.4.8",
+ "vitest": "^2.1.1"
}
}
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/__mocks__/mockGroupsList.ts b/ambari-admin/src/main/resources/ui/ambari-admin/src/__mocks__/mockGroupsList.ts
new file mode 100644
index 0000000000..5d268dc1f8
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/__mocks__/mockGroupsList.ts
@@ -0,0 +1,408 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export const groupsList = {
+ "href": "http://host.example.com:8080/api/v1/groups?fields=*&_=1725623294531",
+ "items": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/56123478123456781234567812345678123456781234567812345678123456781234567812345678",
+ "Groups": {
+ "group_name": "56123478123456781234567812345678123456781234567812345678123456781234567812345678",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/ferfew",
+ "Groups": {
+ "group_name": "ferfew",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/ferfew/members/admin",
+ "MemberInfo": {
+ "group_name": "ferfew",
+ "user_name": "admin"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/ferfew/members/fghhjhjh",
+ "MemberInfo": {
+ "group_name": "ferfew",
+ "user_name": "fghhjhjh"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/ferfew/members/himanshu%40h",
+ "MemberInfo": {
+ "group_name": "ferfew",
+ "user_name": "himanshu@h"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/gdgdeg",
+ "Groups": {
+ "group_name": "gdgdeg",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/gdgdeg/members/dsasd",
+ "MemberInfo": {
+ "group_name": "gdgdeg",
+ "user_name": "dsasd"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/gdgdeg/members/himanshu%40h",
+ "MemberInfo": {
+ "group_name": "gdgdeg",
+ "user_name": "himanshu@h"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group1",
+ "Groups": {
+ "group_name": "group1",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group1/members/12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "MemberInfo": {
+ "group_name": "group1",
+ "user_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group1/members/dsasd",
+ "MemberInfo": {
+ "group_name": "group1",
+ "user_name": "dsasd"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group1/members/jdgjsaas",
+ "MemberInfo": {
+ "group_name": "group1",
+ "user_name": "jdgjsaas"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group2",
+ "Groups": {
+ "group_name": "group2",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group2/members/jdgjsaas",
+ "MemberInfo": {
+ "group_name": "group2",
+ "user_name": "jdgjsaas"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group3",
+ "Groups": {
+ "group_name": "group3",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group3/members/12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "MemberInfo": {
+ "group_name": "group3",
+ "user_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group3/members/jdgjsaas",
+ "MemberInfo": {
+ "group_name": "group3",
+ "user_name": "jdgjsaas"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group4",
+ "Groups": {
+ "group_name": "group4",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group5",
+ "Groups": {
+ "group_name": "group5",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": []
+ }
+ ]
+ }
+
+ export const paginatedGroupsList = {
+ "href": "http://host.example.com:8080/api/v1/groups?fields=*&_=1725623294531",
+ "items": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/56123478123456781234567812345678123456781234567812345678123456781234567812345678",
+ "Groups": {
+ "group_name": "56123478123456781234567812345678123456781234567812345678123456781234567812345678",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/ferfew",
+ "Groups": {
+ "group_name": "ferfew",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/ferfew/members/admin",
+ "MemberInfo": {
+ "group_name": "ferfew",
+ "user_name": "admin"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/ferfew/members/fghhjhjh",
+ "MemberInfo": {
+ "group_name": "ferfew",
+ "user_name": "fghhjhjh"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/ferfew/members/himanshu%40h",
+ "MemberInfo": {
+ "group_name": "ferfew",
+ "user_name": "himanshu@h"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/gdgdeg",
+ "Groups": {
+ "group_name": "gdgdeg",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/gdgdeg/members/dsasd",
+ "MemberInfo": {
+ "group_name": "gdgdeg",
+ "user_name": "dsasd"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/gdgdeg/members/himanshu%40h",
+ "MemberInfo": {
+ "group_name": "gdgdeg",
+ "user_name": "himanshu@h"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group1",
+ "Groups": {
+ "group_name": "group1",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group1/members/12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "MemberInfo": {
+ "group_name": "group1",
+ "user_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group1/members/dsasd",
+ "MemberInfo": {
+ "group_name": "group1",
+ "user_name": "dsasd"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group1/members/jdgjsaas",
+ "MemberInfo": {
+ "group_name": "group1",
+ "user_name": "jdgjsaas"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group2",
+ "Groups": {
+ "group_name": "group2",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group2/members/jdgjsaas",
+ "MemberInfo": {
+ "group_name": "group2",
+ "user_name": "jdgjsaas"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group3",
+ "Groups": {
+ "group_name": "group3",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group3/members/12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "MemberInfo": {
+ "group_name": "group3",
+ "user_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group3/members/jdgjsaas",
+ "MemberInfo": {
+ "group_name": "group3",
+ "user_name": "jdgjsaas"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group4",
+ "Groups": {
+ "group_name": "group4",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group5",
+ "Groups": {
+ "group_name": "group5",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group6",
+ "Groups": {
+ "group_name": "group6",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group8",
+ "Groups": {
+ "group_name": "group8",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/group9",
+ "Groups": {
+ "group_name": "group9",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [],
+ "members": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/hmaurya.12",
+ "Groups": {
+ "group_name": "hmaurya.12",
+ "group_type": "LOCAL",
+ "ldap_group": false
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/hmaurya.12/privileges/754",
+ "PrivilegeInfo": {
+ "group_name": "hmaurya.12",
+ "privilege_id": 754
+ }
+ }
+ ],
+ "members": [
+ {
+ "href": "http://host.example.com:8080/api/v1/groups/hmaurya.12/members/admin",
+ "MemberInfo": {
+ "group_name": "hmaurya.12",
+ "user_name": "admin"
+ }
+ }
+ ]
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/__mocks__/mockRbacData.ts b/ambari-admin/src/main/resources/ui/ambari-admin/src/__mocks__/mockRbacData.ts
new file mode 100644
index 0000000000..e9a85b49c6
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/__mocks__/mockRbacData.ts
@@ -0,0 +1,1598 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export const rbacData = {
+ "href": "http://host.example.com:8080/api/v1/permissions?PermissionInfo/resource_name.in(CLUSTER,AMBARI)&_=1726470229341&fields=PermissionInfo/*,authorizations/AuthorizationInfo/*",
+ "items": [
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1",
+ "PermissionInfo": {
+ "permission_id": 1,
+ "permission_label": "Ambari Administrator",
+ "permission_name": "AMBARI.ADMINISTRATOR",
+ "resource_name": "AMBARI",
+ "sort_order": 1
+ },
+ "authorizations": [
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.ADD_DELETE_CLUSTERS",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.ADD_DELETE_CLUSTERS",
+ "authorization_name": "Create new clusters",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.ASSIGN_ROLES",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.ASSIGN_ROLES",
+ "authorization_name": "Assign roles",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.EDIT_STACK_REPOS",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.EDIT_STACK_REPOS",
+ "authorization_name": "Edit stack repository URLs",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.MANAGE_CONFIGURATION",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.MANAGE_CONFIGURATION",
+ "authorization_name": "Manage ambari configuration",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.MANAGE_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.MANAGE_GROUPS",
+ "authorization_name": "Manage groups",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.MANAGE_SETTINGS",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.MANAGE_SETTINGS",
+ "authorization_name": "Manage administrative settings",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.MANAGE_STACK_VERSIONS",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.MANAGE_STACK_VERSIONS",
+ "authorization_name": "Manage stack versions",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.MANAGE_USERS",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.MANAGE_USERS",
+ "authorization_name": "Manage users",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.MANAGE_VIEWS",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.MANAGE_VIEWS",
+ "authorization_name": "Manage Ambari Views",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.RENAME_CLUSTER",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.RENAME_CLUSTER",
+ "authorization_name": "Rename clusters",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.RUN_CUSTOM_COMMAND",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.RUN_CUSTOM_COMMAND",
+ "authorization_name": "Perform custom administrative actions",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/AMBARI.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "AMBARI.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.MANAGE_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_ALERTS",
+ "authorization_name": "Manage cluster-level alerts",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.MANAGE_ALERT_NOTIFICATIONS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_ALERT_NOTIFICATIONS",
+ "authorization_name": "Manage alert notifications configuration",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.MANAGE_AUTO_START",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_AUTO_START",
+ "authorization_name": "Manage service auto-start configuration",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.MANAGE_CONFIG_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_CONFIG_GROUPS",
+ "authorization_name": "Manage cluster config groups",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.MANAGE_CREDENTIALS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_CREDENTIALS",
+ "authorization_name": "Manage external credentials",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "authorization_name": "Manage cluster-level user persisted data",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.MANAGE_WIDGETS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_WIDGETS",
+ "authorization_name": "Manage widgets",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.MODIFY_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MODIFY_CONFIGS",
+ "authorization_name": "Modify cluster configurations",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.RUN_CUSTOM_COMMAND",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.RUN_CUSTOM_COMMAND",
+ "authorization_name": "Perform custom cluster-level actions",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.TOGGLE_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.TOGGLE_ALERTS",
+ "authorization_name": "Enable/disable cluster-level alerts",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.TOGGLE_KERBEROS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.TOGGLE_KERBEROS",
+ "authorization_name": "Enable/disable Kerberos",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.UPGRADE_DOWNGRADE_STACK",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.UPGRADE_DOWNGRADE_STACK",
+ "authorization_name": "Upgrade/downgrade stack",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_ALERTS",
+ "authorization_name": "View cluster-level alerts",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.VIEW_STACK_DETAILS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STACK_DETAILS",
+ "authorization_name": "View stack version details",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/CLUSTER.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/HOST.ADD_DELETE_COMPONENTS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.ADD_DELETE_COMPONENTS",
+ "authorization_name": "Install components",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/HOST.ADD_DELETE_HOSTS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.ADD_DELETE_HOSTS",
+ "authorization_name": "Add/Delete hosts",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/HOST.TOGGLE_MAINTENANCE",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.TOGGLE_MAINTENANCE",
+ "authorization_name": "Turn on/off maintenance mode",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/HOST.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/HOST.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/HOST.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.ADD_DELETE_SERVICES",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.ADD_DELETE_SERVICES",
+ "authorization_name": "Add/delete services",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.COMPARE_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.COMPARE_CONFIGS",
+ "authorization_name": "Compare configurations",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.DECOMMISSION_RECOMMISSION",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.DECOMMISSION_RECOMMISSION",
+ "authorization_name": "Decommission/recommission",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.ENABLE_HA",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.ENABLE_HA",
+ "authorization_name": "Enable HA",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.MANAGE_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MANAGE_ALERTS",
+ "authorization_name": "Manage service-level alerts",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.MANAGE_AUTO_START",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MANAGE_AUTO_START",
+ "authorization_name": "Manage service auto-start",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.MANAGE_CONFIG_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MANAGE_CONFIG_GROUPS",
+ "authorization_name": "Manage configuration groups",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.MODIFY_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MODIFY_CONFIGS",
+ "authorization_name": "Modify configurations",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.MOVE",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MOVE",
+ "authorization_name": "Move to another host",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.RUN_CUSTOM_COMMAND",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.RUN_CUSTOM_COMMAND",
+ "authorization_name": "Perform service-specific tasks",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.RUN_SERVICE_CHECK",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.RUN_SERVICE_CHECK",
+ "authorization_name": "Run service checks",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.SET_SERVICE_USERS_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.SET_SERVICE_USERS_GROUPS",
+ "authorization_name": "Set service users and groups",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.START_STOP",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.START_STOP",
+ "authorization_name": "Start/Stop/Restart Service",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.TOGGLE_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.TOGGLE_ALERTS",
+ "authorization_name": "Enable/disable service-level alerts",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.TOGGLE_MAINTENANCE",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.TOGGLE_MAINTENANCE",
+ "authorization_name": "Turn on/off maintenance mode",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_ALERTS",
+ "authorization_name": "View service-level alerts",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_CONFIGS",
+ "authorization_name": "View configurations",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.VIEW_OPERATIONAL_LOGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_OPERATIONAL_LOGS",
+ "authorization_name": "View service operational logs",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/SERVICE.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 1
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/1/authorizations/VIEW.USE",
+ "AuthorizationInfo": {
+ "authorization_id": "VIEW.USE",
+ "authorization_name": "Use View",
+ "permission_id": 1
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2",
+ "PermissionInfo": {
+ "permission_id": 2,
+ "permission_label": "Cluster User",
+ "permission_name": "CLUSTER.USER",
+ "resource_name": "CLUSTER",
+ "sort_order": 6
+ },
+ "authorizations": [
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "authorization_name": "Manage cluster-level user persisted data",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/CLUSTER.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_ALERTS",
+ "authorization_name": "View cluster-level alerts",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/CLUSTER.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/CLUSTER.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/CLUSTER.VIEW_STACK_DETAILS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STACK_DETAILS",
+ "authorization_name": "View stack version details",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/CLUSTER.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/HOST.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/HOST.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/HOST.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/SERVICE.COMPARE_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.COMPARE_CONFIGS",
+ "authorization_name": "Compare configurations",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/SERVICE.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_ALERTS",
+ "authorization_name": "View service-level alerts",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/SERVICE.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_CONFIGS",
+ "authorization_name": "View configurations",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/SERVICE.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 2
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/2/authorizations/SERVICE.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 2
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3",
+ "PermissionInfo": {
+ "permission_id": 3,
+ "permission_label": "Cluster Administrator",
+ "permission_name": "CLUSTER.ADMINISTRATOR",
+ "resource_name": "CLUSTER",
+ "sort_order": 2
+ },
+ "authorizations": [
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.MANAGE_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_ALERTS",
+ "authorization_name": "Manage cluster-level alerts",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.MANAGE_ALERT_NOTIFICATIONS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_ALERT_NOTIFICATIONS",
+ "authorization_name": "Manage alert notifications configuration",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.MANAGE_AUTO_START",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_AUTO_START",
+ "authorization_name": "Manage service auto-start configuration",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.MANAGE_CONFIG_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_CONFIG_GROUPS",
+ "authorization_name": "Manage cluster config groups",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.MANAGE_CREDENTIALS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_CREDENTIALS",
+ "authorization_name": "Manage external credentials",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "authorization_name": "Manage cluster-level user persisted data",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.MANAGE_WIDGETS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_WIDGETS",
+ "authorization_name": "Manage widgets",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.MODIFY_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MODIFY_CONFIGS",
+ "authorization_name": "Modify cluster configurations",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.RUN_CUSTOM_COMMAND",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.RUN_CUSTOM_COMMAND",
+ "authorization_name": "Perform custom cluster-level actions",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.TOGGLE_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.TOGGLE_ALERTS",
+ "authorization_name": "Enable/disable cluster-level alerts",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.TOGGLE_KERBEROS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.TOGGLE_KERBEROS",
+ "authorization_name": "Enable/disable Kerberos",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.UPGRADE_DOWNGRADE_STACK",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.UPGRADE_DOWNGRADE_STACK",
+ "authorization_name": "Upgrade/downgrade stack",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_ALERTS",
+ "authorization_name": "View cluster-level alerts",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.VIEW_STACK_DETAILS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STACK_DETAILS",
+ "authorization_name": "View stack version details",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/CLUSTER.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/HOST.ADD_DELETE_COMPONENTS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.ADD_DELETE_COMPONENTS",
+ "authorization_name": "Install components",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/HOST.ADD_DELETE_HOSTS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.ADD_DELETE_HOSTS",
+ "authorization_name": "Add/Delete hosts",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/HOST.TOGGLE_MAINTENANCE",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.TOGGLE_MAINTENANCE",
+ "authorization_name": "Turn on/off maintenance mode",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/HOST.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/HOST.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/HOST.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.ADD_DELETE_SERVICES",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.ADD_DELETE_SERVICES",
+ "authorization_name": "Add/delete services",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.COMPARE_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.COMPARE_CONFIGS",
+ "authorization_name": "Compare configurations",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.DECOMMISSION_RECOMMISSION",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.DECOMMISSION_RECOMMISSION",
+ "authorization_name": "Decommission/recommission",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.ENABLE_HA",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.ENABLE_HA",
+ "authorization_name": "Enable HA",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.MANAGE_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MANAGE_ALERTS",
+ "authorization_name": "Manage service-level alerts",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.MANAGE_AUTO_START",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MANAGE_AUTO_START",
+ "authorization_name": "Manage service auto-start",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.MANAGE_CONFIG_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MANAGE_CONFIG_GROUPS",
+ "authorization_name": "Manage configuration groups",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.MODIFY_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MODIFY_CONFIGS",
+ "authorization_name": "Modify configurations",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.MOVE",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MOVE",
+ "authorization_name": "Move to another host",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.RUN_CUSTOM_COMMAND",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.RUN_CUSTOM_COMMAND",
+ "authorization_name": "Perform service-specific tasks",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.RUN_SERVICE_CHECK",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.RUN_SERVICE_CHECK",
+ "authorization_name": "Run service checks",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.SET_SERVICE_USERS_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.SET_SERVICE_USERS_GROUPS",
+ "authorization_name": "Set service users and groups",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.START_STOP",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.START_STOP",
+ "authorization_name": "Start/Stop/Restart Service",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.TOGGLE_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.TOGGLE_ALERTS",
+ "authorization_name": "Enable/disable service-level alerts",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.TOGGLE_MAINTENANCE",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.TOGGLE_MAINTENANCE",
+ "authorization_name": "Turn on/off maintenance mode",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_ALERTS",
+ "authorization_name": "View service-level alerts",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_CONFIGS",
+ "authorization_name": "View configurations",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.VIEW_OPERATIONAL_LOGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_OPERATIONAL_LOGS",
+ "authorization_name": "View service operational logs",
+ "permission_id": 3
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/3/authorizations/SERVICE.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 3
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5",
+ "PermissionInfo": {
+ "permission_id": 5,
+ "permission_label": "Cluster Operator",
+ "permission_name": "CLUSTER.OPERATOR",
+ "resource_name": "CLUSTER",
+ "sort_order": 3
+ },
+ "authorizations": [
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/CLUSTER.MANAGE_AUTO_START",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_AUTO_START",
+ "authorization_name": "Manage service auto-start configuration",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/CLUSTER.MANAGE_CONFIG_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_CONFIG_GROUPS",
+ "authorization_name": "Manage cluster config groups",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/CLUSTER.MANAGE_CREDENTIALS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_CREDENTIALS",
+ "authorization_name": "Manage external credentials",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "authorization_name": "Manage cluster-level user persisted data",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/CLUSTER.MANAGE_WIDGETS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_WIDGETS",
+ "authorization_name": "Manage widgets",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/CLUSTER.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_ALERTS",
+ "authorization_name": "View cluster-level alerts",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/CLUSTER.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/CLUSTER.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/CLUSTER.VIEW_STACK_DETAILS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STACK_DETAILS",
+ "authorization_name": "View stack version details",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/CLUSTER.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/HOST.ADD_DELETE_COMPONENTS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.ADD_DELETE_COMPONENTS",
+ "authorization_name": "Install components",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/HOST.ADD_DELETE_HOSTS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.ADD_DELETE_HOSTS",
+ "authorization_name": "Add/Delete hosts",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/HOST.TOGGLE_MAINTENANCE",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.TOGGLE_MAINTENANCE",
+ "authorization_name": "Turn on/off maintenance mode",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/HOST.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/HOST.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/HOST.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.COMPARE_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.COMPARE_CONFIGS",
+ "authorization_name": "Compare configurations",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.DECOMMISSION_RECOMMISSION",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.DECOMMISSION_RECOMMISSION",
+ "authorization_name": "Decommission/recommission",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.ENABLE_HA",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.ENABLE_HA",
+ "authorization_name": "Enable HA",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.MANAGE_AUTO_START",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MANAGE_AUTO_START",
+ "authorization_name": "Manage service auto-start",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.MANAGE_CONFIG_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MANAGE_CONFIG_GROUPS",
+ "authorization_name": "Manage configuration groups",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.MODIFY_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MODIFY_CONFIGS",
+ "authorization_name": "Modify configurations",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.MOVE",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MOVE",
+ "authorization_name": "Move to another host",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.RUN_CUSTOM_COMMAND",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.RUN_CUSTOM_COMMAND",
+ "authorization_name": "Perform service-specific tasks",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.RUN_SERVICE_CHECK",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.RUN_SERVICE_CHECK",
+ "authorization_name": "Run service checks",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.START_STOP",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.START_STOP",
+ "authorization_name": "Start/Stop/Restart Service",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.TOGGLE_MAINTENANCE",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.TOGGLE_MAINTENANCE",
+ "authorization_name": "Turn on/off maintenance mode",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_ALERTS",
+ "authorization_name": "View service-level alerts",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_CONFIGS",
+ "authorization_name": "View configurations",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.VIEW_OPERATIONAL_LOGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_OPERATIONAL_LOGS",
+ "authorization_name": "View service operational logs",
+ "permission_id": 5
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/5/authorizations/SERVICE.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 5
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6",
+ "PermissionInfo": {
+ "permission_id": 6,
+ "permission_label": "Service Administrator",
+ "permission_name": "SERVICE.ADMINISTRATOR",
+ "resource_name": "CLUSTER",
+ "sort_order": 4
+ },
+ "authorizations": [
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/CLUSTER.MANAGE_CONFIG_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_CONFIG_GROUPS",
+ "authorization_name": "Manage cluster config groups",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "authorization_name": "Manage cluster-level user persisted data",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/CLUSTER.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_ALERTS",
+ "authorization_name": "View cluster-level alerts",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/CLUSTER.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/CLUSTER.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/CLUSTER.VIEW_STACK_DETAILS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STACK_DETAILS",
+ "authorization_name": "View stack version details",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/CLUSTER.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/HOST.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/HOST.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/HOST.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.COMPARE_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.COMPARE_CONFIGS",
+ "authorization_name": "Compare configurations",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.DECOMMISSION_RECOMMISSION",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.DECOMMISSION_RECOMMISSION",
+ "authorization_name": "Decommission/recommission",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.MANAGE_AUTO_START",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MANAGE_AUTO_START",
+ "authorization_name": "Manage service auto-start",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.MANAGE_CONFIG_GROUPS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MANAGE_CONFIG_GROUPS",
+ "authorization_name": "Manage configuration groups",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.MODIFY_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.MODIFY_CONFIGS",
+ "authorization_name": "Modify configurations",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.RUN_CUSTOM_COMMAND",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.RUN_CUSTOM_COMMAND",
+ "authorization_name": "Perform service-specific tasks",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.RUN_SERVICE_CHECK",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.RUN_SERVICE_CHECK",
+ "authorization_name": "Run service checks",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.START_STOP",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.START_STOP",
+ "authorization_name": "Start/Stop/Restart Service",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.TOGGLE_MAINTENANCE",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.TOGGLE_MAINTENANCE",
+ "authorization_name": "Turn on/off maintenance mode",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_ALERTS",
+ "authorization_name": "View service-level alerts",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_CONFIGS",
+ "authorization_name": "View configurations",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.VIEW_OPERATIONAL_LOGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_OPERATIONAL_LOGS",
+ "authorization_name": "View service operational logs",
+ "permission_id": 6
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/6/authorizations/SERVICE.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 6
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7",
+ "PermissionInfo": {
+ "permission_id": 7,
+ "permission_label": "Service Operator",
+ "permission_name": "SERVICE.OPERATOR",
+ "resource_name": "CLUSTER",
+ "sort_order": 5
+ },
+ "authorizations": [
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.MANAGE_USER_PERSISTED_DATA",
+ "authorization_name": "Manage cluster-level user persisted data",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/CLUSTER.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_ALERTS",
+ "authorization_name": "View cluster-level alerts",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/CLUSTER.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/CLUSTER.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/CLUSTER.VIEW_STACK_DETAILS",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STACK_DETAILS",
+ "authorization_name": "View stack version details",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/CLUSTER.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "CLUSTER.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/HOST.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_CONFIGS",
+ "authorization_name": "View configuration",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/HOST.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/HOST.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "HOST.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/SERVICE.COMPARE_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.COMPARE_CONFIGS",
+ "authorization_name": "Compare configurations",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/SERVICE.DECOMMISSION_RECOMMISSION",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.DECOMMISSION_RECOMMISSION",
+ "authorization_name": "Decommission/recommission",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/SERVICE.RUN_CUSTOM_COMMAND",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.RUN_CUSTOM_COMMAND",
+ "authorization_name": "Perform service-specific tasks",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/SERVICE.RUN_SERVICE_CHECK",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.RUN_SERVICE_CHECK",
+ "authorization_name": "Run service checks",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/SERVICE.START_STOP",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.START_STOP",
+ "authorization_name": "Start/Stop/Restart Service",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/SERVICE.TOGGLE_MAINTENANCE",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.TOGGLE_MAINTENANCE",
+ "authorization_name": "Turn on/off maintenance mode",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/SERVICE.VIEW_ALERTS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_ALERTS",
+ "authorization_name": "View service-level alerts",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/SERVICE.VIEW_CONFIGS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_CONFIGS",
+ "authorization_name": "View configurations",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/SERVICE.VIEW_METRICS",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_METRICS",
+ "authorization_name": "View metrics",
+ "permission_id": 7
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/permissions/7/authorizations/SERVICE.VIEW_STATUS_INFO",
+ "AuthorizationInfo": {
+ "authorization_id": "SERVICE.VIEW_STATUS_INFO",
+ "authorization_name": "View status information",
+ "permission_id": 7
+ }
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/__mocks__/mockUsersList.ts b/ambari-admin/src/main/resources/ui/ambari-admin/src/__mocks__/mockUsersList.ts
new file mode 100644
index 0000000000..a1929cd5ca
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/__mocks__/mockUsersList.ts
@@ -0,0 +1,919 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export const usersList = {
+ "href": "http://host.example.com:8080/api/v1/users?fields=Users/*,privileges/*&_=1725622903674",
+ "items": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1724736468537,
+ "display_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "groups": [
+ "group3",
+ "group1"
+ ],
+ "ldap_user": false,
+ "local_user_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "user_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/12345678123456781234567812345678123456781234567812345678123456781234567812345678/privileges/802",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster User",
+ "permission_name": "CLUSTER.USER",
+ "principal_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "principal_type": "USER",
+ "privilege_id": 802,
+ "type": "CLUSTER",
+ "user_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/1234567890123456789012345678901234567890123456789",
+ "Users": {
+ "active": false,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1724655063232,
+ "display_name": "1234567890123456789012345678901234567890123456789",
+ "groups": [],
+ "ldap_user": false,
+ "local_user_name": "1234567890123456789012345678901234567890123456789",
+ "user_name": "1234567890123456789012345678901234567890123456789",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/1234567890123456789012345678901234567890123456789/privileges/755",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster User",
+ "permission_name": "CLUSTER.USER",
+ "principal_name": "1234567890123456789012345678901234567890123456789",
+ "principal_type": "USER",
+ "privilege_id": 755,
+ "type": "CLUSTER",
+ "user_name": "1234567890123456789012345678901234567890123456789"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1725360999195,
+ "display_name": "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "groups": [],
+ "ldap_user": false,
+ "local_user_name": "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "user_name": "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "user_type": "LOCAL"
+ },
+ "privileges": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin",
+ "Users": {
+ "active": true,
+ "admin": true,
+ "consecutive_failures": 0,
+ "created": 1717156373000,
+ "display_name": "Administrator",
+ "groups": [
+ "test",
+ "ferfew",
+ "vdfgdsf",
+ "hmaurya.12"
+ ],
+ "ldap_user": false,
+ "local_user_name": "admin",
+ "user_name": "admin",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/1",
+ "PrivilegeInfo": {
+ "permission_label": "Ambari Administrator",
+ "permission_name": "AMBARI.ADMINISTRATOR",
+ "principal_name": "admin",
+ "principal_type": "USER",
+ "privilege_id": 1,
+ "type": "AMBARI",
+ "user_name": "admin"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/397",
+ "PrivilegeInfo": {
+ "instance_name": "sjhadja",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "admin",
+ "principal_type": "USER",
+ "privilege_id": 397,
+ "type": "VIEW",
+ "user_name": "admin",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/404",
+ "PrivilegeInfo": {
+ "instance_name": "jfkdfd",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "admin",
+ "principal_type": "USER",
+ "privilege_id": 404,
+ "type": "VIEW",
+ "user_name": "admin",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/558",
+ "PrivilegeInfo": {
+ "instance_name": "Files",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "admin",
+ "principal_type": "USER",
+ "privilege_id": 558,
+ "type": "VIEW",
+ "user_name": "admin",
+ "version": "1.0.0",
+ "view_name": "FILES"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/657",
+ "PrivilegeInfo": {
+ "instance_name": "Files2",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "admin",
+ "principal_type": "USER",
+ "privilege_id": 657,
+ "type": "VIEW",
+ "user_name": "admin",
+ "version": "1.0.0",
+ "view_name": "FILES"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/754",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster Administrator",
+ "permission_name": "CLUSTER.ADMINISTRATOR",
+ "principal_name": "hmaurya.12",
+ "principal_type": "GROUP",
+ "privilege_id": 754,
+ "type": "CLUSTER",
+ "user_name": "admin"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/dsasd",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1724325120429,
+ "display_name": "dsasd",
+ "groups": [
+ "gdgdeg",
+ "group1"
+ ],
+ "ldap_user": false,
+ "local_user_name": "dsasd",
+ "user_name": "dsasd",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/dsasd/privileges/702",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster Administrator",
+ "permission_name": "CLUSTER.ADMINISTRATOR",
+ "principal_name": "dsasd",
+ "principal_type": "USER",
+ "privilege_id": 702,
+ "type": "CLUSTER",
+ "user_name": "dsasd"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/fghhjhjh",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1725355896220,
+ "display_name": "fghhjhjh",
+ "groups": [
+ "ferfew"
+ ],
+ "ldap_user": false,
+ "local_user_name": "fghhjhjh",
+ "user_name": "fghhjhjh",
+ "user_type": "LOCAL"
+ },
+ "privileges": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/himanshu%40h",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1724652183474,
+ "display_name": "Himanshu@h",
+ "groups": [
+ "ferfew",
+ "gdgdeg"
+ ],
+ "ldap_user": false,
+ "local_user_name": "Himanshu@h",
+ "user_name": "himanshu@h",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/himanshu%40h/privileges/753",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster Administrator",
+ "permission_name": "CLUSTER.ADMINISTRATOR",
+ "principal_name": "himanshu@h",
+ "principal_type": "USER",
+ "privilege_id": 753,
+ "type": "CLUSTER",
+ "user_name": "himanshu@h"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/himanshu%40h/privileges/850",
+ "PrivilegeInfo": {
+ "instance_name": "asa",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "himanshu@h",
+ "principal_type": "USER",
+ "privilege_id": 850,
+ "type": "VIEW",
+ "user_name": "himanshu@h",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/himanshu%40h/privileges/851",
+ "PrivilegeInfo": {
+ "instance_name": "cscddwc",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "himanshu@h",
+ "principal_type": "USER",
+ "privilege_id": 851,
+ "type": "VIEW",
+ "user_name": "himanshu@h",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/himanshu%40h/privileges/855",
+ "PrivilegeInfo": {
+ "instance_name": "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "himanshu@h",
+ "principal_type": "USER",
+ "privilege_id": 855,
+ "type": "VIEW",
+ "user_name": "himanshu@h",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/jdgjsaas",
+ "Users": {
+ "active": true,
+ "admin": true,
+ "consecutive_failures": 0,
+ "created": 1723460606840,
+ "display_name": "jdgjsaas",
+ "groups": [
+ "group3",
+ "group2",
+ "group1"
+ ],
+ "ldap_user": false,
+ "local_user_name": "jdgjsaas",
+ "user_name": "jdgjsaas",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/jdgjsaas/privileges/654",
+ "PrivilegeInfo": {
+ "instance_name": "test5",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "jdgjsaas",
+ "principal_type": "USER",
+ "privilege_id": 654,
+ "type": "VIEW",
+ "user_name": "jdgjsaas",
+ "version": "1.0.0",
+ "view_name": "FILES"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/jdgjsaas/privileges/656",
+ "PrivilegeInfo": {
+ "instance_name": "Files2",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "jdgjsaas",
+ "principal_type": "USER",
+ "privilege_id": 656,
+ "type": "VIEW",
+ "user_name": "jdgjsaas",
+ "version": "1.0.0",
+ "view_name": "FILES"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/jdgjsaas/privileges/703",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster Administrator",
+ "permission_name": "CLUSTER.ADMINISTRATOR",
+ "principal_name": "jdgjsaas",
+ "principal_type": "USER",
+ "privilege_id": 703,
+ "type": "CLUSTER",
+ "user_name": "jdgjsaas"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/jdgjsaas/privileges/752",
+ "PrivilegeInfo": {
+ "permission_label": "Ambari Administrator",
+ "permission_name": "AMBARI.ADMINISTRATOR",
+ "principal_name": "jdgjsaas",
+ "principal_type": "USER",
+ "privilege_id": 752,
+ "type": "AMBARI",
+ "user_name": "jdgjsaas"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/sandeep",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1724143724415,
+ "display_name": "sandeep",
+ "groups": [],
+ "ldap_user": false,
+ "local_user_name": "sandeep",
+ "user_name": "sandeep",
+ "user_type": "LOCAL"
+ },
+ "privileges": []
+ }
+ ]
+ }
+
+ export const paginatedUsersList = {
+ "href": "http://host.example.com:8080/api/v1/users?fields=Users/*,privileges/*&_=1725622903674",
+ "items": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1724736468537,
+ "display_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "groups": [
+ "group3",
+ "group1"
+ ],
+ "ldap_user": false,
+ "local_user_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "user_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/12345678123456781234567812345678123456781234567812345678123456781234567812345678/privileges/802",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster User",
+ "permission_name": "CLUSTER.USER",
+ "principal_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678",
+ "principal_type": "USER",
+ "privilege_id": 802,
+ "type": "CLUSTER",
+ "user_name": "12345678123456781234567812345678123456781234567812345678123456781234567812345678"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/1234567890123456789012345678901234567890123456789",
+ "Users": {
+ "active": false,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1724655063232,
+ "display_name": "1234567890123456789012345678901234567890123456789",
+ "groups": [],
+ "ldap_user": false,
+ "local_user_name": "1234567890123456789012345678901234567890123456789",
+ "user_name": "1234567890123456789012345678901234567890123456789",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/1234567890123456789012345678901234567890123456789/privileges/755",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster User",
+ "permission_name": "CLUSTER.USER",
+ "principal_name": "1234567890123456789012345678901234567890123456789",
+ "principal_type": "USER",
+ "privilege_id": 755,
+ "type": "CLUSTER",
+ "user_name": "1234567890123456789012345678901234567890123456789"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1725360999195,
+ "display_name": "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "groups": [],
+ "ldap_user": false,
+ "local_user_name": "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "user_name": "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "user_type": "LOCAL"
+ },
+ "privileges": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin",
+ "Users": {
+ "active": true,
+ "admin": true,
+ "consecutive_failures": 0,
+ "created": 1717156373000,
+ "display_name": "Administrator",
+ "groups": [
+ "test",
+ "ferfew",
+ "vdfgdsf",
+ "hmaurya.12"
+ ],
+ "ldap_user": false,
+ "local_user_name": "admin",
+ "user_name": "admin",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/1",
+ "PrivilegeInfo": {
+ "permission_label": "Ambari Administrator",
+ "permission_name": "AMBARI.ADMINISTRATOR",
+ "principal_name": "admin",
+ "principal_type": "USER",
+ "privilege_id": 1,
+ "type": "AMBARI",
+ "user_name": "admin"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/397",
+ "PrivilegeInfo": {
+ "instance_name": "sjhadja",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "admin",
+ "principal_type": "USER",
+ "privilege_id": 397,
+ "type": "VIEW",
+ "user_name": "admin",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/404",
+ "PrivilegeInfo": {
+ "instance_name": "jfkdfd",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "admin",
+ "principal_type": "USER",
+ "privilege_id": 404,
+ "type": "VIEW",
+ "user_name": "admin",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/558",
+ "PrivilegeInfo": {
+ "instance_name": "Files",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "admin",
+ "principal_type": "USER",
+ "privilege_id": 558,
+ "type": "VIEW",
+ "user_name": "admin",
+ "version": "1.0.0",
+ "view_name": "FILES"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/657",
+ "PrivilegeInfo": {
+ "instance_name": "Files2",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "admin",
+ "principal_type": "USER",
+ "privilege_id": 657,
+ "type": "VIEW",
+ "user_name": "admin",
+ "version": "1.0.0",
+ "view_name": "FILES"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/admin/privileges/754",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster Administrator",
+ "permission_name": "CLUSTER.ADMINISTRATOR",
+ "principal_name": "hmaurya.12",
+ "principal_type": "GROUP",
+ "privilege_id": 754,
+ "type": "CLUSTER",
+ "user_name": "admin"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/dsasd",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1724325120429,
+ "display_name": "dsasd",
+ "groups": [
+ "gdgdeg",
+ "group1"
+ ],
+ "ldap_user": false,
+ "local_user_name": "dsasd",
+ "user_name": "dsasd",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/dsasd/privileges/702",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster Administrator",
+ "permission_name": "CLUSTER.ADMINISTRATOR",
+ "principal_name": "dsasd",
+ "principal_type": "USER",
+ "privilege_id": 702,
+ "type": "CLUSTER",
+ "user_name": "dsasd"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/fghhjhjh",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1725355896220,
+ "display_name": "fghhjhjh",
+ "groups": [
+ "ferfew"
+ ],
+ "ldap_user": false,
+ "local_user_name": "fghhjhjh",
+ "user_name": "fghhjhjh",
+ "user_type": "LOCAL"
+ },
+ "privileges": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/himanshu%40h",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1724652183474,
+ "display_name": "Himanshu@h",
+ "groups": [
+ "ferfew",
+ "gdgdeg"
+ ],
+ "ldap_user": false,
+ "local_user_name": "Himanshu@h",
+ "user_name": "himanshu@h",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/himanshu%40h/privileges/753",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster Administrator",
+ "permission_name": "CLUSTER.ADMINISTRATOR",
+ "principal_name": "himanshu@h",
+ "principal_type": "USER",
+ "privilege_id": 753,
+ "type": "CLUSTER",
+ "user_name": "himanshu@h"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/himanshu%40h/privileges/850",
+ "PrivilegeInfo": {
+ "instance_name": "asa",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "himanshu@h",
+ "principal_type": "USER",
+ "privilege_id": 850,
+ "type": "VIEW",
+ "user_name": "himanshu@h",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/himanshu%40h/privileges/851",
+ "PrivilegeInfo": {
+ "instance_name": "cscddwc",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "himanshu@h",
+ "principal_type": "USER",
+ "privilege_id": 851,
+ "type": "VIEW",
+ "user_name": "himanshu@h",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/himanshu%40h/privileges/855",
+ "PrivilegeInfo": {
+ "instance_name": "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "himanshu@h",
+ "principal_type": "USER",
+ "privilege_id": 855,
+ "type": "VIEW",
+ "user_name": "himanshu@h",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/jdgjsaas",
+ "Users": {
+ "active": true,
+ "admin": true,
+ "consecutive_failures": 0,
+ "created": 1723460606840,
+ "display_name": "jdgjsaas",
+ "groups": [
+ "group3",
+ "group2",
+ "group1"
+ ],
+ "ldap_user": false,
+ "local_user_name": "jdgjsaas",
+ "user_name": "jdgjsaas",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/jdgjsaas/privileges/654",
+ "PrivilegeInfo": {
+ "instance_name": "test5",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "jdgjsaas",
+ "principal_type": "USER",
+ "privilege_id": 654,
+ "type": "VIEW",
+ "user_name": "jdgjsaas",
+ "version": "1.0.0",
+ "view_name": "FILES"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/jdgjsaas/privileges/656",
+ "PrivilegeInfo": {
+ "instance_name": "Files2",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "jdgjsaas",
+ "principal_type": "USER",
+ "privilege_id": 656,
+ "type": "VIEW",
+ "user_name": "jdgjsaas",
+ "version": "1.0.0",
+ "view_name": "FILES"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/jdgjsaas/privileges/703",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster Administrator",
+ "permission_name": "CLUSTER.ADMINISTRATOR",
+ "principal_name": "jdgjsaas",
+ "principal_type": "USER",
+ "privilege_id": 703,
+ "type": "CLUSTER",
+ "user_name": "jdgjsaas"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/jdgjsaas/privileges/752",
+ "PrivilegeInfo": {
+ "permission_label": "Ambari Administrator",
+ "permission_name": "AMBARI.ADMINISTRATOR",
+ "principal_name": "jdgjsaas",
+ "principal_type": "USER",
+ "privilege_id": 752,
+ "type": "AMBARI",
+ "user_name": "jdgjsaas"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/sandeep",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1724143724415,
+ "display_name": "sandeep",
+ "groups": [],
+ "ldap_user": false,
+ "local_user_name": "sandeep",
+ "user_name": "sandeep",
+ "user_type": "LOCAL"
+ },
+ "privileges": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/scscadcsa",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1721627578812,
+ "display_name": "scscadcsa",
+ "groups": [],
+ "ldap_user": false,
+ "local_user_name": "scscadcsa",
+ "user_name": "scscadcsa",
+ "user_type": "LOCAL"
+ },
+ "privileges": [
+ {
+ "href": "http://host.example.com:8080/api/v1/users/scscadcsa/privileges/653",
+ "PrivilegeInfo": {
+ "instance_name": "qrwre",
+ "permission_label": "View User",
+ "permission_name": "VIEW.USER",
+ "principal_name": "scscadcsa",
+ "principal_type": "USER",
+ "privilege_id": 653,
+ "type": "VIEW",
+ "user_name": "scscadcsa",
+ "version": "1.0.0",
+ "view_name": "CAPACITY-SCHEDULER"
+ }
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/scscadcsa/privileges/854",
+ "PrivilegeInfo": {
+ "cluster_name": "dshcjhcwj",
+ "permission_label": "Cluster User",
+ "permission_name": "CLUSTER.USER",
+ "principal_name": "scscadcsa",
+ "principal_type": "USER",
+ "privilege_id": 854,
+ "type": "CLUSTER",
+ "user_name": "scscadcsa"
+ }
+ }
+ ]
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/test1",
+ "Users": {
+ "active": true,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1723549891953,
+ "display_name": "test1",
+ "groups": [],
+ "ldap_user": false,
+ "local_user_name": "test1",
+ "user_name": "test1",
+ "user_type": "LOCAL"
+ },
+ "privileges": []
+ },
+ {
+ "href": "http://host.example.com:8080/api/v1/users/test10",
+ "Users": {
+ "active": false,
+ "admin": false,
+ "consecutive_failures": 0,
+ "created": 1723559647764,
+ "display_name": "test10",
+ "groups": [],
+ "ldap_user": false,
+ "local_user_name": "test10",
+ "user_name": "test10",
+ "user_type": "LOCAL"
+ },
+ "privileges": []
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/AddUser.tsx b/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/AddUser.tsx
new file mode 100644
index 0000000000..f6cf6f3777
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/AddUser.tsx
@@ -0,0 +1,428 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { useEffect } from "react";
+import { Button, Form, Modal } from "react-bootstrap";
+import { faCircleXmark, faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
+import DefaultButton from "../../components/DefaultButton";
+import { useRef, useState } from "react";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import ErrorOverlay from "../../components/ErrorOverlay";
+import RoleBasedAccessControl from "./RoleBasedAccessControl";
+import { permissionLabelToName, userAccessOptions } from "./constants";
+import WarningModal from "./WarningModal";
+import { PrivilegesDataType, UserDataType } from "../../api/types";
+import UserGroupApi from "../../api/userGroupApi";
+import toast from "react-hot-toast";
+import { DefaultAccess, PrincipalType } from "./enums";
+import { PermissionLabel } from "./types";
+import PrivilegeApi from "../../api/privilegeApi";
+import { Link } from "react-router-dom";
+import { get, set } from "lodash";
+
+type AddUserProps = {
+ clusterName: string;
+ showAddUserModal: boolean;
+ setShowAddUserModal: (showAddUserModal: boolean) => void;
+ successCallback: () => void;
+};
+
+enum UserNameCriteria {
+ REGEX = "^[^\\\\&|<>`]*$",
+ MAX_LENGTH = 80,
+}
+
+export default function AddUser({
+ clusterName,
+ showAddUserModal,
+ setShowAddUserModal,
+ successCallback,
+}: AddUserProps) {
+ const [showUsernameTooltip, setShowUsernameTooltip] = useState(false);
+ const [showRoleAccessModal, setShowRoleAccessModal] = useState(false);
+ const [showUserAmbariAdminTooltip, setShowUserAmbariAdminTooltip] =
+ useState(false);
+ const [showUserStatusTooltip, setShowUserStatusTooltip] = useState(false);
+
+ const [userName, setUserName] = useState("");
+ const [password, setPassword] = useState("");
+ const [confirmPassword, setConfirmPassword] = useState("");
+ const [userAccess, setUserAccess] = useState<PermissionLabel>("None");
+ const [isUserAmbariAdmin, setIsUserAmbariAdmin] = useState(false);
+ const [isUserActive, setIsUserActive] = useState(true);
+ const [showAddUserCancelWarning, setShowAddUserCancelWarning] =
+ useState(false);
+ const [validationError, setValidationError] = useState({
+ userName: "Field required!",
+ password: "Field required!",
+ confirmPassword: "Field required!",
+ });
+ const [isFormSubmitted, setIsFormSubmitted] = useState(false);
+
+ const userNameTarget = useRef(null);
+ const userAccessTarget = useRef(null);
+ const userAmbariAdminTarget = useRef(null);
+ const userStatusTarget = useRef(null);
+
+ useEffect(() => {
+ if (!showAddUserModal) {
+ resetValues();
+ setShowUsernameTooltip(false);
+ setShowRoleAccessModal(false);
+ setShowUserAmbariAdminTooltip(false);
+ setShowUserStatusTooltip(false);
+ setShowAddUserModal(false);
+ setValidationError({
+ userName: "Field required!",
+ password: "Field required!",
+ confirmPassword: "Field required!",
+ });
+ setIsFormSubmitted(false);
+ }
+ }, [showAddUserModal]);
+
+ useEffect(() => {
+ let error = {
+ ...validationError,
+ };
+ if (password) {
+ set(error, "password", "");
+ } else {
+ set(error, "password", "Field required!");
+ }
+ if (!confirmPassword) {
+ set(error, "confirmPassword", "Field required!");
+ } else if (password !== confirmPassword) {
+ set(error, "confirmPassword", "Password must match!");
+ } else {
+ set(error, "confirmPassword", "");
+ }
+ setValidationError(error);
+ }, [password, confirmPassword]);
+
+ const validateUserName = (userNameValue: string) => {
+ const regex = new RegExp(UserNameCriteria.REGEX);
+ if (!userNameValue) {
+ setValidationError({
+ ...validationError,
+ userName: "Field required!",
+ });
+ } else if (!regex.test(userNameValue)) {
+ setValidationError({
+ ...validationError,
+ userName: "Must not contain special characters!",
+ });
+ } else if (userNameValue.length > UserNameCriteria.MAX_LENGTH) {
+ setValidationError({
+ ...validationError,
+ userName: "Must not be longer than 80 characters!",
+ });
+ } else {
+ setValidationError({
+ ...validationError,
+ userName: "",
+ });
+ }
+ };
+
+ const handleSave = async (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ if (
+ userName &&
+ password &&
+ confirmPassword &&
+ !get(validationError, "userName") &&
+ !get(validationError, "password") &&
+ !get(validationError, "confirmPassword")
+ ) {
+ const userData: UserDataType = {
+ "Users/active": isUserActive,
+ "Users/admin": isUserAmbariAdmin,
+ "Users/password": password,
+ "Users/user_name": userName,
+ };
+ await UserGroupApi.addUser(userData);
+ toast.success(
+ <div className="toast-message">
+ Created user{" "}
+ <Link to={`/users/${userName}/edit`} className="custom-link">
+ {userName}
+ </Link>
+ </div>
+ );
+ if (userAccess !== DefaultAccess.NONE) {
+ const privilegesData: PrivilegesDataType[] = [
+ {
+ PrivilegeInfo: {
+ permission_name: permissionLabelToName[userAccess],
+ principal_name: userName,
+ principal_type: PrincipalType.USER,
+ },
+ },
+ ];
+ await PrivilegeApi.addClusterPrivileges(clusterName, privilegesData);
+ }
+ resetValues();
+ setShowAddUserModal(false);
+ successCallback();
+ }
+ };
+
+ const resetValues = () => {
+ setUserName("");
+ setPassword("");
+ setConfirmPassword("");
+ setUserAccess("None");
+ setIsUserAmbariAdmin(false);
+ setIsUserActive(true);
+ };
+
+ const handleCancel = () => {
+ if (
+ userName ||
+ password ||
+ confirmPassword ||
+ userAccess !== "None" ||
+ isUserAmbariAdmin ||
+ !isUserActive
+ ) {
+ setShowAddUserCancelWarning(true);
+ } else {
+ setShowAddUserModal(false);
+ }
+ };
+
+ const handleWarningSave = (event: any) => {
+ setShowAddUserCancelWarning(false);
+ handleSave(event);
+ };
+
+ const handleWarningDiscard = () => {
+ setShowAddUserCancelWarning(false);
+ setShowAddUserModal(false);
+ };
+
+ return (
+ <Modal
+ show={showAddUserModal}
+ onHide={handleCancel}
+ size="lg"
+ className="custom-modal-container"
+ data-testid="add-user-modal"
+ >
+ <Modal.Header closeButton>
+ <Modal.Title className="ms-2">Add Users</Modal.Title>
+ </Modal.Header>
+ <Form onSubmit={handleSave}>
+ <Modal.Body>
+ <Form.Group className="mb-4">
+ <Form.Label>
+ Username *{" "}
+ <FontAwesomeIcon
+ icon={faQuestionCircle}
+ onClick={() => setShowUsernameTooltip(!showUsernameTooltip)}
+ data-testid="username-tooltip-icon"
+ />
+ </Form.Label>
+ <Form.Control
+ type="text"
+ value={userName}
+ ref={userNameTarget}
+ placeholder="User name"
+ className={
+ get(validationError, "userName", "") && isFormSubmitted
+ ? "custom-form-control border-danger"
+ : "custom-form-control"
+ }
+ onChange={(e) => {
+ setUserName(e.target.value);
+ validateUserName(e.target.value);
+ }}
+ data-testid="username-input"
+ />
+ {get(validationError, "userName", "") && isFormSubmitted ? (
+ <div className="text-danger mt-1">
+ <FontAwesomeIcon icon={faCircleXmark} />{" "}
+ {get(validationError, "userName")}
+ </div>
+ ) : null}
+ <ErrorOverlay
+ target={userNameTarget}
+ showTooltip={showUsernameTooltip}
+ errorMessage="Maximum length is 80 characters. \, &, |, <, >, `
+ are not allowed."
+ />
+ </Form.Group>
+ <Form.Group className="mb-4 d-flex ">
+ <Form.Group className="me-auto">
+ <Form.Label>Password *</Form.Label>
+ <Form.Control
+ type="password"
+ value={password}
+ htmlSize={40}
+ placeholder="Password"
+ onChange={(e) => setPassword(e.target.value)}
+ className={
+ get(validationError, "password", "") && isFormSubmitted
+ ? "custom-form-control border-danger"
+ : "custom-form-control"
+ }
+ data-testid="password-input"
+ />
+ {get(validationError, "password", "") && isFormSubmitted ? (
+ <div className="text-danger mt-1">
+ <FontAwesomeIcon icon={faCircleXmark} />{" "}
+ {get(validationError, "password")}
+ </div>
+ ) : null}
+ </Form.Group>
+ <Form.Group>
+ <Form.Label>Confirm Password *</Form.Label>
+ <Form.Control
+ type="password"
+ value={confirmPassword}
+ htmlSize={40}
+ placeholder="Confirm Password"
+ onChange={(e) => setConfirmPassword(e.target.value)}
+ className={
+ get(validationError, "confirmPassword", "") && isFormSubmitted
+ ? "custom-form-control border-danger"
+ : "custom-form-control"
+ }
+ data-testid="confirm-password-input"
+ />
+ {get(validationError, "confirmPassword", "") &&
+ isFormSubmitted ? (
+ <div className="text-danger mt-1">
+ <FontAwesomeIcon icon={faCircleXmark} />{" "}
+ {get(validationError, "confirmPassword")}
+ </div>
+ ) : null}
+ </Form.Group>
+ </Form.Group>
+ <Form.Group className="mb-4">
+ <Form.Label>
+ User Access *{" "}
+ <FontAwesomeIcon
+ icon={faQuestionCircle}
+ onClick={() => setShowRoleAccessModal(true)}
+ ref={userAccessTarget}
+ data-testid="user-access-help-icon"
+ />
+ <RoleBasedAccessControl
+ isOpen={showRoleAccessModal}
+ onClose={() => setShowRoleAccessModal(false)}
+ />
+ </Form.Label>
+ <Form.Select
+ aria-label="Select"
+ className="w-50 custom-form-control"
+ onChange={(e) => setUserAccess(e.target.value as PermissionLabel)}
+ data-testid="user-access-dropdown"
+ >
+ {userAccessOptions.map((accessOption, idx) => (
+ <option value={accessOption} key={idx}>
+ {accessOption}
+ </option>
+ ))}
+ </Form.Select>
+ </Form.Group>
+ <Form.Group className="mb-4">
+ <Form.Label>
+ Is this user an Ambari Admin? *{" "}
+ <FontAwesomeIcon
+ icon={faQuestionCircle}
+ onClick={() =>
+ setShowUserAmbariAdminTooltip(!showUserAmbariAdminTooltip)
+ }
+ ref={userAmbariAdminTarget}
+ data-testid="ambari-admin-tooltip-icon"
+ />
+ <ErrorOverlay
+ target={userAmbariAdminTarget}
+ showTooltip={showUserAmbariAdminTooltip}
+ errorMessage="An Ambari Admin can create new clusters and other Ambari Admin Users."
+ />
+ </Form.Label>
+ <div className="d-flex">
+ <Form.Check
+ type="switch"
+ checked={isUserAmbariAdmin}
+ onChange={() => setIsUserAmbariAdmin(!isUserAmbariAdmin)}
+ className="custom-form-check"
+ data-testid="ambari-admin-switch"
+ />
+ {isUserAmbariAdmin ? (
+ <span className="m-2 ps-2">Yes</span>
+ ) : (
+ <span className="m-2 ps-2">No</span>
+ )}
+ </div>
+ </Form.Group>
+ <Form.Group className="mb-4">
+ <Form.Label>
+ User Status *{" "}
+ <FontAwesomeIcon
+ icon={faQuestionCircle}
+ onClick={() => setShowUserStatusTooltip(!showUserStatusTooltip)}
+ ref={userStatusTarget}
+ data-testid="user-status-tooltip-icon"
+ />
+ <ErrorOverlay
+ target={userStatusTarget}
+ showTooltip={showUserStatusTooltip}
+ errorMessage="Active Users can log in to Ambari. Inactive Users cannot."
+ />
+ </Form.Label>
+ <div className="d-flex">
+ <Form.Check
+ type="switch"
+ checked={isUserActive}
+ onChange={() => setIsUserActive(!isUserActive)}
+ className="custom-form-check"
+ data-testid="user-status-switch"
+ />
+ {isUserActive ? (
+ <span className="m-2 ps-2">Active</span>
+ ) : (
+ <span className="m-2 ps-2">Inactive</span>
+ )}
+ </div>
+ </Form.Group>
+ </Modal.Body>
+ <Modal.Footer>
+ <DefaultButton onClick={handleCancel} data-testid="cancel-btn">Cancel</DefaultButton>
+ <WarningModal
+ isOpen={showAddUserCancelWarning}
+ onClose={() => setShowAddUserCancelWarning(false)}
+ handleWarningDiscard={handleWarningDiscard}
+ handleWarningSave={handleWarningSave}
+ />
+ <Button
+ className="custom-btn"
+ type="submit"
+ variant="success"
+ data-testid="save-btn"
+ onClick={() => setIsFormSubmitted(true)}
+ >
+ Save
+ </Button>
+ </Modal.Footer>
+ </Form>
+ </Modal>
+ );
+}
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/RoleBasedAccessControl.tsx b/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/RoleBasedAccessControl.tsx
new file mode 100644
index 0000000000..817dea04b3
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/RoleBasedAccessControl.tsx
@@ -0,0 +1,244 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Modal } from "react-bootstrap";
+import DefaultButton from "../../components/DefaultButton";
+import { useContext, useEffect, useState } from "react";
+import AppContent from "../../context/AppContext";
+import { get, isEmpty, set, startCase } from "lodash";
+import UserGroupApi from "../../api/userGroupApi";
+import Spinner from "../../components/Spinner";
+import { ProcessedRbacDataType } from "./types";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faCheck } from "@fortawesome/free-solid-svg-icons";
+import Table from "../../components/Table";
+
+type RoleBasedAccessControlProps = {
+ isOpen: boolean;
+ onClose: () => void;
+};
+
+export default function RoleBasedAccessControl({
+ isOpen,
+ onClose,
+}: RoleBasedAccessControlProps) {
+ const { rbacData, setRbacData, permissionLabelList, setPermissionLabelList } =
+ useContext(AppContent);
+ const [loading, setLoading] = useState(false);
+
+ useEffect(() => {
+ const getUserGroupAccess = async () => {
+ setLoading(true);
+ const data = await UserGroupApi.getPermissions(
+ "PermissionInfo%2F*,authorizations%2FAuthorizationInfo%2F*"
+ );
+ setRbacData(preProcessRbacData(data));
+ setLoading(false);
+ };
+ if (isEmpty(rbacData)) {
+ getUserGroupAccess();
+ }
+ }, []);
+
+ useEffect(() => {
+ setPermissionLabelList(sortBasedOnAccess(permissionLabelList));
+ }, [rbacData]);
+
+ const columnInRbacTable = [
+ {
+ header: <div className="w-50"></div>,
+ id: "empty",
+ width: "30%",
+ cell: (info: any) => {
+ return Object.keys(get(info, "row.original", {}))?.[0];
+ },
+ },
+ ...permissionLabelList.map((permissionLabel: string) => ({
+ header: <div className="w-50">{permissionLabel}</div>,
+ id: permissionLabel,
+ cell: (info: any) => {
+ if (
+ get(
+ Object.values(get(info, "row.original")),
+ `[0][${permissionLabel}]`,
+ false
+ )
+ ) {
+ return (
+ <div className="d-flex justify-content-center w-50">
+ <FontAwesomeIcon icon={faCheck} className="make-green fs-6" />
+ </div>
+ );
+ }
+ },
+ })),
+ ];
+
+ const sortBasedOnAccess = (data: string[]) => {
+ let metaData = data.reduce((acc: any, item: string) => {
+ acc[item] = 0;
+ return acc;
+ }, {});
+ Object.values(rbacData)
+ .flat()
+ .forEach((item: any) => {
+ const innerDic: { [key: string]: string } = Object.values(
+ item
+ )?.[0] as { [key: string]: string };
+ Object.keys(innerDic).forEach((key: string) => {
+ if (innerDic[key]) {
+ metaData[key] = metaData[key] + 1;
+ }
+ });
+ });
+ return (Object.entries(metaData) as Array<[string, number]>)
+ .sort((a, b) => a[1] - b[1])
+ .map((entry) => entry[0]);
+ };
+
+ const preProcessRbacData = (data: any) => {
+ let permissioLabels: string[] = [];
+ let permissionLevelList = new Set<string>();
+ get(data, "items", []).forEach((item: any) => {
+ permissioLabels.push(get(item, "PermissionInfo.permission_label"));
+ get(item, "authorizations", []).forEach((authorization: any) => {
+ const authorizationId = get(
+ authorization,
+ "AuthorizationInfo.authorization_id",
+ ""
+ );
+ permissionLevelList.add(authorizationId.split(".")?.[0]);
+ });
+ });
+
+ setPermissionLabelList(permissioLabels);
+
+ let processedData: ProcessedRbacDataType = {};
+
+ permissionLevelList.forEach((permission: string) => {
+ set(processedData, permission, []);
+ get(data, "items", []).forEach((item: any) => {
+ const authorizations = get(item, "authorizations", []).reduce(
+ (acc: any, authorization: any) => {
+ const authorizationId = get(
+ authorization,
+ "AuthorizationInfo.authorization_id",
+ ""
+ );
+ if (authorizationId.split(".")?.[0] === permission) {
+ acc.push(
+ get(authorization, "AuthorizationInfo.authorization_name", "")
+ );
+ }
+ return acc;
+ },
+ []
+ );
+ processedData[permission].push({
+ [get(item, "PermissionInfo.permission_label")]: authorizations,
+ });
+ });
+ });
+
+ Object.keys(processedData).forEach((processedDataKey: string) => {
+ const combinedList = processedData[processedDataKey].reduce(
+ (acc: string[], obj: { [key: string]: string[] }) => {
+ const values = Object.values(obj)[0];
+ return [...new Set([...acc, ...values])];
+ },
+ []
+ );
+
+ const combinedData = combinedList.reduce(
+ (acc: any, obj: string, idx: number) => {
+ acc[obj] = combinedList[idx];
+ return acc;
+ },
+ {}
+ );
+
+ processedData[processedDataKey].forEach((element) => {
+ const role = Object.keys(element)[0];
+ const permissions = element[role];
+
+ element[role] = combinedList.reduce((obj: any, key: string) => {
+ obj[key] = permissions.includes(key);
+ return obj;
+ }, {});
+ });
+
+ processedData[processedDataKey] = [
+ { "": combinedData },
+ ...processedData[processedDataKey],
+ ];
+
+ processedData[processedDataKey] = Object.keys(
+ processedData[processedDataKey][0][""]
+ ).map((key: string) => {
+ const obj: any = {};
+ processedData[processedDataKey].slice(1).forEach((item: any) => {
+ const role = Object.keys(item)[0];
+ obj[role] = item[role][key];
+ });
+ return { [key]: obj };
+ });
+ });
+
+ return processedData;
+ };
+
+ return (
+ <Modal
+ show={isOpen}
+ onHide={onClose}
+ size="xl"
+ className="custom-modal-container"
+ data-testid="role-based-access-control-modal"
+ >
+ <Modal.Header closeButton>
+ <Modal.Title>Role Based Access Control</Modal.Title>
+ </Modal.Header>
+ {loading ? (
+ <Spinner />
+ ) : (
+ <div>
+ <Modal.Body className="scrollable">
+ {Object.keys(rbacData).map((rbacDataKey: string) => {
+ return (
+ <div key={rbacDataKey} className="p-2 mb-4">
+ <h6 key={rbacDataKey}>
+ {startCase(rbacDataKey.toLowerCase()) +
+ "-level Permissions"}
+ </h6>
+ <Table
+ columns={columnInRbacTable}
+ data={rbacData[rbacDataKey]}
+ striped={true}
+ hover={true}
+ />
+ </div>
+ );
+ })}
+ </Modal.Body>
+ <Modal.Footer className="d-flex justify-content-center">
+ <DefaultButton onClick={onClose}>CLOSE</DefaultButton>
+ </Modal.Footer>
+ </div>
+ )}
+ </Modal>
+ );
+}
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/WarningModal.tsx b/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/WarningModal.tsx
new file mode 100644
index 0000000000..9a3e1be45f
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/WarningModal.tsx
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Button, Modal } from "react-bootstrap";
+import DefaultButton from "../../components/DefaultButton";
+
+type WarningModalProps = {
+ isOpen: boolean;
+ onClose: () => void;
+ handleWarningDiscard: () => void;
+ handleWarningSave: (event: any) => void;
+};
+
+export default function WarningModal({
+ isOpen,
+ onClose,
+ handleWarningDiscard,
+ handleWarningSave,
+}: WarningModalProps) {
+ return (
+ <Modal
+ show={isOpen}
+ onHide={onClose}
+ size="lg"
+ className="custom-modal-container modal-width"
+ data-testid="warning-modal"
+ >
+ <Modal.Header>
+ <Modal.Title><h3>Warning</h3></Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <div>You have unsaved changes. Save changes or discard?</div>
+ </Modal.Body>
+ <Modal.Footer className="d-flex justify-content-end">
+ <DefaultButton onClick={onClose}>
+ Cancel
+ </DefaultButton>
+ <Button
+ className="custom-btn text-light"
+ variant="warning"
+ onClick={handleWarningDiscard}
+ >
+ Discard
+ </Button>
+ <Button
+ className="custom-btn"
+ variant="success"
+ onClick={handleWarningSave}
+ >
+ Save
+ </Button>
+ </Modal.Footer>
+ </Modal>
+ );
+}
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/constants.ts b/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/constants.ts
new file mode 100644
index 0000000000..02c9b49c07
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/constants.ts
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { PermissionLabel } from "./types";
+
+const userAccessOptions = [
+ "None",
+ "Cluster User",
+ "Cluster Administrator",
+ "Cluster Operator",
+ "Service Administrator",
+ "Service Operator",
+];
+
+const permissionLabelToName : Record<PermissionLabel, string> = {
+ "None": "NONE",
+ "Cluster User": "CLUSTER.USER",
+ "Cluster Administrator": "CLUSTER.ADMINISTRATOR",
+ "Cluster Operator": "CLUSTER.OPERATOR",
+ "Service Administrator": "SERVICE.ADMINISTRATOR",
+ "Service Operator": "SERVICE.OPERATOR",
+};
+
+export { userAccessOptions, permissionLabelToName };
\ No newline at end of file
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/index.tsx b/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/index.tsx
index e31316d9d0..19d4bb30dd 100644
--- a/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/index.tsx
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/screens/Users/index.tsx
@@ -51,6 +51,7 @@ import {
getFromLocalStorage,
parseJSONData,
} from "../../api/Utility";
+import AddUser from "./AddUser";
export default function Users() {
const [currentLoggedInUser, setCurrentLoggedInUser] = useState("");
@@ -385,6 +386,14 @@ export default function Users() {
return (
<div className="make-all-grey">
+ {showAddUserModal ? (
+ <AddUser
+ clusterName={clusterName}
+ showAddUserModal={showAddUserModal}
+ setShowAddUserModal={setShowAddUserModal}
+ successCallback={() => getUsersList()}
+ />
+ ) : null}
{showDeleteUserModal ? (
<ConfirmationModal
isOpen={showDeleteUserModal}
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/styles/custom.scss b/ambari-admin/src/main/resources/ui/ambari-admin/src/styles/custom.scss
index fcb05a5acb..d49cfc5cc9 100644
--- a/ambari-admin/src/main/resources/ui/ambari-admin/src/styles/custom.scss
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/styles/custom.scss
@@ -3397,6 +3397,13 @@ input[type="checkbox"]:checked + label:after {
padding: 0 !important;
}
+.btn-light-success {
+ background-color: #3FAE2A !important;
+ color: #D1E8D1 !important;
+ opacity: 0.6 !important;
+ pointer-events: none;
+}
+
.scrollable {
max-height: 70vh;
overflow-y: auto;
@@ -3449,4 +3456,11 @@ path {
.make-scrollable .modal-body {
max-height: 70vh !important;
overflow-y: auto !important;
+}
+
+.toast-message {
+ word-wrap: break-word !important;
+ white-space: pre-wrap !important;
+ overflow-wrap: break-word !important;
+ max-width: 300px !important;
}
\ No newline at end of file
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/tests/AddUser.test.tsx b/ambari-admin/src/main/resources/ui/ambari-admin/src/tests/AddUser.test.tsx
new file mode 100644
index 0000000000..d0c4b3daaa
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/tests/AddUser.test.tsx
@@ -0,0 +1,302 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { render, screen, fireEvent, waitFor } from "@testing-library/react";
+import AddUser from "../screens/Users/AddUser";
+import { describe, it, beforeEach, expect, vi } from "vitest";
+import "@testing-library/jest-dom/vitest";
+import UserGroupApi from "../api/userGroupApi";
+import { Router } from "react-router";
+import AppContent from "../context/AppContext";
+import { createMemoryHistory } from "history";
+import { rbacData } from "../__mocks__/mockRbacData";
+import toast from "react-hot-toast";
+import { UserDataType } from "../api/types";
+import { get } from "lodash";
+
+describe("AddUser component", () => {
+ const mockClusterName = "testCluster";
+ const mockContext = {
+ cluster: { cluster_name: mockClusterName },
+ rbacData: {},
+ setRbacData: () => vi.fn(),
+ permissionLabelList: [],
+ setPermissionLabelList: vi.fn(),
+ };
+ const mockProps = {
+ clusterName: mockClusterName,
+ showAddUserModal: true,
+ setShowAddUserModal: vi.fn(),
+ successCallback: vi.fn(),
+ };
+
+ let mockToastSuccessMessage = "";
+ let mockToastErrorMessage = "";
+
+ toast.success = (message) => {
+ mockToastSuccessMessage = message as string;
+ return "";
+ };
+
+ toast.error = (message) => {
+ mockToastErrorMessage = message as string;
+ return "";
+ };
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ mockToastSuccessMessage = "";
+ mockToastErrorMessage = "";
+ UserGroupApi.getPermissions = async () => rbacData;
+ });
+
+ const renderComponent = (props = mockProps) => {
+ render(
+ <AppContent.Provider value={mockContext}>
+ <Router history={createMemoryHistory()}>
+ <AddUser {...props} />
+ </Router>
+ </AppContent.Provider>
+ );
+ };
+
+ it("renders AddUser modal without crashing", () => {
+ renderComponent();
+ expect(screen.getByTestId("add-user-modal")).toBeInTheDocument();
+ });
+
+ it("should display required errors when input fields are empty", async () => {
+ renderComponent();
+
+ const saveButton = screen.getByTestId("save-btn");
+ fireEvent.click(saveButton);
+
+ await waitFor(async () => {
+ const errorMessages = await screen.findAllByText(/required/i);
+ expect(errorMessages).toHaveLength(3);
+ });
+ });
+
+ it("renders username input and validates input", async () => {
+ renderComponent();
+
+ const saveButton = screen.getByTestId("save-btn");
+ fireEvent.click(saveButton);
+
+ const usernameInput = screen.getByTestId("username-input");
+ fireEvent.change(usernameInput, { target: { value: "invalid&username" } });
+
+ await waitFor(() => {
+ expect(
+ screen.getByText("Must not contain special characters!")
+ ).toBeInTheDocument();
+ });
+
+ fireEvent.change(usernameInput, {
+ target: {
+ value:
+ "012345678901234567890123456789012345678901234567890123456789012345678901234567891",
+ },
+ });
+
+ await waitFor(() => {
+ expect(
+ screen.queryByText("Must not be longer than 80 characters!")
+ ).toBeInTheDocument();
+ });
+
+ fireEvent.change(usernameInput, { target: { value: "validusername" } });
+
+ await waitFor(() => {
+ expect(
+ screen.queryByText("Must not be longer than 80 characters!")
+ ).not.toBeInTheDocument();
+ });
+ });
+
+ it("renders password and confirm password inputs and validates matching", async () => {
+ renderComponent();
+
+ const saveButton = screen.getByTestId("save-btn");
+ fireEvent.click(saveButton);
+
+ const passwordInput = screen.getByTestId("password-input");
+ const confirmPasswordInput = screen.getByTestId("confirm-password-input");
+
+ fireEvent.change(passwordInput, { target: { value: "password" } });
+ fireEvent.change(confirmPasswordInput, {
+ target: { value: "differentpassword" },
+ });
+
+ await waitFor(() => {
+ expect(screen.getByText("Password must match!")).toBeInTheDocument();
+ });
+
+ fireEvent.change(confirmPasswordInput, { target: { value: "password" } });
+
+ await waitFor(() => {
+ expect(
+ screen.queryByText("Password must match!")
+ ).not.toBeInTheDocument();
+ });
+ });
+
+ it("renders user access dropdown and selects an option", () => {
+ renderComponent();
+
+ const userAccessSelect = screen.getByTestId(
+ "user-access-dropdown"
+ ) as HTMLSelectElement;
+ fireEvent.change(userAccessSelect, { target: { value: "Cluster User" } });
+
+ expect(userAccessSelect.value).toBe("Cluster User");
+ });
+
+ it("renders Ambari Admin switch and toggles it", () => {
+ renderComponent();
+
+ const ambariAdminSwitch = screen.getByTestId("ambari-admin-switch");
+ fireEvent.click(ambariAdminSwitch);
+
+ expect(ambariAdminSwitch).toBeChecked();
+ });
+
+ it("renders User Status switch and toggles it", () => {
+ renderComponent();
+
+ const userStatusSwitch = screen.getByTestId("user-status-switch");
+ fireEvent.click(userStatusSwitch);
+
+ expect(userStatusSwitch).not.toBeChecked();
+ });
+
+ it("calls handleSave on form submit with valid data", async () => {
+ UserGroupApi.addUser = async (userData: UserDataType) => {
+ toast.success(
+ `Created user ${get(userData, "Users/user_name", "")}`
+ );
+ return { status: 200 };
+ };
+
+ renderComponent();
+
+ const usernameInput = screen.getByTestId("username-input");
+ const passwordInput = screen.getByTestId("password-input");
+ const confirmPasswordInput = screen.getByTestId("confirm-password-input");
+
+ fireEvent.change(usernameInput, { target: { value: "validusername" } });
+ fireEvent.change(passwordInput, { target: { value: "password" } });
+ fireEvent.change(confirmPasswordInput, { target: { value: "password" } });
+
+ const saveButton = screen.getByTestId("save-btn");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(mockToastSuccessMessage).toBe(
+ "Created user validusername"
+ );
+ });
+ });
+
+ it("calls handleSave on form submit but API got failed", async () => {
+ UserGroupApi.addUser = async (userName: UserDataType) => {
+ toast.error(
+ `Error while adding user ${get(userName, "Users/user_name", "")}`
+ );
+ return { status: 400 };
+ };
+
+ renderComponent();
+
+ const usernameInput = screen.getByTestId("username-input");
+ const passwordInput = screen.getByTestId("password-input");
+ const confirmPasswordInput = screen.getByTestId("confirm-password-input");
+
+ fireEvent.change(usernameInput, { target: { value: "validusername" } });
+ fireEvent.change(passwordInput, { target: { value: "password" } });
+ fireEvent.change(confirmPasswordInput, { target: { value: "password" } });
+
+ const saveButton = screen.getByTestId("save-btn");
+ fireEvent.click(saveButton);
+
+ await waitFor(() => {
+ expect(mockToastErrorMessage).toBe(
+ "Error while adding user validusername"
+ );
+ });
+ });
+
+ it("calls handleCancel and shows warning modal if form is dirty", () => {
+ renderComponent();
+
+ const usernameInput = screen.getByTestId("username-input");
+ fireEvent.change(usernameInput, { target: { value: "validusername" } });
+
+ const cancelButton = screen.getByTestId("cancel-btn");
+ fireEvent.click(cancelButton);
+
+ expect(screen.getByTestId("warning-modal")).toBeInTheDocument();
+ });
+
+ it("renders ErrorOverlay for username tooltip", async () => {
+ renderComponent();
+
+ const usernameTooltipIcon = screen.getByTestId("username-tooltip-icon");
+ fireEvent.click(usernameTooltipIcon);
+
+ await waitFor(() => {
+ expect(screen.getByText(/are not allowed/i)).toBeInTheDocument();
+ });
+ });
+
+ it("renders RoleBasedAccessControl modal", () => {
+ renderComponent();
+
+ const roleAccessIcon = screen.getByTestId("user-access-help-icon");
+ fireEvent.click(roleAccessIcon);
+
+ expect(screen.getByText("Role Based Access Control")).toBeInTheDocument();
+ });
+
+ it("renders ErrorOverlay for Ambari Admin tooltip", () => {
+ renderComponent();
+
+ const ambariAdminTooltipIcon = screen.getByTestId(
+ "ambari-admin-tooltip-icon"
+ );
+ fireEvent.click(ambariAdminTooltipIcon);
+
+ expect(
+ screen.getByText(/can create new clusters and other Ambari Admin Users/i)
+ ).toBeInTheDocument();
+ });
+
+ it("renders ErrorOverlay for User Status tooltip", () => {
+ renderComponent();
+
+ const userStatusTooltipIcon = screen.getByTestId(
+ "user-status-tooltip-icon"
+ );
+ fireEvent.click(userStatusTooltipIcon);
+
+ expect(
+ screen.getByText(
+ /Active Users can log in to Ambari. Inactive Users cannot/i
+ )
+ ).toBeInTheDocument();
+ });
+});
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/src/tests/ListUsersGroups.test.tsx b/ambari-admin/src/main/resources/ui/ambari-admin/src/tests/ListUsersGroups.test.tsx
new file mode 100644
index 0000000000..2c6f4f294e
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/tests/ListUsersGroups.test.tsx
@@ -0,0 +1,441 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {
+ fireEvent,
+ render,
+ screen,
+ waitFor,
+ within,
+ } from "@testing-library/react";
+ import Users from "../screens/Users";
+ import { describe, it, beforeEach, expect, vi } from "vitest";
+ import "@testing-library/jest-dom/vitest";
+ import { Router } from "react-router";
+ import AppContent from "../context/AppContext";
+ import { createMemoryHistory } from "history";
+ import UserGroupApi from "../api/userGroupApi";
+ import { usersList, paginatedUsersList } from "../__mocks__/mockUsersList";
+ import { groupsList, paginatedGroupsList } from "../__mocks__/mockGroupsList";
+ import { rbacData } from "../__mocks__/mockRbacData";
+ import PrivilegeApi from "../api/privilegeApi";
+ import toast from "react-hot-toast";
+ import { get } from "lodash";
+
+ describe("Users and Groups List component", () => {
+ const mockClusterName = "testCluster";
+ const mockContext = {
+ cluster: { cluster_name: mockClusterName },
+ setSelectedOption: () => "Users",
+ rbacData: {},
+ setRbacData: vi.fn(),
+ permissionLabelList: [],
+ setPermissionLabelList: vi.fn(),
+ };
+
+ let mockToastSuccessMessage = "";
+
+ toast.success = (message) => {
+ mockToastSuccessMessage = message as string;
+ return "";
+ };
+
+ beforeEach(async () => {
+ vi.clearAllMocks();
+ mockToastSuccessMessage = "";
+ UserGroupApi.usersList = async () => usersList;
+ UserGroupApi.groupsList = async () => groupsList;
+ UserGroupApi.getPermissions = async () => rbacData;
+ UserGroupApi.userNames = async () => ({ items: [] });
+ });
+
+ const renderUserComponent = () => {
+ render(
+ <AppContent.Provider value={mockContext}>
+ <Router history={createMemoryHistory()}>
+ <Users />
+ </Router>
+ </AppContent.Provider>
+ );
+ };
+
+ it("renders user component without crashing", async () => {
+ renderUserComponent();
+ });
+
+ //Users Test Cases
+
+ it("renders users page without crashing", async () => {
+ renderUserComponent();
+
+ expect(screen.getByTestId("users-tab")).toBeInTheDocument();
+ expect(screen.getByTestId("users-tab")).toHaveClass("active");
+ });
+
+ it("renders appropriate message if users list is empty", async () => {
+ const mockEmptyUsersList = { href: "http://example.com", items: [] };
+ UserGroupApi.usersList = async () => mockEmptyUsersList;
+
+ renderUserComponent();
+
+ await waitFor(() => {
+ expect(screen.getByTestId("empty-user-list")).toBeInTheDocument();
+ });
+ });
+
+ it("renders correct number of items in users list", async () => {
+ renderUserComponent();
+
+ await waitFor(() => {
+ screen.getByText(/dsasd/i);
+ });
+
+ const listContainer = screen.getByTestId("users-list-container");
+ const listItems = within(listContainer).getAllByRole("listitem");
+
+ expect(listItems).toHaveLength(usersList.items.length);
+ });
+
+ it("renders users list data for a specific item correctly", async () => {
+ renderUserComponent();
+
+ await waitFor(() => {
+ screen.getByText(/dsasd/i);
+ });
+
+ const listContainer = screen.getByTestId("users-list-container");
+ const allRows = within(listContainer).getAllByRole("listitem");
+ const specificRow = allRows.find((row) => within(row).queryByText("dsasd"));
+
+ if (!specificRow) {
+ throw new Error("No row with the specified text found");
+ }
+
+ expect(
+ within(specificRow).getByText(/Cluster Administrator/i)
+ ).toBeInTheDocument();
+ expect(within(specificRow).getByText(/Active/i)).toBeInTheDocument();
+ expect(within(specificRow).getByText(/Local/i)).toBeInTheDocument();
+ expect(within(specificRow).getByText(/gdgdeg/i)).toBeInTheDocument();
+ expect(within(specificRow).getByText(/group1/i)).toBeInTheDocument();
+ });
+
+ it("renders loading spinner when users list data is being fetched", async () => {
+ renderUserComponent();
+
+ const spinner = screen.getByTestId("admin-spinner");
+ expect(spinner).toBeInTheDocument();
+ });
+
+ it("renders pagination for users list page when items are more than 10", async () => {
+ UserGroupApi.usersList = async () => paginatedUsersList;
+
+ renderUserComponent();
+
+ await waitFor(() => screen.getByText(/dsasd/i));
+
+ const pagination = screen.getByTestId("pagination");
+ expect(pagination).toBeInTheDocument();
+ });
+
+ it("checks if AddUser Form is coming on clicking AddUser button", async () => {
+ renderUserComponent();
+
+ const addUserBtn = screen.getByTestId("add-users-btn");
+ expect(addUserBtn).toBeInTheDocument();
+
+ fireEvent.click(addUserBtn);
+
+ await waitFor(() => {
+ screen.getByTestId("add-user-modal");
+ });
+ });
+
+ it("renders delete user confirmation modal on clicking delete button", async () => {
+ renderUserComponent();
+
+ await waitFor(() => {
+ screen.getByText(/dsasd/i);
+ });
+
+ const deleteUserBtn = screen.getByTestId("delete-user-dsasd-btn");
+ expect(deleteUserBtn).toBeInTheDocument();
+
+ fireEvent.click(deleteUserBtn);
+
+ await waitFor(() => {
+ screen.getByTestId("confirmation-modal");
+ });
+ });
+
+ it("renders search filters for users list page", async () => {
+ renderUserComponent();
+
+ const searchFilterBtn = screen.getByTestId("filter-users-btn");
+ expect(searchFilterBtn).toBeInTheDocument();
+
+ fireEvent.click(searchFilterBtn);
+
+ await waitFor(() => {
+ screen.getByTestId("search-filters");
+ });
+ });
+
+ it("deletes a user", async () => {
+ UserGroupApi.userData = async () => {};
+ UserGroupApi.removeUser = async (userName: string) => {
+ toast.success(`${userName} deleted successfully.`);
+ return { status: 200 };
+ };
+ PrivilegeApi.removeViewPrivileges = async () => {
+ return { status: 200 };
+ };
+ PrivilegeApi.removeClusterPrivileges = async () => {
+ return { status: 200 };
+ };
+
+ renderUserComponent();
+
+ await waitFor(() => {
+ screen.getByText(/dsasd/i);
+ });
+
+ const deleteUserBtn = screen.getByTestId("delete-user-dsasd-btn");
+ expect(deleteUserBtn).toBeInTheDocument();
+
+ fireEvent.click(deleteUserBtn);
+
+ await waitFor(() => {
+ screen.getByTestId("confirmation-modal");
+ screen.getByText(/Are you sure you want to delete user "dsasd"/i);
+ });
+
+ const confirmButton = screen.getByTestId("confirm-ok-btn");
+ fireEvent.click(confirmButton);
+
+ await waitFor(() => {
+ expect(get(mockToastSuccessMessage, "props.children", []).join("")).toBe(
+ "dsasd deleted successfully."
+ );
+ });
+ });
+
+ //Groups Test Cases
+
+ it("renders groups page without crashing", async () => {
+ renderUserComponent();
+
+ const groupsTab = screen.getByTestId("groups-tab");
+ expect(groupsTab).toBeInTheDocument();
+
+ fireEvent.click(groupsTab);
+
+ await waitFor(() => {
+ expect(groupsTab).toHaveClass("active");
+ });
+ });
+
+ it("renders appropriate message if groups list is empty", async () => {
+ const mockEmptyGroupsList = { href: "http://example.com", items: [] };
+ UserGroupApi.groupsList = async () => mockEmptyGroupsList;
+
+ renderUserComponent();
+
+ const groupsTab = screen.getByTestId("groups-tab");
+ expect(groupsTab).toBeInTheDocument();
+
+ fireEvent.click(groupsTab);
+
+ await waitFor(() => {
+ expect(screen.getByTestId("empty-group-list")).toBeInTheDocument();
+ });
+ });
+
+ it("renders correct number of items in groups list", async () => {
+ renderUserComponent();
+
+ const groupsTab = screen.getByTestId("groups-tab");
+ expect(groupsTab).toBeInTheDocument();
+
+ fireEvent.click(groupsTab);
+
+ await waitFor(() => {
+ screen.getByText(/group5/i);
+ });
+
+ const listContainer = screen.getByTestId("groups-list-container");
+ const listItems = within(listContainer).getAllByRole("listitem");
+
+ expect(listItems).toHaveLength(groupsList.items.length);
+ });
+
+ it("renders groups list data for a specific item correctly", async () => {
+ renderUserComponent();
+
+ const groupsTab = screen.getByTestId("groups-tab");
+ expect(groupsTab).toBeInTheDocument();
+
+ fireEvent.click(groupsTab);
+
+ await waitFor(() => {
+ screen.getByText(/group5/i);
+ });
+
+ const listContainer = screen.getByTestId("groups-list-container");
+ const allRows = within(listContainer).getAllByRole("listitem");
+ const specificRow = allRows.find((row) =>
+ within(row).queryByText("group5")
+ );
+
+ if (!specificRow) {
+ throw new Error("No row with the specified text found");
+ }
+
+ expect(within(specificRow).getByText(/Local/i)).toBeInTheDocument();
+ expect(within(specificRow).getByText(/0 members/i)).toBeInTheDocument();
+ });
+
+ it("renders loading spinner when groups list data is being fetched", async () => {
+ renderUserComponent();
+
+ const groupsTab = screen.getByTestId("groups-tab");
+ expect(groupsTab).toBeInTheDocument();
+
+ fireEvent.click(groupsTab);
+
+ const spinner = screen.getByTestId("admin-spinner");
+ expect(spinner).toBeInTheDocument();
+ });
+
+ it("renders pagination for groups list page when items are more than 10", async () => {
+ UserGroupApi.groupsList = async () => paginatedGroupsList;
+
+ renderUserComponent();
+
+ const groupsTab = screen.getByTestId("groups-tab");
+ expect(groupsTab).toBeInTheDocument();
+
+ fireEvent.click(groupsTab);
+
+ await waitFor(() => screen.getByText(/group5/i));
+
+ const pagination = screen.getByTestId("pagination");
+ expect(pagination).toBeInTheDocument();
+ });
+
+ it("checks if AddGroup Form is coming on clicking AddGroup button", async () => {
+ renderUserComponent();
+
+ const groupsTab = screen.getByTestId("groups-tab");
+ expect(groupsTab).toBeInTheDocument();
+
+ fireEvent.click(groupsTab);
+
+ const addGroupBtn = screen.getByTestId("add-groups-btn");
+ expect(addGroupBtn).toBeInTheDocument();
+
+ fireEvent.click(addGroupBtn);
+
+ await waitFor(() => {
+ screen.getByTestId("add-group-modal");
+ });
+ });
+
+ it("renders delete group confirmation modal on clicking delete button", async () => {
+ renderUserComponent();
+
+ const groupsTab = screen.getByTestId("groups-tab");
+ expect(groupsTab).toBeInTheDocument();
+
+ fireEvent.click(groupsTab);
+
+ await waitFor(() => {
+ screen.getByText(/group5/i);
+ });
+
+ const deleteGroupBtn = screen.getByTestId("delete-group-group5-btn");
+ expect(deleteGroupBtn).toBeInTheDocument();
+
+ fireEvent.click(deleteGroupBtn);
+
+ await waitFor(() => {
+ screen.getByTestId("confirmation-modal");
+ });
+ });
+
+ it("renders search filters for groups list page", async () => {
+ renderUserComponent();
+
+ const groupsTab = screen.getByTestId("groups-tab");
+ expect(groupsTab).toBeInTheDocument();
+
+ fireEvent.click(groupsTab);
+
+ const searchFilterBtn = screen.getByTestId("filter-groups-btn");
+ expect(searchFilterBtn).toBeInTheDocument();
+
+ fireEvent.click(searchFilterBtn);
+
+ await waitFor(() => {
+ screen.getByTestId("search-filters");
+ });
+ });
+
+ it("deletes a group", async () => {
+ UserGroupApi.groupData = async () => {};
+ UserGroupApi.removeGroup = async (groupName: string) => {
+ toast.success(`${groupName} deleted successfully.`);
+ return { status: 200 };
+ };
+ PrivilegeApi.removeViewPrivileges = async () => {
+ return { status: 200 };
+ };
+ PrivilegeApi.removeClusterPrivileges = async () => {
+ return { status: 200 };
+ };
+
+ renderUserComponent();
+
+ const groupsTab = screen.getByTestId("groups-tab");
+ expect(groupsTab).toBeInTheDocument();
+
+ fireEvent.click(groupsTab);
+
+ await waitFor(() => {
+ screen.getByText(/group5/i);
+ });
+
+ const deleteGroupBtn = screen.getByTestId("delete-group-group5-btn");
+ expect(deleteGroupBtn).toBeInTheDocument();
+
+ fireEvent.click(deleteGroupBtn);
+
+ await waitFor(() => {
+ screen.getByTestId("confirmation-modal");
+ });
+
+ const confirmButton = screen.getByTestId("confirm-ok-btn");
+ fireEvent.click(confirmButton);
+
+ await waitFor(() => {
+ expect(get(mockToastSuccessMessage, "props.children", []).join("")).toBe(
+ "group5 deleted successfully."
+ );
+ });
+ });
+ });
+
\ No newline at end of file
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/vitest.config.ts b/ambari-admin/src/main/resources/ui/ambari-admin/vitest.config.ts
new file mode 100644
index 0000000000..da92ab40b2
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/vitest.config.ts
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { defineConfig } from "vitest/config";
+
+export default defineConfig({
+ test: {
+ environment: "jsdom",
+ globals: true,
+ coverage: {
+ provider: "istanbul", // or 'v8',
+ include: ["src/**/*.ts", "src/**/*.tsx", "src/screens/*"],
+ exclude: [""],
+ },
+ },
+});
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ambari.apache.org
For additional commands, e-mail: commits-help@ambari.apache.org