mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-01 01:17:13 +00:00
feat(dashboard): grants on the Permissions page and on account and character pages
A Grants tab on the Permissions page (with grants_manage: every grant in force, the history, and a form that asks whose it is, searching accounts or characters by name), and a Permission grants card on account and character pages (the account's or character's grants and history; the form with grants_manage). The form picks the kind (dashboard permission, in-game command, every permission of a category, every command up to a GM level) and searches what to grant among only what the signed-in user may grant; grant or deny, an optional expiry and a note. In-force grants have a Remove button when the user may remove them. Players see their own grants, read-only. The Permissions page (and its menu entry) now opens with permissions_manage or grants_manage; the GM level tabs still need permissions_manage. Check: as GM 9, add a grant and a deny from the Permissions page and from an account and a character page, with and without an expiry; remove one; the lists and history update (also in a second tab). As a GM 8 given grants_manage: only the Grants tab shows, and only permissions and commands GM 8 has are offered. As a player: your own account page lists your grants without a form. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -307,6 +307,16 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if is_self or can.grants_manage %}
|
||||
<div class="card mb-4">
|
||||
<div class="card-header"><h5 class="mb-0">Permission grants</h5></div>
|
||||
<div class="card-body">
|
||||
<p class="small text-body-secondary">Dashboard permissions and in-game commands given to{% if can.grants_manage %} (or taken from){% endif %} this account on top of what its GM level allows. They count on the dashboard and in game, on every character; each character can have its own too (on its page).</p>
|
||||
<div id="grantsPanel" data-account="{{ account.id }}"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if is_self or (can.api_keys_manage and can.accounts_view and manage.tools) %}
|
||||
<div class="card mb-4" id="apiKeys" data-account="{{ account.id }}" data-self="{% if is_self %}1{% endif %}" data-can-create="{% if is_self and can.api_access %}1{% endif %}">
|
||||
<div class="card-header d-flex align-items-center">
|
||||
@@ -680,4 +690,11 @@ function disconnectMailAccount() {
|
||||
<script src="/js/strikes.js"></script>
|
||||
<script src="/js/account-links.js"></script>
|
||||
<script src="/js/api-keys.js"></script>
|
||||
<script src="/js/grants.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
var panel = document.getElementById('grantsPanel');
|
||||
if (panel) Grants.mount(panel, { type: 'account', id: panel.dataset.account });
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -245,6 +245,16 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if can.grants_manage or character.is_own %}
|
||||
<div class="card mb-4">
|
||||
<div class="card-header"><h5 class="mb-0">Permission grants</h5></div>
|
||||
<div class="card-body">
|
||||
<p class="small text-body-secondary">In-game commands and permissions given to{% if can.grants_manage %} (or taken from){% endif %} this character on top of its GM level, while it is logged in. The account's own grants count too.</p>
|
||||
<div id="grantsPanel" data-character="{{ character.id }}"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="card mb-4" id="relatedCard" data-kind="character" data-id="{{ character.id }}"><div class="card-body text-body-secondary">Loading related data…</div></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -760,4 +770,11 @@ function rescueCharacter() {
|
||||
<script src="/js/character-missions.js"></script>
|
||||
<script src="/js/related.js"></script>
|
||||
<script src="/js/mail-view.js"></script>
|
||||
<script src="/js/grants.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
var panel = document.getElementById('grantsPanel');
|
||||
if (panel) Grants.mount(panel, { type: 'character', id: panel.dataset.character });
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% set adminPages = ["settings", "settings_history", "permissions", "tasks", "play_keys", "backups", "webhooks", "client_assets", "ugc"] %}
|
||||
{% if can.settings or can.permissions_manage or can.tasks_view or can.play_keys_manage or can.backups or can.webhooks or can.client_files or can.ugc_manage %}
|
||||
{% if can.settings or can.permissions_manage or can.grants_manage or can.tasks_view or can.play_keys_manage or can.backups or can.webhooks or can.client_files or can.ugc_manage %}
|
||||
<div class="nav-group">
|
||||
<button class="nav-group-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#nav-admin" aria-expanded="{% if current_page in adminPages %}true{% else %}false{% endif %}" aria-controls="nav-admin">
|
||||
Server Admin<span class="nav-group-dot" title="Something in here needs attention"></span>
|
||||
@@ -128,7 +128,7 @@
|
||||
<div class="collapse{% if current_page in adminPages %} show{% endif %}" id="nav-admin">
|
||||
<div class="list-group list-group-flush">
|
||||
{% if can.settings %}<a href="/settings" class="list-group-item list-group-item-action{% if current_page == "settings" or current_page == "settings_history" %} active{% endif %}">Settings</a>{% endif %}
|
||||
{% if can.permissions_manage %}<a href="/permissions" class="list-group-item list-group-item-action{% if current_page == "permissions" %} active{% endif %}">Permissions</a>{% endif %}
|
||||
{% if can.permissions_manage or can.grants_manage %}<a href="/permissions" class="list-group-item list-group-item-action{% if current_page == "permissions" %} active{% endif %}">Permissions</a>{% endif %}
|
||||
{% if can.tasks_view %}<a href="/tasks" class="list-group-item list-group-item-action{% if current_page == "tasks" %} active{% endif %}">Scheduled Tasks</a>{% endif %}
|
||||
{% if can.play_keys_manage %}<a href="/play_keys" class="list-group-item list-group-item-action{% if current_page == "play_keys" %} active{% endif %}">Play Keys</a>{% endif %}
|
||||
{% if can.backups %}<a href="/backups" class="list-group-item list-group-item-action{% if current_page == "backups" %} active{% endif %}">Backups</a>{% endif %}
|
||||
|
||||
@@ -23,16 +23,36 @@
|
||||
<div class="mb-3">
|
||||
<h2 class="mb-1">Permissions</h2>
|
||||
<p class="text-body-secondary mb-0">What each GM level may do on the dashboard and in the game. Click a level to make it the lowest one allowed; every level
|
||||
above it is allowed too. Changes apply straight away, no restart needed. GM 9 can always do everything on the dashboard.</p>
|
||||
above it is allowed too. Changes apply straight away, no restart needed. GM 9 can always do everything on the dashboard.
|
||||
<strong>Grants</strong> give (or take away) a permission or command for one account or character.</p>
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-tabs mb-3" id="permTabs" role="tablist">
|
||||
{% if can.permissions_manage %}
|
||||
<li class="nav-item" role="presentation"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tabDashboard" data-hash="dashboard" type="button" role="tab">Dashboard <span class="badge rounded-pill text-bg-secondary" id="permCount"></span></button></li>
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tabCommands" data-hash="commands" type="button" role="tab">In-game commands <span class="badge rounded-pill text-bg-secondary" id="commandCount"></span></button></li>
|
||||
{% endif %}
|
||||
{% if can.grants_manage %}
|
||||
<li class="nav-item" role="presentation"><button class="nav-link{% if not can.permissions_manage %} active{% endif %}" data-bs-toggle="tab" data-bs-target="#tabGrants" data-hash="grants" type="button" role="tab">Grants</button></li>
|
||||
{% endif %}
|
||||
{% if can.permissions_manage %}
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tabConfig" data-hash="config" type="button" role="tab">Config files</button></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
{% if can.grants_manage %}
|
||||
<div class="tab-pane fade{% if not can.permissions_manage %} show active{% endif %}" id="tabGrants" role="tabpanel">
|
||||
<details class="about-text mb-2"><summary>How grants work</summary><p class="mb-0">A grant gives one account or character a dashboard permission, an
|
||||
in-game command, every permission of a category or every command up to a GM level, on top of what its GM level allows. A deny takes one away
|
||||
even when the GM level allows it (never from GM 9). A deny beats a grant. Account grants count on the dashboard and in game; character grants
|
||||
count in game while that character is logged in. A grant of a permission also covers the commands that follow it. Online players get changes
|
||||
at once. You can only grant what you have yourself, on accounts you may manage; <code>settings</code>, <code>permissions_manage</code>,
|
||||
commands with a fixed level and commands that never go below a GM level (<code>/execute</code>) can't be granted.</p></details>
|
||||
<div class="card"><div class="card-body" id="grantsPanel"></div></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if can.permissions_manage %}
|
||||
<div class="tab-pane fade show active" id="tabDashboard" role="tabpanel">
|
||||
<div class="perm-toolbar d-flex flex-wrap align-items-center gap-2 mb-3">
|
||||
<input type="search" class="form-control form-control-sm" id="permFilter" placeholder="Search permissions" aria-label="Search permissions">
|
||||
@@ -98,12 +118,29 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="/js/grants.js"></script>
|
||||
<script>
|
||||
(function () {
|
||||
var grantsPanel = document.getElementById('grantsPanel');
|
||||
if (grantsPanel) Grants.mount(grantsPanel, null);
|
||||
|
||||
// The open tab is in the address (#commands, #grants, #config), so it survives a reload and can be linked to
|
||||
var tabs = document.querySelectorAll('#permTabs [data-hash]');
|
||||
Array.prototype.forEach.call(tabs, function (tab) {
|
||||
if (window.location.hash === '#' + tab.dataset.hash) bootstrap.Tab.getOrCreateInstance(tab).show();
|
||||
tab.addEventListener('shown.bs.tab', function () { history.replaceState(null, '', '#' + tab.dataset.hash); });
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
(function () {
|
||||
// The GM level tabs: only with permissions_manage
|
||||
if (!document.getElementById('permRows')) return;
|
||||
var permissions = [], commands = [];
|
||||
var SOURCES = { 'default': ['Default', 'secondary'], web: ['This page', 'primary'], file: ['Config file', 'info'], env: ['Environment', 'info'], fixed: ['Fixed', 'dark'], permission: ['Permission', 'success'] };
|
||||
var filter = document.getElementById('commandFilter'), showClient = document.getElementById('showClient'), commandChanged = document.getElementById('commandChanged');
|
||||
@@ -285,13 +322,6 @@
|
||||
permCategory.addEventListener('change', renderPermissions);
|
||||
permChanged.addEventListener('change', renderPermissions);
|
||||
|
||||
// The open tab is in the address (#commands, #config), so it survives a reload and can be linked to
|
||||
var tabs = document.querySelectorAll('#permTabs [data-hash]');
|
||||
Array.prototype.forEach.call(tabs, function (tab) {
|
||||
if (window.location.hash === '#' + tab.dataset.hash) bootstrap.Tab.getOrCreateInstance(tab).show();
|
||||
tab.addEventListener('shown.bs.tab', function () { history.replaceState(null, '', '#' + tab.dataset.hash); });
|
||||
});
|
||||
|
||||
if (window.Live) Live.on('permissions', Live.throttle(load, 500));
|
||||
load();
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user