@page "/role-grants" @using ZB.MOM.WW.OtOpcUa.Admin.Services @using ZB.MOM.WW.OtOpcUa.Configuration.Entities @using ZB.MOM.WW.OtOpcUa.Configuration.Enums @using ZB.MOM.WW.OtOpcUa.Configuration.Services @inject ILdapGroupRoleMappingService RoleSvc @inject ClusterService ClusterSvc

LDAP group → Admin role grants

Maps LDAP groups to Admin UI roles (ConfigViewer / ConfigEditor / FleetAdmin). Control-plane only — OPC UA data-path authorization reads NodeAcl rows directly and is unaffected by these mappings (see decision #150). A fleet-wide grant applies across every cluster; a cluster-scoped grant only binds within the named cluster. The same LDAP group may hold different roles on different clusters.
@if (_rows is null) {

Loading…

} else if (_rows.Count == 0) {

No role grants defined yet. Without at least one FleetAdmin grant, only the bootstrap admin can publish drafts.

} else { @foreach (var r in _rows) { }
LDAP groupRoleScopeCreatedNotes
@r.LdapGroup @r.Role @(r.IsSystemWide ? "Fleet-wide" : $"Cluster: {r.ClusterId}") @r.CreatedAtUtc.ToString("yyyy-MM-dd") @r.Notes
} @if (_showForm) {
New role grant
@if (_error is not null) {
@_error
}
} @code { private IReadOnlyList? _rows; private List? _clusters; private bool _showForm; private string _group = string.Empty; private AdminRole _role = AdminRole.ConfigViewer; private bool _isSystemWide; private string _clusterId = string.Empty; private string? _notes; private string? _error; protected override async Task OnInitializedAsync() => await ReloadAsync(); private async Task ReloadAsync() { _rows = await RoleSvc.ListAllAsync(CancellationToken.None); _clusters = await ClusterSvc.ListAsync(CancellationToken.None); } private void StartAdd() { _group = string.Empty; _role = AdminRole.ConfigViewer; _isSystemWide = false; _clusterId = string.Empty; _notes = null; _error = null; _showForm = true; } private async Task SaveAsync() { _error = null; try { var row = new LdapGroupRoleMapping { LdapGroup = _group.Trim(), Role = _role, IsSystemWide = _isSystemWide, ClusterId = _isSystemWide ? null : (string.IsNullOrWhiteSpace(_clusterId) ? null : _clusterId), Notes = string.IsNullOrWhiteSpace(_notes) ? null : _notes, }; await RoleSvc.CreateAsync(row, CancellationToken.None); _showForm = false; await ReloadAsync(); } catch (Exception ex) { _error = ex.Message; } } private async Task DeleteAsync(Guid id) { await RoleSvc.DeleteAsync(id, CancellationToken.None); await ReloadAsync(); } }