mirror of
				https://github.com/dani-garcia/vaultwarden.git
				synced 2025-11-04 12:18:20 +02:00 
			
		
		
		
	Redesign of the admin interface.
Main changes: - Splitted up settings and users into two separate pages. - Added verified shield when the e-mail address has been verified. - Added the amount of personal items in the database to the users overview. - Added Organizations and Diagnostics pages. - Shows if DNS resolving works. - Shows if there is a posible time drift. - Shows current versions of server and web-vault. - Optimized logo-gray.png using optipng Items which can be added later: - Amount of cipher items accessible for a user, not only his personal items. - Amount of users per Org - Version update check in the diagnostics overview. - Copy/Pasteable runtime config which has sensitive data changed or removed for support questions either on the forum or github issues. - Option to delete Orgs and all its passwords (when there are no members anymore). - Etc....
This commit is contained in:
		
							
								
								
									
										134
									
								
								src/static/templates/admin/users.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								src/static/templates/admin/users.hbs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
			
		||||
<main class="container">
 | 
			
		||||
    <div id="users-block" class="my-3 p-3 bg-white rounded shadow">
 | 
			
		||||
        <h6 class="border-bottom pb-2 mb-0">Registered Users</h6>
 | 
			
		||||
 | 
			
		||||
        <div id="users-list">
 | 
			
		||||
            {{#each users}}
 | 
			
		||||
            <div class="media pt-3">
 | 
			
		||||
                <img class="mr-2 rounded identicon" data-src="{{Email}}">
 | 
			
		||||
                <div class="media-body pb-3 mb-0 small border-bottom">
 | 
			
		||||
                    <div class="row justify-content-between">
 | 
			
		||||
                        <div class="col">
 | 
			
		||||
                            <strong>{{Name}}</strong>
 | 
			
		||||
                            {{#if TwoFactorEnabled}}
 | 
			
		||||
                            <span class="badge badge-success ml-2">2FA</span>
 | 
			
		||||
                            {{/if}}
 | 
			
		||||
                            {{#case _Status 1}}
 | 
			
		||||
                            <span class="badge badge-warning ml-2">Invited</span>
 | 
			
		||||
                            {{/case}}
 | 
			
		||||
                            <span class="d-block">{{Email}}
 | 
			
		||||
                                {{#if EmailVerified}}
 | 
			
		||||
                                <span class="badge badge-success ml-2">Verified</span>
 | 
			
		||||
                                {{/if}}
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col">
 | 
			
		||||
                            <strong> Personal Items: </strong>
 | 
			
		||||
                            <span class="d-block">
 | 
			
		||||
                                {{cipher_count}}
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-4">
 | 
			
		||||
                            <strong> Organizations: </strong>
 | 
			
		||||
                            <span class="d-block">
 | 
			
		||||
                                {{#each Organizations}}
 | 
			
		||||
                                <span class="badge badge-primary" data-orgtype="{{Type}}">{{Name}}</span>
 | 
			
		||||
                                {{/each}}
 | 
			
		||||
                            </span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col" style="font-size: 90%; text-align: right; padding-right: 15px">
 | 
			
		||||
                            {{#if TwoFactorEnabled}}
 | 
			
		||||
                            <a class="mr-2" href="#" onclick='remove2fa({{jsesc Id}})'>Remove all 2FA</a>
 | 
			
		||||
                            {{/if}}
 | 
			
		||||
 | 
			
		||||
                            <a class="mr-2" href="#" onclick='deauthUser({{jsesc Id}})'>Deauthorize sessions</a>
 | 
			
		||||
                            <a class="mr-2" href="#" onclick='deleteUser({{jsesc Id}}, {{jsesc Email}})'>Delete User</a>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            {{/each}}
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class="mt-3">
 | 
			
		||||
            <button type="button" class="btn btn-sm btn-link" onclick="updateRevisions();"
 | 
			
		||||
                title="Force all clients to fetch new data next time they connect. Useful after restoring a backup to remove any stale data.">
 | 
			
		||||
                Force clients to resync
 | 
			
		||||
            </button>
 | 
			
		||||
 | 
			
		||||
            <button type="button" class="btn btn-sm btn-primary float-right" onclick="reload();">Reload users</button>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div id="invite-form-block" class="align-items-center p-3 mb-3 text-white-50 bg-secondary rounded shadow">
 | 
			
		||||
        <div>
 | 
			
		||||
            <h6 class="mb-0 text-white">Invite User</h6>
 | 
			
		||||
            <small>Email:</small>
 | 
			
		||||
 | 
			
		||||
            <form class="form-inline" id="invite-form" onsubmit="inviteUser(); return false;">
 | 
			
		||||
                <input type="email" class="form-control w-50 mr-2" id="email-invite" placeholder="Enter email">
 | 
			
		||||
                <button type="submit" class="btn btn-primary">Invite</button>
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</main>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
    function deleteUser(id, mail) {
 | 
			
		||||
        var input_mail = prompt("To delete user '" + mail + "', please type the email below")
 | 
			
		||||
        if (input_mail != null) {
 | 
			
		||||
            if (input_mail == mail) {
 | 
			
		||||
                _post("{{urlpath}}/admin/users/" + id + "/delete",
 | 
			
		||||
                    "User deleted correctly",
 | 
			
		||||
                    "Error deleting user");
 | 
			
		||||
            } else {
 | 
			
		||||
                alert("Wrong email, please try again")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    function remove2fa(id) {
 | 
			
		||||
        _post("{{urlpath}}/admin/users/" + id + "/remove-2fa",
 | 
			
		||||
            "2FA removed correctly",
 | 
			
		||||
            "Error removing 2FA");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    function deauthUser(id) {
 | 
			
		||||
        _post("{{urlpath}}/admin/users/" + id + "/deauth",
 | 
			
		||||
            "Sessions deauthorized correctly",
 | 
			
		||||
            "Error deauthorizing sessions");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    function updateRevisions() {
 | 
			
		||||
        _post("{{urlpath}}/admin/users/update_revision",
 | 
			
		||||
            "Success, clients will sync next time they connect",
 | 
			
		||||
            "Error forcing clients to sync");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    function inviteUser() {
 | 
			
		||||
        inv = document.getElementById("email-invite");
 | 
			
		||||
        data = JSON.stringify({ "email": inv.value });
 | 
			
		||||
        inv.value = "";
 | 
			
		||||
        _post("{{urlpath}}/admin/invite/", "User invited correctly",
 | 
			
		||||
            "Error inviting user", data);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let OrgTypes = {
 | 
			
		||||
        "0": { "name": "Owner", "color": "orange" },
 | 
			
		||||
        "1": { "name": "Admin", "color": "blueviolet" },
 | 
			
		||||
        "2": { "name": "User", "color": "blue" },
 | 
			
		||||
        "3": { "name": "Manager", "color": "green" },
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    document.querySelectorAll("img.identicon").forEach(function (e, i) {
 | 
			
		||||
        e.src = identicon(e.dataset.src);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    document.querySelectorAll("[data-orgtype]").forEach(function (e, i) {
 | 
			
		||||
        let orgtype = OrgTypes[e.dataset.orgtype];
 | 
			
		||||
        e.style.backgroundColor = orgtype.color;
 | 
			
		||||
        e.title = orgtype.name;
 | 
			
		||||
    });
 | 
			
		||||
</script>
 | 
			
		||||
		Reference in New Issue
	
	Block a user