diff --git a/Oqtane.Client/Modules/Controls/AutoComplete.razor b/Oqtane.Client/Modules/Controls/AutoComplete.razor
new file mode 100644
index 00000000..b464fd20
--- /dev/null
+++ b/Oqtane.Client/Modules/Controls/AutoComplete.razor
@@ -0,0 +1,153 @@
+@namespace Oqtane.Modules.Controls
+@inherits LocalizableComponent
+
+
+
+ @if (_results != null)
+ {
+
+ }
+
+
+@code {
+ Dictionary _results;
+
+ [Parameter]
+ public Func>> 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;
+ }
+}
diff --git a/Oqtane.Client/Modules/Controls/PermissionGrid.razor b/Oqtane.Client/Modules/Controls/PermissionGrid.razor
index c2e6f87a..9fdb0d31 100644
--- a/Oqtane.Client/Modules/Controls/PermissionGrid.razor
+++ b/Oqtane.Client/Modules/Controls/PermissionGrid.razor
@@ -2,6 +2,7 @@
@inherits ModuleControlBase
@inject IRoleService RoleService
@inject IUserService UserService
+@inject IUserRoleService UserRoleService
@inject IStringLocalizer Localizer
@inject IStringLocalizer SharedLocalizer
@@ -77,23 +78,16 @@
-
-
-
+
+
+
@@ -104,7 +98,7 @@
private List _roles;
private List _permissions;
private List _users = new List();
- 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> 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(int.Parse(_user.Key), ModuleState.SiteId);
+ if (user != null && !_users.Any(item => item.UserId == user.UserId))
{
- var user = await UserService.GetUserAsync(_username, ModuleState.SiteId);
- if (user != null)
- {
- _users.Add(user);
- }
- }
- catch
- {
- _message = Localizer["Message.Username.DontExist"];
+ _users.Add(user);
}
}
-
- _username = string.Empty;
+ else
+ {
+ _message = Localizer["Message.Username.DontExist"];
+ }
+ _user.Clear();
}
private void PermissionChanged(bool? value, string permissionName, string securityId)
diff --git a/Oqtane.Client/Resources/Modules/Controls/PermissionGrid.resx b/Oqtane.Client/Resources/Modules/Controls/PermissionGrid.resx
index 3961c7cc..194c7267 100644
--- a/Oqtane.Client/Resources/Modules/Controls/PermissionGrid.resx
+++ b/Oqtane.Client/Resources/Modules/Controls/PermissionGrid.resx
@@ -1,4 +1,4 @@
-
+