added an autocomplete component and implemented in permission grid

This commit is contained in:
Shaun Walker 2023-01-04 14:50:05 -05:00
parent 39dc288f9c
commit 6a213561f6
3 changed files with 180 additions and 30 deletions

View File

@ -0,0 +1,153 @@
@namespace Oqtane.Modules.Controls
@inherits LocalizableComponent
<div class="app-autocomplete">
<input class="form-control" value="@Value" @oninput="OnInput" @onkeyup="OnKeyUp" placeholder="@Placeholder" autocomplete="off" />
@if (_results != null)
{
<select class="form-select" style="position: relative;" value="@Value" size="@Rows" @onkeyup="OnKeyUp" @onchange="(e => OnChange(e))">
@if (_results.Any())
{
@foreach (var result in _results)
{
if (result.Value == Value)
{
<option selected>@result.Value</option>
}
else
{
<option>@result.Value</option>
}
}
}
else
{
<option disabled>No Results</option>
}
</select>
}
</div>
@code {
Dictionary<string, string> _results;
[Parameter]
public Func<string, Task<Dictionary<string, string>>> OnSearch { get; set; } // required - an async delegate method which accepts a filter string parameter and returns a dictionary
[Parameter]
public int Characters { get; set; } = 3; // optional - number of characters before search is initiated
[Parameter]
public int Rows { get; set; } = 3; // optional - number of result rows to display
[Parameter]
public string Placeholder { get; set; } // optional - placeholder input text
[Parameter]
public string Value { get; set; } // value of item selected
[Parameter]
public string Key { get; set; } // key of item selected
private async Task OnInput(ChangeEventArgs e)
{
Value = e.Value?.ToString();
if (Value?.Length >= Characters)
{
_results = await OnSearch?.Invoke(Value);
}
else
{
_results = null;
}
SetKey();
}
private async Task OnKeyUp(KeyboardEventArgs e)
{
var index = -1;
switch (e.Key)
{
case "ArrowDown":
if (_results == null)
{
if (Value?.Length >= Characters)
{
_results = await OnSearch?.Invoke(Value);
}
}
else
{
index = GetIndex();
if (index < _results.Count - 1)
{
Value = _results.ElementAt(index + 1).Value;
Key = _results.ElementAt(index + 1).Key;
}
}
break;
case "ArrowUp":
index = GetIndex();
if (index > 0)
{
Value = _results.ElementAt(index - 1).Value;
Key = _results.ElementAt(index - 1).Key;
}
break;
case "ArrowRight":
case "Tab":
_results = null;
break;
case "Enter": // note within a form the enter key submits the entire form
case "NumpadEnter":
_results = null;
break;
case "Escape":
Value = "";
_results = null;
break;
}
}
private void OnChange(ChangeEventArgs e)
{
Value = (string)e.Value;
SetKey();
_results = null;
}
private int GetIndex()
{
if (_results != null)
{
for (int index = 0; index < _results.Count; index++)
{
if (_results.ElementAt(index).Value == Value)
{
return index;
}
}
}
return -1;
}
private void SetKey()
{
var index = GetIndex();
if (index != -1)
{
Key = _results.ElementAt(index).Key;
}
else
{
Key = "";
}
}
public void Clear()
{
Value = "";
Key = "";
_results = null;
}
}

View File

@ -2,6 +2,7 @@
@inherits ModuleControlBase
@inject IRoleService RoleService
@inject IUserService UserService
@inject IUserRoleService UserRoleService
@inject IStringLocalizer<PermissionGrid> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer
@ -77,23 +78,16 @@
</div>
</div>
<div class="row">
<div class="col">
<table class="table table-borderless">
<tbody>
<tr>
<td class="input-group">
<input type="text" name="Username" class="form-control" placeholder="@Localizer["Username.Enter"]" @bind="@_username" />
<div class="col-11">
<AutoComplete OnSearch="GetUsers" Placeholder="@Localizer["Username.Enter"]" @ref="_user" />
</div>
<div class="col-1">
<button type="button" class="btn btn-primary" @onclick="AddUser">@SharedLocalizer["Add"]</button>
</td>
</tr>
</tbody>
</table>
<br />
</div>
</div>
<div class="row">
<div class="col">
<ModuleMessage Type="MessageType.Error" Message="@_message" />
<ModuleMessage Type="MessageType.Warning" Message="@_message" />
</div>
</div>
</div>
@ -104,7 +98,7 @@
private List<Role> _roles;
private List<PermissionString> _permissions;
private List<User> _users = new List<User>();
private string _username = string.Empty;
private AutoComplete _user;
private string _message = string.Empty;
[Parameter]
@ -191,25 +185,28 @@
private bool GetPermissionDisabled(string roleName)
=> (roleName == RoleNames.Admin && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) ? true : false;
private async Task<Dictionary<string, string>> GetUsers(string filter)
{
var users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
return users.Where(item => item.User.DisplayName.Contains(filter, StringComparison.OrdinalIgnoreCase))
.ToDictionary(item => item.UserId.ToString(), item => item.User.DisplayName);
}
private async Task AddUser()
{
if (_users.Where(item => item.Username == _username).FirstOrDefault() == null)
if (!string.IsNullOrEmpty(_user.Key))
{
try
{
var user = await UserService.GetUserAsync(_username, ModuleState.SiteId);
if (user != null)
var user = await UserService.GetUserAsync(int.Parse(_user.Key), ModuleState.SiteId);
if (user != null && !_users.Any(item => item.UserId == user.UserId))
{
_users.Add(user);
}
}
catch
else
{
_message = Localizer["Message.Username.DontExist"];
}
}
_username = string.Empty;
_user.Clear();
}
private void PermissionChanged(bool? value, string permissionName, string securityId)

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
@ -124,9 +124,9 @@
<value>User</value>
</data>
<data name="Username.Enter" xml:space="preserve">
<value>Enter Username</value>
<value>Enter User's Name</value>
</data>
<data name="Message.Username.DontExist" xml:space="preserve">
<value>Username Does Not Exist</value>
<value>User Does Not Exist With Name Specified</value>
</data>
</root>