Started improving server shares and general api controller structure

This commit is contained in:
2025-07-24 18:28:10 +02:00
parent a2db7be26f
commit 1f94752c54
29 changed files with 318 additions and 201 deletions

View File

@@ -11,11 +11,11 @@ public class DefaultServerTabProvider : IServerTabProvider
{
ServerTab[] tabs =
[
ServerTab.CreateFromComponent<ConsoleTab>("Console", "console", 0, permission => permission.Name == "console"),
ServerTab.CreateFromComponent<FilesTab>("Files", "files", 1, permission => permission.Name == "files"),
ServerTab.CreateFromComponent<SharesTab>("Shares", "shares", 2, permission => permission.Name == "shares"),
ServerTab.CreateFromComponent<VariablesTab>("Variables", "variables", 9, permission => permission.Name == "variables"),
ServerTab.CreateFromComponent<SettingsTab>("Settings", "settings", 10, permission => permission.Name == "settings"),
ServerTab.CreateFromComponent<ConsoleTab>("Console", "console", 0, permission => permission.Identifier == "console"),
ServerTab.CreateFromComponent<FilesTab>("Files", "files", 1, permission => permission.Identifier == "files"),
ServerTab.CreateFromComponent<SharesTab>("Shares", "shares", 2, permission => permission.Identifier == "shares"),
ServerTab.CreateFromComponent<VariablesTab>("Variables", "variables", 9, permission => permission.Identifier == "variables"),
ServerTab.CreateFromComponent<SettingsTab>("Settings", "settings", 10, permission => permission.Identifier == "settings"),
];
return Task.FromResult(tabs);

View File

@@ -1,4 +1,5 @@
using MoonlightServers.Frontend.UI.Components.Servers.ServerTabs;
using MoonlightServers.Shared.Enums;
using MoonlightServers.Shared.Models;
namespace MoonlightServers.Frontend.Models;
@@ -7,7 +8,8 @@ public record ServerTab
{
public string Name { get; private set; }
public string Path { get; private set; }
public Func<ServerSharePermission, bool>? PermissionFilter { get; private set; }
public string PermissionId { get; set; }
public ServerPermissionLevel PermissionLevel { get; set; }
public int Priority { get; private set; }
public Type ComponentType { get; private set; }
@@ -15,7 +17,7 @@ public record ServerTab
string name,
string path,
int priority,
Func<ServerSharePermission, bool>? filter = null) where T : BaseServerTab
string permissionId = "", ServerPermissionLevel permissionLevel = ServerPermissionLevel.None) where T : BaseServerTab
{
return new()
{
@@ -23,7 +25,8 @@ public record ServerTab
Path = path,
Priority = priority,
ComponentType = typeof(T),
PermissionFilter = filter
PermissionLevel = permissionLevel,
PermissionId = permissionId
};
}
}

View File

