diff --git a/userManagment/static/userManagment/userManagment.js b/userManagment/static/userManagment/userManagment.js
index 22b2f7f2c..f898b411e 100644
--- a/userManagment/static/userManagment/userManagment.js
+++ b/userManagment/static/userManagment/userManagment.js
@@ -1659,6 +1659,147 @@ app.controller('apiAccessCTRL', function ($scope, $http) {
});
/* Java script code for api access */
+/* Java script code for api users list */
+app.controller('apiUsersCTRL', function ($scope, $http) {
+ $scope.apiUsers = [];
+ $scope.filteredUsers = [];
+ $scope.searchQuery = '';
+ $scope.apiUsersLoading = true;
+
+ $scope.loadAPIUsers = function() {
+ $scope.apiUsersLoading = false;
+
+ var url = "/users/fetchAPIUsers";
+ var config = {
+ headers: {
+ 'X-CSRFToken': getCookie('csrftoken')
+ }
+ };
+
+ $http.get(url, config).then(loadAPIUsersSuccess, loadAPIUsersError);
+ };
+
+ function loadAPIUsersSuccess(response) {
+ $scope.apiUsersLoading = true;
+
+ if (response.data.status === 1) {
+ $scope.apiUsers = response.data.users;
+ $scope.filteredUsers = response.data.users;
+
+ new PNotify({
+ title: 'Success!',
+ text: 'API users loaded successfully',
+ type: 'success'
+ });
+ } else {
+ new PNotify({
+ title: 'Error!',
+ text: response.data.error_message,
+ type: 'error'
+ });
+ }
+ }
+
+ function loadAPIUsersError(response) {
+ $scope.apiUsersLoading = true;
+ new PNotify({
+ title: 'Error!',
+ text: 'Could not load API users. Please refresh the page.',
+ type: 'error'
+ });
+ }
+
+ $scope.searchUsers = function() {
+ if (!$scope.searchQuery || $scope.searchQuery.trim() === '') {
+ $scope.filteredUsers = $scope.apiUsers;
+ return;
+ }
+
+ var query = $scope.searchQuery.toLowerCase();
+ $scope.filteredUsers = $scope.apiUsers.filter(function(user) {
+ return user.userName.toLowerCase().includes(query) ||
+ user.firstName.toLowerCase().includes(query) ||
+ user.lastName.toLowerCase().includes(query) ||
+ user.email.toLowerCase().includes(query) ||
+ user.aclName.toLowerCase().includes(query);
+ });
+ };
+
+ $scope.clearSearch = function() {
+ $scope.searchQuery = '';
+ $scope.filteredUsers = $scope.apiUsers;
+ };
+
+ $scope.viewUserDetails = function(user) {
+ new PNotify({
+ title: 'User Details',
+ text: 'Username: ' + user.userName + '
' +
+ 'Full Name: ' + user.firstName + ' ' + user.lastName + '
' +
+ 'Email: ' + user.email + '
' +
+ 'ACL: ' + user.aclName + '
' +
+ 'Token Status: ' + user.tokenStatus + '
' +
+ 'State: ' + user.state,
+ type: 'info',
+ styling: 'bootstrap3',
+ delay: 10000
+ });
+ };
+
+ $scope.disableAPI = function(user) {
+ if (confirm('Are you sure you want to disable API access for ' + user.userName + '?')) {
+ $scope.apiUsersLoading = false;
+
+ var url = "/users/saveChangesAPIAccess";
+ var data = {
+ accountUsername: user.userName,
+ access: 'Disable'
+ };
+ var config = {
+ headers: {
+ 'X-CSRFToken': getCookie('csrftoken')
+ }
+ };
+
+ $http.post(url, data, config).then(disableAPISuccess, disableAPIError);
+ }
+ };
+
+ function disableAPISuccess(response) {
+ $scope.apiUsersLoading = true;
+
+ if (response.data.status === 1) {
+ // Remove user from the list
+ $scope.apiUsers = $scope.apiUsers.filter(function(u) {
+ return u.userName !== response.data.accountUsername;
+ });
+ $scope.filteredUsers = $scope.apiUsers;
+
+ new PNotify({
+ title: 'Success!',
+ text: 'API access disabled for ' + response.data.accountUsername,
+ type: 'success'
+ });
+ } else {
+ new PNotify({
+ title: 'Error!',
+ text: response.data.error_message,
+ type: 'error'
+ });
+ }
+ }
+
+ function disableAPIError(response) {
+ $scope.apiUsersLoading = true;
+ new PNotify({
+ title: 'Error!',
+ text: 'Could not disable API access. Please try again.',
+ type: 'error'
+ });
+ }
+
+ // Load API users when controller initializes
+ $scope.loadAPIUsers();
+});
/* Java script code to list table users */
diff --git a/userManagment/templates/userManagment/apiAccess.html b/userManagment/templates/userManagment/apiAccess.html
index 30f4d80b8..8dd4baac8 100644
--- a/userManagment/templates/userManagment/apiAccess.html
+++ b/userManagment/templates/userManagment/apiAccess.html
@@ -166,6 +166,220 @@
.text-muted {
color: var(--text-secondary, #8893a7);
}
+ /* Tab Navigation Styles */
+ .tab-navigation {
+ display: flex;
+ margin-bottom: 20px;
+ border-bottom: 2px solid var(--border-color, #e8e9ff);
+ }
+ .tab-button {
+ background: none;
+ border: none;
+ padding: 15px 25px;
+ font-size: 16px;
+ font-weight: 600;
+ color: var(--text-secondary, #8893a7);
+ cursor: pointer;
+ border-bottom: 3px solid transparent;
+ transition: all 0.3s ease;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+ .tab-button:hover {
+ color: var(--accent-color, #5b5fcf);
+ background: var(--bg-hover, #f8f9ff);
+ }
+ .tab-button.active {
+ color: var(--accent-color, #5b5fcf);
+ border-bottom-color: var(--accent-color, #5b5fcf);
+ background: var(--bg-hover, #f8f9ff);
+ }
+ .tab-content {
+ display: none;
+ }
+ .tab-content.active {
+ display: block;
+ }
+
+ /* Search Container Styles */
+ .search-container {
+ margin-bottom: 25px;
+ }
+ .search-box {
+ position: relative;
+ max-width: 400px;
+ }
+ .search-box i {
+ position: absolute;
+ left: 15px;
+ top: 50%;
+ transform: translateY(-50%);
+ color: var(--text-secondary, #8893a7);
+ }
+ .search-input {
+ width: 100%;
+ padding: 12px 45px 12px 45px;
+ border: 1px solid var(--border-color, #e8e9ff);
+ border-radius: 8px;
+ font-size: 16px;
+ background: var(--bg-secondary, white);
+ color: var(--text-primary, #2f3640);
+ transition: all 0.3s ease;
+ }
+ .search-input:focus {
+ border-color: var(--accent-color, #5b5fcf);
+ box-shadow: 0 0 0 3px rgba(91, 95, 207, 0.1);
+ outline: none;
+ }
+ .clear-search {
+ position: absolute;
+ right: 10px;
+ top: 50%;
+ transform: translateY(-50%);
+ background: none;
+ border: none;
+ color: var(--text-secondary, #8893a7);
+ cursor: pointer;
+ padding: 5px;
+ border-radius: 50%;
+ transition: all 0.3s ease;
+ }
+ .clear-search:hover {
+ background: var(--bg-hover, #f8f9ff);
+ color: var(--accent-color, #5b5fcf);
+ }
+ .search-results-info {
+ margin-top: 10px;
+ color: var(--text-secondary, #8893a7);
+ font-size: 14px;
+ }
+
+ /* Users Table Styles */
+ .users-table-container {
+ overflow-x: auto;
+ }
+ .users-table {
+ width: 100%;
+ border-collapse: collapse;
+ background: var(--bg-secondary, white);
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 2px 8px var(--shadow-color, rgba(0,0,0,0.08));
+ }
+ .users-table th {
+ background: var(--bg-hover, #f8f9ff);
+ color: var(--text-primary, #2f3640);
+ font-weight: 600;
+ padding: 15px 12px;
+ text-align: left;
+ border-bottom: 2px solid var(--border-color, #e8e9ff);
+ }
+ .users-table td {
+ padding: 15px 12px;
+ border-bottom: 1px solid var(--border-color, #e8e9ff);
+ vertical-align: middle;
+ }
+ .users-table tbody tr:hover {
+ background: var(--bg-hover, #f8f9ff);
+ }
+
+ /* Badge Styles */
+ .acl-badge {
+ background: var(--accent-color, #5b5fcf);
+ color: white;
+ padding: 4px 8px;
+ border-radius: 4px;
+ font-size: 12px;
+ font-weight: 600;
+ }
+
+ /* Token Status Styles */
+ .token-status {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 14px;
+ font-weight: 500;
+ }
+ .token-valid {
+ color: var(--success-text, #10b981);
+ }
+ .token-warning {
+ color: var(--warning-text, #f59e0b);
+ }
+ .token-error {
+ color: var(--danger-text, #ef4444);
+ }
+ .token-status i {
+ font-size: 8px;
+ }
+
+ /* User State Styles */
+ .user-state {
+ padding: 4px 8px;
+ border-radius: 4px;
+ font-size: 12px;
+ font-weight: 600;
+ text-transform: uppercase;
+ }
+ .state-active {
+ background: var(--success-bg, #f0fdf4);
+ color: var(--success-text, #166534);
+ }
+ .state-inactive {
+ background: var(--danger-bg, #fef2f2);
+ color: var(--danger-text, #991b1b);
+ }
+
+ /* Action Buttons */
+ .action-buttons {
+ display: flex;
+ gap: 8px;
+ }
+ .btn-action {
+ background: none;
+ border: 1px solid var(--border-color, #e8e9ff);
+ padding: 6px 10px;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ color: var(--text-secondary, #8893a7);
+ }
+ .btn-action:hover {
+ background: var(--bg-hover, #f8f9ff);
+ border-color: var(--accent-color, #5b5fcf);
+ color: var(--accent-color, #5b5fcf);
+ }
+ .btn-view:hover {
+ color: var(--info-text, #3b82f6);
+ border-color: var(--info-text, #3b82f6);
+ }
+ .btn-disable:hover {
+ color: var(--danger-text, #ef4444);
+ border-color: var(--danger-text, #ef4444);
+ }
+
+ /* Empty State */
+ .empty-state {
+ text-align: center;
+ padding: 60px 20px;
+ color: var(--text-secondary, #8893a7);
+ }
+ .empty-state i {
+ font-size: 48px;
+ margin-bottom: 20px;
+ color: var(--text-secondary, #8893a7);
+ }
+ .empty-state h3 {
+ margin-bottom: 10px;
+ color: var(--text-primary, #2f3640);
+ }
+ .empty-state p {
+ margin: 0;
+ line-height: 1.5;
+ }
+
@media (max-width: 768px) {
.content-card {
padding: 20px;
@@ -176,6 +390,17 @@
.section-title {
font-size: 1.1rem;
}
+ .tab-button {
+ padding: 12px 15px;
+ font-size: 14px;
+ }
+ .users-table {
+ font-size: 14px;
+ }
+ .users-table th,
+ .users-table td {
+ padding: 10px 8px;
+ }
}
@@ -185,10 +410,22 @@
+
+ | {% trans "Username" %} | +{% trans "Full Name" %} | +{% trans "Email" %} | +{% trans "ACL" %} | +{% trans "Token Status" %} | +{% trans "State" %} | +{% trans "Actions" %} | +
|---|---|---|---|---|---|---|
| + {{ user.userName }} + | +{{ user.firstName }} {{ user.lastName }} | +{{ user.email }} | ++ {{ user.aclName }} + | ++ + {{ user.tokenStatus }} + + | ++ + {{ user.state }} + + | ++ + | +
{% trans "No users currently have API access enabled. Use the Configure tab to enable API access for users." %}
+{% trans "No users match your search criteria. Try adjusting your search terms." %}
+