114 lines
5.5 KiB
Cheetah
114 lines
5.5 KiB
Cheetah
{{define "permissions"}}
|
|
<div class="page-container">
|
|
<div class="page-card" style="max-width: 640px; margin: 0 auto;">
|
|
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 32px;">
|
|
<div>
|
|
<h1>{{.T.permissions_title}}</h1>
|
|
<p class="intro">{{.T.permissions_subtitle}}</p>
|
|
</div>
|
|
<a href="/dossier/{{.TargetDossier.DossierID}}" class="btn btn-secondary btn-small">← {{.T.back}}</a>
|
|
</div>
|
|
|
|
{{if .Error}}<div class="error">{{.Error}}</div>{{end}}
|
|
{{if .Success}}<div class="success">{{.Success}}</div>{{end}}
|
|
|
|
<div style="margin-bottom: 32px;">
|
|
<h3>{{.T.current_access}}</h3>
|
|
<div id="grantees-list">
|
|
{{if .Grantees}}
|
|
{{range .Grantees}}
|
|
<div style="display: flex; justify-content: space-between; align-items: center; padding: 16px; border-bottom: 1px solid var(--border);">
|
|
<div>
|
|
<span style="font-weight: 500;">{{.Name}}</span>
|
|
<span style="margin-left: 8px; font-size: 0.85rem; color: var(--text-muted);">{{.Role}}</span>
|
|
<span style="color: var(--text-muted); font-size: 0.85rem; margin-left: 8px;">{{.Ops}}</span>
|
|
</div>
|
|
<div style="display: flex; gap: 8px;">
|
|
<a href="/dossier/{{$.TargetDossier.DossierID}}/rbac/{{.GranteeID}}" class="btn btn-secondary btn-small">Edit</a>
|
|
<form action="/dossier/{{$.TargetDossier.DossierID}}/permissions" method="POST" style="display: inline;">
|
|
<input type="hidden" name="action" value="revoke">
|
|
<input type="hidden" name="grantee_id" value="{{.GranteeID}}">
|
|
<button type="submit" class="btn btn-danger btn-small" onclick="return confirm('Revoke access for {{.Name}}?')">{{$.T.revoke}}</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
{{else}}
|
|
<p style="color: var(--text-muted); padding: 16px;">{{.T.no_grantees}}</p>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<div style="border-top: 1px solid var(--border); padding-top: 32px;">
|
|
<h3>{{.T.grant_access}}</h3>
|
|
<form action="/dossier/{{.TargetDossier.DossierID}}/permissions" method="POST">
|
|
<input type="hidden" name="action" value="grant">
|
|
<div class="form-group">
|
|
<label>{{.T.person_email}}</label>
|
|
<input type="email" name="email" required placeholder="someone@example.com" autofocus>
|
|
<small style="color: var(--text-muted);">{{.T.person_email_hint}}</small>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>{{.T.person_name}}</label>
|
|
<input type="text" name="name" required placeholder="First Last">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>{{.T.role}}</label>
|
|
<select name="role" required onchange="updateOpsFromRole(this)">
|
|
<option value="">{{.T.select_role}}</option>
|
|
{{range .Roles}}
|
|
<option value="{{.Name}}" data-ops="{{.Ops}}">{{.Name}} — {{.Description}}</option>
|
|
{{end}}
|
|
<option value="custom" data-ops="r">{{.T.custom_role}}</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" id="custom-ops-group" style="display: none;">
|
|
<label>{{.T.permissions}}</label>
|
|
<div style="display: flex; gap: 16px; flex-wrap: wrap;">
|
|
<label class="checkbox-label"><input type="checkbox" name="op_r" value="1" checked disabled><span>{{.T.op_read}}</span></label>
|
|
<label class="checkbox-label"><input type="checkbox" name="op_w" value="1"><span>{{.T.op_write}}</span></label>
|
|
<label class="checkbox-label"><input type="checkbox" name="op_d" value="1"><span>{{.T.op_delete}}</span></label>
|
|
<label class="checkbox-label"><input type="checkbox" name="op_m" value="1"><span>{{.T.op_manage}}</span></label>
|
|
</div>
|
|
</div>
|
|
<div style="display: flex; gap: 12px; margin-top: 24px;">
|
|
<a href="/dossier/{{.TargetDossier.DossierID}}" class="btn btn-secondary" style="flex: 1; text-align: center;">{{.T.cancel}}</a>
|
|
<button type="submit" class="btn btn-primary" style="flex: 1;">{{.T.grant}}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div style="border-top: 1px solid var(--border); padding-top: 32px; margin-top: 32px;">
|
|
<h3>{{.T.role_descriptions}}</h3>
|
|
<div style="display: grid; gap: 16px;">
|
|
{{range .Roles}}
|
|
<div style="padding: 12px 16px; background: var(--bg-secondary); border-radius: 8px;">
|
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
<span style="font-weight: 500;">{{.Name}}</span>
|
|
<code style="font-size: 0.8rem;">{{.Ops}}</code>
|
|
</div>
|
|
<p style="color: var(--text-muted); font-size: 0.9rem; margin-top: 4px;">{{.Description}}</p>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
<div style="margin-top: 24px; padding: 16px; background: var(--bg-secondary); border-radius: 8px;">
|
|
<p style="font-size: 0.9rem; margin-bottom: 8px;"><strong>{{.T.ops_legend}}</strong></p>
|
|
<p style="font-size: 0.85rem; color: var(--text-muted);">
|
|
<code>r</code> = {{.T.op_read_desc}} ·
|
|
<code>w</code> = {{.T.op_write_desc}} ·
|
|
<code>d</code> = {{.T.op_delete_desc}} ·
|
|
<code>m</code> = {{.T.op_manage_desc}}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function updateOpsFromRole(select) {
|
|
var customGroup = document.getElementById('custom-ops-group');
|
|
customGroup.style.display = select.value === 'custom' ? '' : 'none';
|
|
}
|
|
</script>
|
|
{{end}}
|