@@ -19,24 +19,39 @@
{
var i = Permissions.TryGetValue(name, out var permission) ? (int)permission : -1;
<div class="col-span-1 flex flex-row items-center justify-center lg:justify-start">
@name
<div class="col-span-1 flex flex-col justify-center lg:justify-start text-center lg:text-start">
<span>@name</span>
<span class="text-base-content/80 text-sm">This is a long description</span>
</div>
<div class="col-span-1 flex flex-row items-center justify-center lg:justify-end">
<div class="tabs">
<button @onclick="() => Reset(name)"
class="tabs-segment @(i == -1 ? "tabs-segment-active" : "")">
None
</button>
<button @onclick="() => Set(name, ServerPermissionType.Read)"
class="tabs-segment @(i == 0 ? "tabs-segment-active" : "")">
Read
</button>
<button @onclick="() => Set(name, ServerPermissionType.ReadWrite)"
class="tabs-segment @(i == 1 ? "tabs-segment-active" : "")">
Read & Write
</button>
<div class="col-span-1 flex justify-end">
<div class="join drop-shadow">
@if (i == -1)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="None" checked="checked"/>
}
else
{
<input @onclick="() => Reset(name)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="None"/>
}
@if (i == 0)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read" checked="checked"/>
}
else
{
<input @onclick="() => Set(name, ServerPermissionLevel.Read)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read"/>
}
@if (i == 1)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read & Write" checked="checked"/>
}
else
{
<input @onclick="() => Set(name, ServerPermissionLevel.ReadWrite)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read & Write"/>
}
</div>
</div>
}
@@ -56,7 +71,7 @@
private HandleForm HandleForm;
private CreateShareRequest Request;
private Dictionary<string, ServerPermissionType> Permissions = new();
private Dictionary<string, ServerPermissionLevel> Permissions = new();
private string[] Names =
[
@@ -76,9 +91,9 @@
};
}
private async Task Set(string name, ServerPermissionType type)
private async Task Set(string name, ServerPermissionLevel level)
{
Permissions[name] = type;
Permissions[name] = level;
await InvokeAsync(StateHasChanged);
}
@@ -93,10 +108,10 @@
private async Task OnValidSubmit()
{
Request.Permissions = Permissions.Select(x => new ServerSharePermission()
Request.Permissions = Permissions.Select(x => new GrantedServerPermission()
{
Name = x.Key,
Type = x.Value
Identifier = x.Key,
Level = x.Value
}).ToList();
await OnSubmit.Invoke(Request);

View File

@@ -16,24 +16,39 @@
{
var i = Permissions.TryGetValue(name, out var permission) ? (int)permission : -1;
<div class="col-span-1 flex flex-row items-center justify-center lg:justify-start">
@name
<div class="col-span-1 flex flex-col justify-center lg:justify-start text-center lg:text-start">
<span>@name</span>
<span class="text-base-content/80 text-sm">This is a long description</span>
</div>
<div class="col-span-1 flex flex-row items-center justify-center lg:justify-end">
<div class="tabs">
<button @onclick="() => Reset(name)"
class="tabs-segment @(i == -1 ? "tabs-segment-active" : "")">
None
</button>
<button @onclick="() => Set(name, ServerPermissionType.Read)"
class="tabs-segment @(i == 0 ? "tabs-segment-active" : "")">
Read
</button>
<button @onclick="() => Set(name, ServerPermissionType.ReadWrite)"
class="tabs-segment @(i == 1 ? "tabs-segment-active" : "")">
Read & Write
</button>
<div class="col-span-1 flex justify-end">
<div class="join drop-shadow">
@if (i == -1)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="None" checked="checked"/>
}
else
{
<input @onclick="() => Reset(name)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="None"/>
}
@if (i == 0)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read" checked="checked"/>
}
else
{
<input @onclick="() => Set(name, ServerPermissionLevel.Read)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read"/>
}
@if (i == 1)
{
<input class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read & Write" checked="checked"/>
}
else
{
<input @onclick="() => Set(name, ServerPermissionLevel.ReadWrite)" class="join-item btn btn-soft" type="radio" name="share-@name" aria-label="Read & Write"/>
}
</div>
</div>
}
@@ -53,7 +68,7 @@
private HandleForm HandleForm;
private UpdateShareRequest Request;
private Dictionary<string, ServerPermissionType> Permissions = new();
private Dictionary<string, ServerPermissionLevel> Permissions = new();
private string[] Names =
[
@@ -69,12 +84,12 @@
{
Request = new();
Permissions = Share.Permissions.ToDictionary(x => x.Name, x => x.Type);
Permissions = Share.Permissions.ToDictionary(x => x.Identifier, x => x.Level);
}
private async Task Set(string name, ServerPermissionType type)
private async Task Set(string name, ServerPermissionLevel level)
{
Permissions[name] = type;
Permissions[name] = level;
await InvokeAsync(StateHasChanged);
}
@@ -89,10 +104,10 @@
private async Task OnValidSubmit()
{
Request.Permissions = Permissions.Select(x => new ServerSharePermission()
Request.Permissions = Permissions.Select(x => new GrantedServerPermission()
{
Name = x.Key,
Type = x.Value
Identifier = x.Key,
Level = x.Value
}).ToList();
await OnSubmit.Invoke(Request);

View File

@@ -39,7 +39,7 @@
_ => "status-secondary"
};
}
<div class="inline-grid *:[grid-area:1/1] me-3">
@if (State != ServerState.Offline)
{
@@ -65,7 +65,7 @@
</div>
<div class="flex flex-row items-center">
<div class="flex gap-x-1.5">
@if (HasPermissionTo("power", ServerPermissionType.ReadWrite))
@if (HasPermissionTo("power", ServerPermissionLevel.ReadWrite))
{
@if (State == ServerState.Offline)
{
@@ -128,12 +128,12 @@
<i class="icon-play align-middle"></i>
<span class="align-middle">Start</span>
</button>
<button type="button" class="btn btn-primary" disabled="disabled">
<i class="icon-rotate-ccw align-middle"></i>
<span class="align-middle">Restart</span>
</button>
<button type="button" class="btn btn-error" disabled="disabled">
<i class="icon-squircle align-middle"></i>
<span class="align-middle">Stop</span>
@@ -144,7 +144,7 @@
</div>
<div class="mt-3">
<nav class="tabs space-x-2 overflow-x-auto" aria-label="Tabs" role="tablist" aria-orientation="horizontal">
@foreach (var tab in Tabs)
{
@@ -154,8 +154,8 @@
role="tab"
@onclick:preventDefault
@onclick="() => SwitchTab(tab)">
@tab.Name
</a>
@tab.Name
</a>
}
</nav>
@@ -217,13 +217,18 @@
// If we are accessing a shared server, we need to handle permissions
if (Server.Share != null)
{
// This removes all tabs where the permission filter is not set
// This removes all tabs where the user doesn't have the required permissions
tmpTabs.RemoveAll(tab =>
{
if (tab.PermissionFilter == null)
if (string.IsNullOrEmpty(tab.PermissionId) || tab.PermissionLevel == ServerPermissionLevel.None)
return false;
return !Server.Share.Permissions.Any(tab.PermissionFilter);
// If permission is required but not set, we dont have access to it
if (!Server.Share.Permissions.TryGetValue(tab.PermissionId, out var level))
return true;
// True if the acquired level is higher or equal than the required permission level for the tba
return level >= tab.PermissionLevel;
});
}
@@ -244,7 +249,7 @@
State = status.State;
if (!HasPermissionTo("console", ServerPermissionType.Read))
if (!HasPermissionTo("console", ServerPermissionLevel.Read))
return; // Exit early if we don't have permissions to load the console
// Load initial messages
@@ -300,13 +305,16 @@
}
}
private bool HasPermissionTo(string name, ServerPermissionType type)
private bool HasPermissionTo(string id, ServerPermissionLevel level)
{
// All non shares have permissions
if (Server.Share == null)
return true;
return Server.Share.Permissions.Any(x => x.Name == name && x.Type >= type);
if (!Server.Share.Permissions.TryGetValue(id, out var acquiredLevel))
return false;
return acquiredLevel >= level;
}
private async Task SwitchTab(ServerTab tab)