inou/portal/templates/edit_rbac_ru.tmpl

149 lines
7.5 KiB
Cheetah
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{{define "edit_rbac_ru"}}
<style>
.col-toggle { cursor: pointer; user-select: none; display: inline-flex; align-items: center; gap: 4px; }
</style>
<div class="page-container">
<div class="page-card" style="max-width: 780px; margin: 0 auto;">
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 32px;">
<div>
<h1>Редактировать права</h1>
<p class="intro">Доступ {{.GranteeName}} к {{.TargetDossier.Name}}</p>
</div>
<a href="/dossier/{{.TargetDossier.DossierID}}" class="btn btn-secondary btn-small">Назад</a>
</div>
{{if .Error}}<div class="error">{{.Error}}</div>{{end}}
{{if .Success}}<div class="success">{{.Success}}</div>{{end}}
<form action="/dossier/{{.TargetDossier.DossierID}}/rbac/{{.GranteeID}}" method="POST">
<input type="hidden" name="action" value="update">
<input type="hidden" name="role" id="roleHidden" value="{{.SelectedRole}}">
<div style="margin-bottom: 24px;">
<label style="font-weight: 600; margin-bottom: 8px; display: block;">Роль</label>
<select id="roleSelect" style="width: 100%;">
<option value="Custom"{{if eq .SelectedRole "Custom"}} selected{{end}}>Пользовательская</option>
{{range .Roles}}
<option value="{{.Name}}" data-grants='{{.GrantsJSON}}'{{if eq $.SelectedRole .Name}} selected{{end}}>{{.Name}} &mdash; {{.Description}}</option>
{{end}}
</select>
</div>
<table style="width: 100%; border-collapse: collapse; font-size: 0.9rem; table-layout: fixed;">
<colgroup>
<col style="width: auto;">
<col style="width: 72px;">
<col style="width: 72px;">
<col style="width: 72px;">
<col style="width: 72px;">
<col style="width: 72px;">
</colgroup>
<tr style="border-bottom: 2px solid var(--border);">
<th style="text-align: left; padding: 8px 12px;">Категория</th>
<th style="text-align: center; padding: 8px 4px;">Все</th>
<th style="text-align: center; padding: 8px 4px;"><label class="col-toggle" data-op="r"><input type="checkbox" class="col-cb" data-op="r"> Чтение</label></th>
<th style="text-align: center; padding: 8px 4px;"><label class="col-toggle" data-op="w"><input type="checkbox" class="col-cb" data-op="w"> Запись</label></th>
<th style="text-align: center; padding: 8px 4px;"><label class="col-toggle" data-op="d"><input type="checkbox" class="col-cb" data-op="d"> Удаление</label></th>
<th style="text-align: center; padding: 8px 4px;"><label class="col-toggle" data-op="m"><input type="checkbox" class="col-cb" data-op="m"> Управление</label></th>
</tr>
{{range .CategoriesRBAC}}
<tr style="border-bottom: 1px solid var(--border);" data-cat="{{.ID}}">
<td style="padding: 6px 12px; text-transform: capitalize;">{{.Name}}</td>
<td style="text-align: center; padding: 6px 4px;"><input type="checkbox" class="row-toggle"></td>
<td style="text-align: center; padding: 6px 4px;"><input type="checkbox" name="cat_{{.ID}}_r" value="1" class="perm-cb op-r" {{if .CanRead}}checked{{end}}></td>
<td style="text-align: center; padding: 6px 4px;"><input type="checkbox" name="cat_{{.ID}}_w" value="1" class="perm-cb op-w" {{if .CanWrite}}checked{{end}}></td>
<td style="text-align: center; padding: 6px 4px;"><input type="checkbox" name="cat_{{.ID}}_d" value="1" class="perm-cb op-d" {{if .CanDelete}}checked{{end}}></td>
<td style="text-align: center; padding: 6px 4px;"><input type="checkbox" name="cat_{{.ID}}_m" value="1" class="perm-cb op-m" {{if .CanManage}}checked{{end}}></td>
</tr>
{{end}}
</table>
<div style="display: flex; gap: 12px; margin-top: 32px;">
<a href="/dossier/{{.TargetDossier.DossierID}}" class="btn btn-secondary" style="flex: 1; text-align: center;">Отмена</a>
<button type="submit" class="btn btn-primary" style="flex: 1;">Сохранить изменения</button>
</div>
</form>
<div style="border-top: 1px solid var(--border); padding-top: 32px; margin-top: 32px;">
<form action="/dossier/{{.TargetDossier.DossierID}}/rbac/{{.GranteeID}}" method="POST" onsubmit="return confirm('Отозвать весь доступ для {{.GranteeName}}?');">
<input type="hidden" name="action" value="revoke">
<button type="submit" class="btn btn-danger btn-full">Отозвать весь доступ</button>
</form>
</div>
</div>
</div>
<script>
(function() {
var roleSelect = document.getElementById('roleSelect');
var roleHidden = document.getElementById('roleHidden');
var allCbs = document.querySelectorAll('.perm-cb');
var catIDs = [];
document.querySelectorAll('tr[data-cat]').forEach(function(tr) { catIDs.push(parseInt(tr.dataset.cat)); });
roleSelect.addEventListener('change', function() {
roleHidden.value = this.value;
if (this.value === 'Custom') return;
var opt = this.options[this.selectedIndex];
var grantsJSON = opt.dataset.grants;
if (!grantsJSON) return;
var grants = JSON.parse(grantsJSON);
allCbs.forEach(function(cb) { cb.checked = false; });
var rootOps = '';
grants.forEach(function(g) { if (g.Category === 0) rootOps = g.Ops || ''; });
if (rootOps) catIDs.forEach(function(id) { setOps(id, rootOps); });
grants.forEach(function(g) { if (g.Category > 0) setOps(g.Category, g.Ops || ''); });
syncAll();
});
function setOps(catID, ops) {
var row = document.querySelector('tr[data-cat="' + catID + '"]');
if (!row) return;
var cbs = row.querySelectorAll('.perm-cb');
if (cbs[0]) cbs[0].checked = ops.includes('r');
if (cbs[1]) cbs[1].checked = ops.includes('w');
if (cbs[2]) cbs[2].checked = ops.includes('d');
if (cbs[3]) cbs[3].checked = ops.includes('m');
}
allCbs.forEach(function(cb) {
cb.addEventListener('change', function() {
roleSelect.value = 'Custom'; roleHidden.value = 'Custom';
syncRowToggle(this.closest('tr')); syncColToggles();
});
});
document.querySelectorAll('.row-toggle').forEach(function(toggle) {
toggle.addEventListener('change', function() {
var row = this.closest('tr');
row.querySelectorAll('.perm-cb').forEach(function(cb) { cb.checked = toggle.checked; });
roleSelect.value = 'Custom'; roleHidden.value = 'Custom';
syncColToggles();
});
});
document.querySelectorAll('.col-cb').forEach(function(cb) {
cb.addEventListener('change', function() {
document.querySelectorAll('.op-' + this.dataset.op).forEach(function(c) { c.checked = cb.checked; });
roleSelect.value = 'Custom'; roleHidden.value = 'Custom';
syncRowToggles();
});
});
function syncRowToggle(row) {
var cbs = row.querySelectorAll('.perm-cb');
var toggle = row.querySelector('.row-toggle');
if (toggle) toggle.checked = cbs.length > 0 && Array.from(cbs).every(function(cb) { return cb.checked; });
}
function syncRowToggles() { document.querySelectorAll('tr[data-cat]').forEach(syncRowToggle); }
function syncColToggles() {
document.querySelectorAll('.col-cb').forEach(function(cb) {
var colCbs = document.querySelectorAll('.op-' + cb.dataset.op);
cb.checked = colCbs.length > 0 && Array.from(colCbs).every(function(c) { return c.checked; });
});
}
function syncAll() { syncRowToggles(); syncColToggles(); }
syncAll();
})();
</script>
{{end}}