Compare commits

..

No commits in common. "main" and "save-path-regex" have entirely different histories.

45 changed files with 431 additions and 5031 deletions

View File

@ -38,14 +38,11 @@
<Reference Include="ByteSize, Version=2.1.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ByteSize.2.1.1\lib\net45\ByteSize.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.7.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.7.0.0\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Playnite.SDK, Version=6.10.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\PlayniteSDK.6.10.0\lib\net462\Playnite.SDK.dll</HintPath>
@ -77,14 +74,14 @@
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encoding.CodePages, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encoding.CodePages.8.0.0\lib\net462\System.Text.Encoding.CodePages.dll</HintPath>
<Reference Include="System.Text.Encoding.CodePages, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encoding.CodePages.7.0.0\lib\net462\System.Text.Encoding.CodePages.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
<Reference Include="System.Text.Encodings.Web, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.7.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Json.8.0.0\lib\net462\System.Text.Json.dll</HintPath>
<Reference Include="System.Text.Json, Version=7.0.0.3, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Json.7.0.3\lib\net462\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>

View File

@ -38,13 +38,3 @@ Packages:
- Full game download will be skipped if the game files already exist, see full release notes for more details
- Play sessions are now recorded to the server with user ID, start time, and end time
- Connection status now updates correctly when authenticating through addon settings
- Version: 0.3.0
RequiredApiVersion: 6.0.0
ReleaseDate: 2023-12-03
PackageUrl: https://github.com/LANCommander/LANCommander/releases/download/v0.3.0/LANCommander.PlaynitePlugin_48e1bac7-e0a0-45d7-ba83-36f5e9e959fc_0_3_0.pext
Changelog:
- Save paths now support regex patterns (experimental)
- Fixed redistributable archive downloading
- Fixed redistributable scripts not being able to run as admin if marked as such
- Fixed game save downloading
- Fixed addon loading of YamlDotNet library

View File

@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ByteSize" version="2.1.1" targetFramework="net462" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net462" />
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="8.0.0" targetFramework="net462" />
<package id="Microsoft.Extensions.Logging.Abstractions" version="8.0.0" targetFramework="net462" />
<package id="NuGet.CommandLine" version="6.8.0" targetFramework="net462" developmentDependency="true" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="7.0.0" targetFramework="net462" />
<package id="Microsoft.Extensions.Logging.Abstractions" version="7.0.0" targetFramework="net462" />
<package id="NuGet.CommandLine" version="6.7.0" targetFramework="net462" developmentDependency="true" />
<package id="PlayniteSDK" version="6.10.0" targetFramework="net462" />
<package id="PowerShellStandard.Library" version="5.1.1" targetFramework="net462" />
<package id="RestSharp" version="106.15.0" targetFramework="net462" />
@ -14,9 +13,9 @@
<package id="System.Memory" version="4.5.5" targetFramework="net462" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net462" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net462" />
<package id="System.Text.Encoding.CodePages" version="8.0.0" targetFramework="net462" />
<package id="System.Text.Encodings.Web" version="8.0.0" targetFramework="net462" />
<package id="System.Text.Json" version="8.0.0" targetFramework="net462" />
<package id="System.Text.Encoding.CodePages" version="7.0.0" targetFramework="net462" />
<package id="System.Text.Encodings.Web" version="7.0.0" targetFramework="net462" />
<package id="System.Text.Json" version="7.0.3" targetFramework="net462" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net462" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net462" />
<package id="YamlDotNet" version="5.4.0" targetFramework="net462" />

View File

@ -39,57 +39,21 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=5.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.2.10\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
</Reference>
<Reference Include="RestSharp, Version=106.15.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
<HintPath>..\packages\RestSharp.106.15.0\lib\net452\RestSharp.dll</HintPath>
</Reference>
<Reference Include="SharpCompress, Version=0.34.2.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
<HintPath>..\packages\SharpCompress.0.34.2\lib\net462\SharpCompress.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encoding.CodePages, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encoding.CodePages.8.0.0\lib\net462\System.Text.Encoding.CodePages.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="YamlDotNet, Version=5.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\YamlDotNet.5.4.0\lib\net45\YamlDotNet.dll</HintPath>
</Reference>
<Reference Include="ZstdSharp, Version=0.7.4.0, Culture=neutral, PublicKeyToken=8d151af33a4ad5cf, processorArchitecture=MSIL">
<HintPath>..\packages\ZstdSharp.Port.0.7.4\lib\net462\ZstdSharp.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Cmdlets.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
@ -97,10 +61,6 @@
<Project>{807943bf-0c7d-4ed3-8393-cfee64e3138c}</Project>
<Name>LANCommander.PowerShell</Name>
</ProjectReference>
<ProjectReference Include="..\LANCommander.SDK\LANCommander.SDK.csproj">
<Project>{4c2a71fd-a30b-4d62-888a-4ef843d8e506}</Project>
<Name>LANCommander.SDK</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

View File

@ -1,16 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Bcl.AsyncInterfaces" version="5.0.0" targetFramework="net462" />
<package id="MSTest.TestAdapter" version="2.2.10" targetFramework="net462" />
<package id="MSTest.TestFramework" version="2.2.10" targetFramework="net462" />
<package id="RestSharp" version="106.15.0" targetFramework="net462" />
<package id="SharpCompress" version="0.34.2" targetFramework="net462" />
<package id="System.Buffers" version="4.5.1" targetFramework="net462" />
<package id="System.Memory" version="4.5.5" targetFramework="net462" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net462" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net462" />
<package id="System.Text.Encoding.CodePages" version="8.0.0" targetFramework="net462" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net462" />
<package id="YamlDotNet" version="5.4.0" targetFramework="net462" />
<package id="ZstdSharp.Port" version="0.7.4" targetFramework="net462" />
</packages>

View File

@ -20,9 +20,6 @@ namespace LANCommander.PowerShell.Cmdlets
[Parameter]
public int MaxLength { get; set; } = 0;
[Parameter]
public int MinLength { get; set; } = 0;
protected override void ProcessRecord()
{
byte[] output;
@ -30,11 +27,6 @@ namespace LANCommander.PowerShell.Cmdlets
if (MaxLength > 0 && Input.Length > MaxLength)
Input = Input.Substring(0, MaxLength);
if (MinLength > 0 && MinLength < MaxLength)
Input = Input.PadRight(MinLength, '\0');
else if (MinLength > 0)
Input = Input.PadRight(MaxLength, '\0');
if (Utf16 && BigEndian)
output = System.Text.Encoding.BigEndianUnicode.GetBytes(Input);
else if (Utf16)

View File

@ -5,7 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
<PackageReference Include="RestSharp" Version="106.15.0" />
<PackageReference Include="SharpCompress" Version="0.34.2" />

View File

@ -58,18 +58,11 @@
ICollection<Script> Scripts { get; set; } = new List<Script>();
protected override async Task OnParametersSetAsync()
{
await LoadData();
}
private async Task LoadData()
{
if (GameId != Guid.Empty)
Scripts = await ScriptService.Get(s => s.GameId == GameId).ToListAsync();
else if (RedistributableId != Guid.Empty)
Scripts = await ScriptService.Get(s => s.RedistributableId == RedistributableId).ToListAsync();
await InvokeAsync(StateHasChanged);
}
private async void Edit(Guid? scriptId = null)
@ -96,8 +89,10 @@
modalRef.OnOk = async (script) =>
{
await LoadData();
};
StateHasChanged();
}
private async void Delete(Script script = null)

View File

@ -85,16 +85,6 @@
{
if (Options.ScriptId != Guid.Empty)
Script = await ScriptService.Get(Options.ScriptId);
else if (Options.GameId != Guid.Empty)
Script = new Script()
{
GameId = Options.GameId
};
else if (Options.RedistributableId != Guid.Empty)
Script = new Script()
{
RedistributableId = Options.RedistributableId
};
Snippets = ScriptService.GetSnippets();
}
@ -171,8 +161,6 @@
}
private async Task Save()
{
try
{
var value = await Editor.GetValue();
@ -183,13 +171,6 @@
else
Script = await ScriptService.Update(Script);
MessageService.Success("Script saved!");
}
catch (Exception ex)
{
MessageService.Error("Script could not be saved!");
throw ex;
}
await MessageService.Success("Script saved!");
}
}

View File

@ -2,7 +2,7 @@
<Select Mode="tags" TItem="Guid" TItemValue="Guid" @bind-Values="@SelectedValues" OnSelectedItemsChanged="OnSelectedItemsChanged" EnableSearch>
<SelectOptions>
@foreach (var entity in Entities.OrderBy(OptionLabelSelector))
@foreach (var entity in Entities)
{
<SelectOption TItemValue="Guid" TItem="Guid" Value="@entity.Id" Label="@OptionLabelSelector.Invoke(entity)" />
}
@ -45,7 +45,7 @@
}
if (ValuesChanged.HasDelegate)
await ValuesChanged.InvokeAsync(Values);
await ValuesChanged.InvokeAsync();
StateHasChanged();
}

View File

@ -20,7 +20,6 @@ namespace LANCommander.Data
builder.ConfigureBaseRelationships<Data.Models.Action>();
builder.ConfigureBaseRelationships<Archive>();
builder.ConfigureBaseRelationships<Category>();
builder.ConfigureBaseRelationships<Collection>();
builder.ConfigureBaseRelationships<Company>();
builder.ConfigureBaseRelationships<Game>();
builder.ConfigureBaseRelationships<GameSave>();
@ -181,28 +180,6 @@ namespace LANCommander.Data
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade);
#endregion
#region Collection Relationships
builder.Entity<Collection>()
.HasMany(c => c.Games)
.WithMany(g => g.Collections)
.UsingEntity<Dictionary<string, object>>(
"CollectionGame",
cg => cg.HasOne<Game>().WithMany().HasForeignKey("GameId"),
cg => cg.HasOne<Collection>().WithMany().HasForeignKey("CollectionId")
);
#endregion
#region Role Relationships
builder.Entity<Role>()
.HasMany(r => r.Collections)
.WithMany(c => c.Roles)
.UsingEntity<Dictionary<string, object>>(
"RoleCollection",
rc => rc.HasOne<Collection>().WithMany().HasForeignKey("CollectionId"),
rc => rc.HasOne<Role>().WithMany().HasForeignKey("RoleId")
);
#endregion
}
public DbSet<Game>? Games { get; set; }

View File

@ -1,15 +0,0 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace LANCommander.Data.Models
{
[Table("Collections")]
public class Collection : BaseModel
{
public string Name { get; set; }
[JsonIgnore]
public virtual ICollection<Game> Games { get; set; }
[JsonIgnore]
public virtual ICollection<Role> Roles { get; set; }
}
}

View File

@ -39,6 +39,5 @@ namespace LANCommander.Data.Models
public string? ValidKeyRegex { get; set; }
public virtual ICollection<Key>? Keys { get; set; }
public virtual ICollection<Collection> Collections { get; set; }
}
}

View File

@ -6,6 +6,5 @@ namespace LANCommander.Data.Models
[Table("Roles")]
public class Role : IdentityRole<Guid>
{
public virtual ICollection<Collection> Collections { get; set; }
}
}

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-LANCommander-C1F79CFA-9767-4AD7-BD5A-2549F8328A2D</UserSecretsId>
@ -34,14 +34,14 @@
<PackageReference Include="Hangfire.InMemory" Version="0.6.0" />
<PackageReference Include="IGDB" Version="2.3.2" />
<PackageReference Include="IPXRelayDotNet" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0">
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.13" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.13" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="7.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.13">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@ -50,14 +50,14 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.11" />
<PackageReference Include="NLog" Version="5.2.5" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.5" />
<PackageReference Include="RegParserDotNet" Version="1.0.4" />
<PackageReference Include="rix0rrr.BeaconLib" Version="1.0.2" />
<PackageReference Include="swashbuckle" Version="5.6.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="8.0.0" />
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="7.0.0" />
<PackageReference Include="XtermBlazor" Version="1.10.0" />
<PackageReference Include="YamlDotNet" Version="13.3.1" />
</ItemGroup>
@ -66,6 +66,7 @@
<Folder Include="bin\Debug\net6.0\" />
<Folder Include="Data\Migrations\" />
<Folder Include="Migrations\" />
<Folder Include="Pages\Games\Archives\" />
<Folder Include="Scripts\" />
</ItemGroup>

View File

@ -11,15 +11,15 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace LANCommander.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20231202235325_AddSavePathRegexFlag")]
partial class AddSavePathRegexFlag
[Migration("20231106061719_AddRegexFlagToSavePath")]
partial class AddRegexFlagToSavePath
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("ProductVersion", "7.0.13")
.HasAnnotation("Proxies:ChangeTracking", false)
.HasAnnotation("Proxies:CheckEquality", false)
.HasAnnotation("Proxies:LazyLoading", true);
@ -358,7 +358,7 @@ namespace LANCommander.Migrations
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<Guid?>("GameId")
b.Property<Guid>("GameId")
.HasColumnType("TEXT");
b.Property<Guid?>("UpdatedById")
@ -573,49 +573,6 @@ namespace LANCommander.Migrations
b.ToTable("MultiplayerModes");
});
modelBuilder.Entity("LANCommander.Data.Models.PlaySession", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid?>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<DateTime?>("End")
.HasColumnType("TEXT");
b.Property<Guid?>("GameId")
.HasColumnType("TEXT");
b.Property<DateTime?>("Start")
.HasColumnType("TEXT");
b.Property<Guid?>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.Property<Guid>("UserId")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CreatedById");
b.HasIndex("GameId");
b.HasIndex("UpdatedById");
b.HasIndex("UserId");
b.ToTable("PlaySessions");
});
modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b =>
{
b.Property<Guid>("Id")
@ -1254,8 +1211,7 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("Actions")
@ -1265,8 +1221,7 @@ namespace LANCommander.Migrations
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1279,8 +1234,7 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("Archives")
@ -1298,8 +1252,7 @@ namespace LANCommander.Migrations
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1316,8 +1269,7 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Category", "Parent")
.WithMany("Children")
@ -1325,8 +1277,7 @@ namespace LANCommander.Migrations
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1339,13 +1290,11 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1356,13 +1305,11 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1373,18 +1320,17 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("GameSaves")
.HasForeignKey("GameId")
.OnDelete(DeleteBehavior.SetNull);
.OnDelete(DeleteBehavior.NoAction)
.IsRequired();
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.HasOne("LANCommander.Data.Models.User", "User")
.WithMany("GameSaves")
@ -1405,13 +1351,11 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1426,8 +1370,7 @@ namespace LANCommander.Migrations
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("Keys")
@ -1437,8 +1380,7 @@ namespace LANCommander.Migrations
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("ClaimedByUser");
@ -1453,8 +1395,7 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("Media")
@ -1464,8 +1405,7 @@ namespace LANCommander.Migrations
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1478,8 +1418,7 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("MultiplayerModes")
@ -1489,8 +1428,7 @@ namespace LANCommander.Migrations
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1499,49 +1437,15 @@ namespace LANCommander.Migrations
b.Navigation("UpdatedBy");
});
modelBuilder.Entity("LANCommander.Data.Models.PlaySession", b =>
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("PlaySessions")
.HasForeignKey("GameId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("LANCommander.Data.Models.User", "User")
.WithMany("PlaySessions")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CreatedBy");
b.Navigation("Game");
b.Navigation("UpdatedBy");
b.Navigation("User");
});
modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b =>
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1552,18 +1456,15 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("SavePaths")
.HasForeignKey("GameId")
.OnDelete(DeleteBehavior.Cascade);
.HasForeignKey("GameId");
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1576,8 +1477,7 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("Scripts")
@ -1591,8 +1491,7 @@ namespace LANCommander.Migrations
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1607,18 +1506,16 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Game", "Game")
.WithMany("Servers")
.HasForeignKey("GameId")
.OnDelete(DeleteBehavior.SetNull);
.OnDelete(DeleteBehavior.NoAction);
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1631,8 +1528,7 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Server", "Server")
.WithMany()
@ -1646,8 +1542,7 @@ namespace LANCommander.Migrations
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1660,8 +1555,7 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.Server", "Server")
.WithMany()
@ -1675,8 +1569,7 @@ namespace LANCommander.Migrations
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1689,13 +1582,11 @@ namespace LANCommander.Migrations
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("CreatedById");
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
.HasForeignKey("UpdatedById");
b.Navigation("CreatedBy");
@ -1772,8 +1663,6 @@ namespace LANCommander.Migrations
b.Navigation("MultiplayerModes");
b.Navigation("PlaySessions");
b.Navigation("SavePaths");
b.Navigation("Scripts");
@ -1798,8 +1687,6 @@ namespace LANCommander.Migrations
modelBuilder.Entity("LANCommander.Data.Models.User", b =>
{
b.Navigation("GameSaves");
b.Navigation("PlaySessions");
});
#pragma warning restore 612, 618
}

View File

@ -5,7 +5,7 @@
namespace LANCommander.Migrations
{
/// <inheritdoc />
public partial class AddSavePathRegexFlag : Migration
public partial class AddRegexFlagToSavePath : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LANCommander.Migrations
{
/// <inheritdoc />
public partial class FixScriptDisplayBounds : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$Display.Width', '$Display.Bounds.Width')");
migrationBuilder.Sql("UPDATE Scripts SET Contents = REPLACE(Contents, '$Display.Height', '$Display.Bounds.Height')");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,124 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LANCommander.Migrations
{
/// <inheritdoc />
public partial class AddCollections : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Collections",
columns: table => new
{
Id = table.Column<Guid>(type: "TEXT", nullable: false),
Name = table.Column<string>(type: "TEXT", nullable: false),
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
CreatedById = table.Column<Guid>(type: "TEXT", nullable: true),
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Collections", x => x.Id);
table.ForeignKey(
name: "FK_Collections_AspNetUsers_CreatedById",
column: x => x.CreatedById,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.SetNull);
table.ForeignKey(
name: "FK_Collections_AspNetUsers_UpdatedById",
column: x => x.UpdatedById,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.SetNull);
});
migrationBuilder.CreateTable(
name: "CollectionGame",
columns: table => new
{
CollectionId = table.Column<Guid>(type: "TEXT", nullable: false),
GameId = table.Column<Guid>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CollectionGame", x => new { x.CollectionId, x.GameId });
table.ForeignKey(
name: "FK_CollectionGame_Collections_CollectionId",
column: x => x.CollectionId,
principalTable: "Collections",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_CollectionGame_Games_GameId",
column: x => x.GameId,
principalTable: "Games",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "RoleCollection",
columns: table => new
{
CollectionId = table.Column<Guid>(type: "TEXT", nullable: false),
RoleId = table.Column<Guid>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_RoleCollection", x => new { x.CollectionId, x.RoleId });
table.ForeignKey(
name: "FK_RoleCollection_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_RoleCollection_Collections_CollectionId",
column: x => x.CollectionId,
principalTable: "Collections",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_CollectionGame_GameId",
table: "CollectionGame",
column: "GameId");
migrationBuilder.CreateIndex(
name: "IX_Collections_CreatedById",
table: "Collections",
column: "CreatedById");
migrationBuilder.CreateIndex(
name: "IX_Collections_UpdatedById",
table: "Collections",
column: "UpdatedById");
migrationBuilder.CreateIndex(
name: "IX_RoleCollection_RoleId",
table: "RoleCollection",
column: "RoleId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "CollectionGame");
migrationBuilder.DropTable(
name: "RoleCollection");
migrationBuilder.DropTable(
name: "Collections");
}
}
}

View File

@ -16,7 +16,7 @@ namespace LANCommander.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("ProductVersion", "7.0.13")
.HasAnnotation("Proxies:ChangeTracking", false)
.HasAnnotation("Proxies:CheckEquality", false)
.HasAnnotation("Proxies:LazyLoading", true);
@ -36,21 +36,6 @@ namespace LANCommander.Migrations
b.ToTable("CategoryGame");
});
modelBuilder.Entity("CollectionGame", b =>
{
b.Property<Guid>("CollectionId")
.HasColumnType("TEXT");
b.Property<Guid>("GameId")
.HasColumnType("TEXT");
b.HasKey("CollectionId", "GameId");
b.HasIndex("GameId");
b.ToTable("CollectionGame");
});
modelBuilder.Entity("GameDeveloper", b =>
{
b.Property<Guid>("DeveloperId")
@ -272,37 +257,6 @@ namespace LANCommander.Migrations
b.ToTable("Categories");
});
modelBuilder.Entity("LANCommander.Data.Models.Collection", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<Guid?>("CreatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("CreatedOn")
.HasColumnType("TEXT");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT");
b.Property<Guid?>("UpdatedById")
.HasColumnType("TEXT");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CreatedById");
b.HasIndex("UpdatedById");
b.ToTable("Collections");
});
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
{
b.Property<Guid>("Id")
@ -1203,21 +1157,6 @@ namespace LANCommander.Migrations
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("RoleCollection", b =>
{
b.Property<Guid>("CollectionId")
.HasColumnType("TEXT");
b.Property<Guid>("RoleId")
.HasColumnType("TEXT");
b.HasKey("CollectionId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("RoleCollection");
});
modelBuilder.Entity("CategoryGame", b =>
{
b.HasOne("LANCommander.Data.Models.Category", null)
@ -1233,21 +1172,6 @@ namespace LANCommander.Migrations
.IsRequired();
});
modelBuilder.Entity("CollectionGame", b =>
{
b.HasOne("LANCommander.Data.Models.Collection", null)
.WithMany()
.HasForeignKey("CollectionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.Game", null)
.WithMany()
.HasForeignKey("GameId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("GameDeveloper", b =>
{
b.HasOne("LANCommander.Data.Models.Company", null)
@ -1408,23 +1332,6 @@ namespace LANCommander.Migrations
b.Navigation("UpdatedBy");
});
modelBuilder.Entity("LANCommander.Data.Models.Collection", b =>
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
.WithMany()
.HasForeignKey("UpdatedById")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("CreatedBy");
b.Navigation("UpdatedBy");
});
modelBuilder.Entity("LANCommander.Data.Models.Company", b =>
{
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
@ -1843,21 +1750,6 @@ namespace LANCommander.Migrations
.IsRequired();
});
modelBuilder.Entity("RoleCollection", b =>
{
b.HasOne("LANCommander.Data.Models.Collection", null)
.WithMany()
.HasForeignKey("CollectionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("LANCommander.Data.Models.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("LANCommander.Data.Models.Category", b =>
{
b.Navigation("Children");

View File

@ -1,7 +0,0 @@
namespace LANCommander.Models
{
public class AddToCollectionOptions
{
public IEnumerable<Guid> GameIds { get; set; }
}
}

View File

@ -1,10 +0,0 @@
namespace LANCommander.Models
{
public class RoleViewModel
{
public string Name { get; set; }
public int Users { get; set; }
public int Collections { get; set; }
}
}

View File

@ -1,145 +0,0 @@
@page "/Collections/{id:guid}"
@page "/Collections/Add"
@using LANCommander.Data.Enums;
@using LANCommander.Extensions
@attribute [Authorize(Roles = "Administrator")]
@inject CollectionService CollectionService
@inject IMessageService MessageService
@inject NavigationManager NavigationManager
<PageHeader>
<PageHeaderTitle>
<Input Size="@InputSize.Large" @bind-Value="@Collection.Name" />
</PageHeaderTitle>
<PageHeaderExtra>
<Button Type="@ButtonType.Primary" OnClick="Save">Save</Button>
</PageHeaderExtra>
</PageHeader>
<Table TItem="Game" DataSource="@Collection.Games" Responsive>
<Column TData="string" Title="Icon">
<Image Src="@GetIcon(context)" Height="32" Width="32" Preview="false"></Image>
</Column>
<PropertyColumn Property="g => g.Title" Sortable Filterable />
<PropertyColumn Property="g => g.ReleasedOn" Format="MM/dd/yyyy" Sortable Filterable />
<PropertyColumn Property="g => g.Singleplayer" Sortable Filterable>
<Checkbox Disabled="true" Checked="context.Singleplayer" />
</PropertyColumn>
<Column TData="bool" Title="Multiplayer">
<Checkbox Disabled="true" Checked="context.MultiplayerModes?.Count > 0" />
</Column>
<Column TData="string[]" Title="Developers">
@foreach (var dev in context.Developers)
{
<Tag>@dev.Name</Tag>
}
</Column>
<Column TData="string[]" Title="Publishers">
@foreach (var pub in context.Publishers)
{
<Tag>@pub.Name</Tag>
}
</Column>
<Column TData="string[]" Title="Genres">
@foreach (var genre in context.Genres)
{
<Tag>@genre.Name</Tag>
}
</Column>
<Column TData="Data.Enums.MultiplayerType[]" Title="Multiplayer Modes">
@foreach (var mode in context.MultiplayerModes.Select(mm => mm.Type).Distinct())
{
<Tag>@mode.GetDisplayName()</Tag>
}
</Column>
<ActionColumn Title="" Style="text-align: right">
<ChildContent>
<Space Direction="DirectionVHType.Horizontal">
<SpaceItem>
<Popconfirm OnConfirm="() => RemoveGame(context)" Title="Are you sure you want to remove this game from the collection?">
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
</Popconfirm>
</SpaceItem>
</Space>
</ChildContent>
</ActionColumn>
</Table>
@code {
[Parameter] public Guid Id { get; set; }
Collection Collection;
protected override async Task OnInitializedAsync()
{
if (Id == Guid.Empty)
Collection = new Collection();
else
Collection = await CollectionService.Get(Id);
}
private async Task Save()
{
try
{
if (Collection.Id != Guid.Empty)
{
Collection = await CollectionService.Update(Collection);
await MessageService.Success("Collection updated!");
}
else
{
Collection = await CollectionService.Add(Collection);
NavigationManager.LocationChanged += NotifyCollectionAdded;
NavigationManager.NavigateTo($"/Collections/{Collection.Id}");
}
}
catch (Exception ex)
{
await MessageService.Error("Could not save!");
}
}
private void NotifyCollectionAdded(object? sender, LocationChangedEventArgs e)
{
NavigationManager.LocationChanged -= NotifyCollectionAdded;
MessageService.Success("Collection added!");
}
private async Task RemoveGame(Game game)
{
try
{
Collection.Games.Remove(game);
await CollectionService.Update(Collection);
}
catch (Exception ex)
{
MessageService.Error("Game could not be removed from the collection!");
}
}
private string GetIcon(Game game)
{
var media = game?.Media?.FirstOrDefault(m => m.Type == Data.Enums.MediaType.Icon);
if (media != null)
return $"/api/Media/{media.Id}/Download?fileId={media.FileId}";
else
return "/favicon.ico";
}
}

View File

@ -1,110 +0,0 @@
@page "/Collections"
@using Microsoft.EntityFrameworkCore;
@attribute [Authorize(Roles = "Administrator")]
@inject CollectionService CollectionService
@inject NavigationManager NavigationManager
@inject IMessageService MessageService
<PageHeader Title="Collections">
<PageHeaderExtra>
<Space Direction="DirectionVHType.Horizontal">
<SpaceItem>
<Search Placeholder="Search" @bind-Value="Search" BindOnInput DebounceMilliseconds="150" OnChange="() => LoadData()" />
</SpaceItem>
</Space>
</PageHeaderExtra>
</PageHeader>
<TableColumnPicker @ref="Picker" Key="Collections" @bind-Visible="ColumnPickerVisible" />
<Table TItem="Collection" DataSource="@Collections" Loading="@Loading" PageSize="25" Responsive>
<PropertyColumn Property="r => r.Name" Sortable Hidden="@(Picker.IsColumnHidden("Name"))" />
<PropertyColumn Property="s => s.CreatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable Hidden="@(Picker.IsColumnHidden("Created On"))" />
<PropertyColumn Property="s => s.CreatedBy" Sortable Hidden="@(Picker.IsColumnHidden("Created By"))">
@context.CreatedBy?.UserName
</PropertyColumn>
<PropertyColumn Property="g => g.UpdatedOn" Format="MM/dd/yyyy hh:mm tt" Sortable Hidden="@(Picker.IsColumnHidden("Updated On"))" />
<PropertyColumn Property="g => g.UpdatedBy" Sortable Hidden="@(Picker.IsColumnHidden("Updated By"))">
@context.UpdatedBy?.UserName
</PropertyColumn>
<Column Title="Games" TData="int">
@context.Games.Count
</Column>
<ActionColumn Title="" Style="text-align: right; white-space: nowrap">
<TitleTemplate>
<div style="text-align: right">
<Button Icon="@IconType.Outline.Edit" Type="@ButtonType.Text" OnClick="() => OpenColumnPicker()" />
</div>
</TitleTemplate>
<ChildContent>
<Space Direction="DirectionVHType.Horizontal">
<SpaceItem>
<a href="/Collections/@(context.Id)" class="ant-btn ant-btn-primary">Edit</a>
</SpaceItem>
<SpaceItem>
<Popconfirm OnConfirm="() => Delete(context)" Title="Are you sure you want to delete this Collection?">
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
</Popconfirm>
</SpaceItem>
</Space>
</ChildContent>
</ActionColumn>
</Table>
@code {
IEnumerable<Collection> Collections { get; set; } = new List<Collection>();
bool Loading = true;
string Search = "";
TableColumnPicker Picker;
bool ColumnPickerVisible = false;
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
LoadData();
Loading = false;
StateHasChanged();
}
}
private async Task LoadData()
{
var fuzzySearch = Search.ToLower().Trim();
Collections = await CollectionService.Get(r => r.Name.ToLower().Contains(fuzzySearch)).OrderBy(r => r.Name).ToListAsync();
}
private void Add()
{
NavigationManager.NavigateTo("/Collections/Add");
}
private async Task Delete(Collection Collection)
{
Collections = new List<Collection>();
Loading = true;
await CollectionService.Delete(Collection);
Collections = await CollectionService.Get(x => true).OrderBy(r => r.Name).ToListAsync();
Loading = false;
}
private async Task OpenColumnPicker()
{
ColumnPickerVisible = true;
}
private async Task CloseColumnPicker()
{
ColumnPickerVisible = false;
}
}

View File

@ -0,0 +1,94 @@
@using System.Diagnostics;
@using LANCommander.Extensions;
@using AntDesign.Charts;
@using System.Collections.Concurrent;
<Spin Spinning="Loading">
<Area @ref="Chart" Config="Config" />
</Spin>
@code {
[Parameter] public int TimerHistory { get; set; }
[Parameter] public int TimerInterval { get; set; }
IChartComponent? Chart;
System.Timers.Timer Timer;
bool Loading = true;
Dictionary<string, double[]> Data = new Dictionary<string, double[]>();
ConcurrentDictionary<string, PerformanceCounter> PerformanceCounters = new ConcurrentDictionary<string, PerformanceCounter>();
string JsConfig = @"{
meta: {
value: {
alias: 'Speed',
formatter: (v) => humanFileSize(v, true) + '/s'
}
}
}";
AreaConfig Config = new AreaConfig
{
Name = "Network Download Rate",
Padding = "auto",
SeriesField = "series",
YField = "value",
XField = "index",
Animation = false,
XAxis = new ValueCatTimeAxis
{
Visible = false
}
};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if (Timer == null)
{
Timer = new System.Timers.Timer();
Timer.Interval = TimerInterval;
Timer.Elapsed += async (s, e) =>
{
await RefreshData();
};
}
await Chart.UpdateChart(Config, null, null, JsConfig);
Timer.Start();
Loading = false;
StateHasChanged();
}
}
private async Task RefreshData()
{
#if WINDOWS
var category = new PerformanceCounterCategory("Network Interface");
foreach (var instance in category.GetInstanceNames())
{
if (!Data.ContainsKey(instance))
Data[instance] = new double[TimerHistory];
if (!PerformanceCounters.ContainsKey(instance))
PerformanceCounters[instance] = new PerformanceCounter("Network Interface", "Bytes Received/sec", instance);
Data[instance] = Data[instance].ShiftArrayAndInsert((double)PerformanceCounters[instance].NextValue(), TimerHistory);
}
try
{
await Chart.ChangeData(Data.SelectMany(x => x.Value.Select((y, i) => new { value = y, index = i, series = x.Key })), true);
}
catch { }
#endif
}
}

View File

@ -0,0 +1,93 @@
@using System.Diagnostics;
@using LANCommander.Extensions;
@using AntDesign.Charts;
@using System.Collections.Concurrent;
<Spin Spinning="Loading">
<Area @ref="Chart" Config="Config" />
</Spin>
@code {
[Parameter] public int TimerHistory { get; set; }
[Parameter] public int TimerInterval { get; set; }
IChartComponent? Chart;
System.Timers.Timer Timer;
bool Loading = true;
Dictionary<string, double[]> Data = new Dictionary<string, double[]>();
ConcurrentDictionary<string, PerformanceCounter> PerformanceCounters = new ConcurrentDictionary<string, PerformanceCounter>();
string JsConfig = @"{
meta: {
value: {
alias: 'Speed',
formatter: (v) => humanFileSize(v, true) + '/s'
}
}
}";
AreaConfig Config = new AreaConfig
{
Name = "Network Upload Rate",
Padding = "auto",
SeriesField = "series",
YField = "value",
XField = "index",
Animation = false,
XAxis = new ValueCatTimeAxis
{
Visible = false
}
};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if (Timer == null)
{
Timer = new System.Timers.Timer();
Timer.Interval = TimerInterval;
Timer.Elapsed += async (s, e) =>
{
await RefreshData();
};
}
await Chart.UpdateChart(Config, null, null, JsConfig);
Timer.Start();
Loading = false;
StateHasChanged();
}
}
private async Task RefreshData()
{
#if WINDOWS
var category = new PerformanceCounterCategory("Network Interface");
foreach (var instance in category.GetInstanceNames())
{
if (!Data.ContainsKey(instance))
Data[instance] = new double[TimerHistory];
if (!PerformanceCounters.ContainsKey(instance))
PerformanceCounters[instance] = new PerformanceCounter("Network Interface", "Bytes Sent/sec", instance);
Data[instance] = Data[instance].ShiftArrayAndInsert((double)PerformanceCounters[instance].NextValue(), TimerHistory);
}
try
{
await Chart.ChangeData(Data.SelectMany(x => x.Value.Select((y, i) => new { value = y, index = i, series = x.Key })), true);
}
catch { }
#endif
}
}

View File

@ -1,65 +0,0 @@
@using AntDesign.Charts
@using ByteSizeLib
@inject PlaySessionService PlaySessionService
<Spin Spinning="Loading">
<Pie Data="Data" Config="Config" JsConfig="@JsConfig" />
</Spin>
@code {
object[] Data;
bool Loading = true;
string JsConfig = @"{
meta: {
value: {
alias: 'Overall Playtime',
formatter: (v) => new Date(v * 1000).toISOString().slice(11, 19)
}
},
label: {
visible: true,
type: 'outer-center'
}
}";
PieConfig Config = new PieConfig
{
Radius = 0.8,
AngleField = "value",
ColorField = "type",
};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
Dictionary<string, TimeSpan> playtimes = new Dictionary<string, TimeSpan>();
var sessions = await PlaySessionService.Get();
foreach (var gameSessions in sessions.Where(s => s.GameId.HasValue && s.GameId.Value != Guid.Empty).GroupBy(s => s.GameId))
{
var total = new TimeSpan();
foreach (var session in gameSessions.Where(gs => gs.Start != null && gs.End != null))
{
total = total.Add(session.End.Value.Subtract(session.Start.Value));
}
playtimes[gameSessions.First().Game.Title] = total;
}
Data = playtimes.Select(pt => new
{
type = pt.Key,
value = (int)pt.Value.TotalSeconds
}).ToArray();
Loading = false;
StateHasChanged();
}
}
}

View File

@ -0,0 +1,85 @@
@using System.Diagnostics;
@using LANCommander.Extensions;
@using AntDesign.Charts;
<Spin Spinning="Loading">
<Area @ref="Chart" Config="Config" />
</Spin>
@code {
[Parameter] public int TimerHistory { get; set; }
[Parameter] public int TimerInterval { get; set; }
IChartComponent? Chart;
System.Timers.Timer Timer;
bool Loading = true;
double[] Data;
PerformanceCounter PerformanceCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
string JsConfig = @"{
meta: {
value: {
alias: '% Usage',
formatter: (v) => v + '%'
}
}
}";
AreaConfig Config = new AreaConfig
{
Name = "Processor Utilization",
Padding = "auto",
YField = "value",
XField = "index",
Animation = false,
IsPercent = true,
YAxis = new ValueAxis
{
Min = 0,
Max = 100
},
XAxis = new ValueCatTimeAxis
{
Visible = false
}
};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
if (Timer == null)
{
Timer = new System.Timers.Timer();
Timer.Interval = TimerInterval;
Timer.Elapsed += async (s, e) =>
{
await RefreshData();
};
}
await Chart.UpdateChart(Config, null, null, JsConfig);
Timer.Start();
Loading = false;
StateHasChanged();
}
}
private async Task RefreshData()
{
#if WINDOWS
Data = Data.ShiftArrayAndInsert((double)Math.Ceiling(PerformanceCounter.NextValue()), TimerHistory);
try
{
await Chart.ChangeData(Data.Select((x, i) => new { value = x, index = i }), true);
}
catch { }
#endif
}
}

View File

@ -7,9 +7,25 @@
<GridRow Gutter="(16, 16)">
<GridCol Xs="24" Md="12">
<Card Title="Overall Playtime">
<Card Title="Network Download Rate">
<Body>
<OverallPlaytime />
<NetworkDownloadRate TimerHistory="60" TimerInterval="1000" />
</Body>
</Card>
</GridCol>
<GridCol Xs="24" Md="12">
<Card Title="Network Upload Rate">
<Body>
<NetworkUploadRate TimerHistory="60" TimerInterval="1000" />
</Body>
</Card>
</GridCol>
<GridCol Xs="24" Md="12">
<Card Title="CPU Usage (%)">
<Body>
<ProcessorUtilization TimerHistory="60" TimerInterval="1000" />
</Body>
</Card>
</GridCol>

View File

@ -12,7 +12,7 @@
<Input Type="text" @bind-Value="context.Name" />
</PropertyColumn>
<PropertyColumn Property="a => a.Path">
<FilePicker @bind-Value="context.Path" ArchiveId="@ArchiveId" AllowDirectories="true" Prefix="{InstallDir}\" Title="Select Action Executable" />
<FilePicker @bind-Value="context.Path" ArchiveId="@ArchiveId" AllowDirectories="true" />
</PropertyColumn>
<PropertyColumn Property="a => a.Arguments">
<Input Type="text" @bind-Value="context.Arguments" />
@ -90,6 +90,43 @@
Move(action.SortOrder, action.SortOrder + 1);
}
private async void BrowseForActionPath(Data.Models.Action action)
{
var modalOptions = new ModalOptions()
{
Title = "Choose Action Executable",
Maximizable = false,
DefaultMaximized = true,
Closable = true,
OkText = "Select File"
};
var browserOptions = new FilePickerOptions()
{
ArchiveId = ArchiveId,
Select = true,
Multiple = false
};
var modalRef = await ModalService.CreateModalAsync<FilePickerDialog, FilePickerOptions, IEnumerable<IFileManagerEntry>>(modalOptions, browserOptions);
modalRef.OnOk = (results) =>
{
action.Path = results.FirstOrDefault().Path;
var parts = action.Path.Split('/');
if (parts.Length > 1)
{
action.Path = parts.Last();
action.WorkingDirectory = "{InstallDir}/" + String.Join('/', parts.Take(parts.Length - 1));
}
StateHasChanged();
return Task.CompletedTask;
};
}
private void Move(int oldIndex, int newIndex)
{
foreach (var action in Actions)

View File

@ -1,107 +0,0 @@
@using LANCommander.Models
@inherits FeedbackComponent<AddToCollectionOptions, Collection>
@inject CollectionService CollectionService
@inject GameService GameService
@inject IMessageService MessageService
<Select
TItem="Collection"
TItemValue="Guid"
DataSource="@Collections"
@bind-Value="SelectedCollection"
LabelName="@nameof(Collection.Name)"
ValueName="@nameof(Collection.Id)"
Placeholder="Select a Collection"
DropdownRender="@DropdownRender"
OnSelectedItemChanged="OnSelectedItemChanged" />
@code {
ICollection<Collection> Collections = new List<Collection>();
Guid SelectedCollection;
string NewCollectionName;
protected override async Task OnInitializedAsync()
{
await LoadData();
}
private async Task LoadData()
{
Collections = (await CollectionService.Get()).OrderBy(c => c.Name).ToList();
}
private RenderFragment DropdownRender(RenderFragment originNode)
{
RenderFragment customDropdownRender =
@<Template>
<div>
@originNode
<Divider Style="margin: 4px 0"></Divider>
<div style="display: flex; flex-wrap: nowrap; padding: 8px">
<Input Style="flex: auto" @bind-Value="@NewCollectionName" />
<a style="flex: none; padding: 8px; display: block; cursor: pointer" @onclick="AddCollection">
<Icon Type="plus" Theme="outline"></Icon>
Add New Collection
</a>
</div>
</div>
</Template>
;
return customDropdownRender;
}
private async Task AddCollection(MouseEventArgs args)
{
try
{
if (!String.IsNullOrWhiteSpace(NewCollectionName))
{
await CollectionService.Add(new Collection()
{
Name = NewCollectionName
});
await LoadData();
MessageService.Success("Collection added!");
}
}
catch (Exception ex)
{
MessageService.Error("Could not add a new collection!");
}
}
private void OnSelectedItemChanged(Collection collection)
{
SelectedCollection = collection.Id;
}
public override async Task OnFeedbackOkAsync(ModalClosingEventArgs args)
{
var collection = await CollectionService.Get(SelectedCollection);
try
{
foreach (var gameId in Options.GameIds.Where(gid => collection.Games != null && !collection.Games.Any(g => g.Id == gid)))
{
var game = await GameService.Get(gameId);
collection.Games.Add(game);
}
await CollectionService.Update(collection);
MessageService.Success("Added to collection!");
}
catch (Exception ex)
{
MessageService.Error("Could not add to collection!");
}
await base.OkCancelRefWithResult!.OnOk(collection);
}
}

View File

@ -161,7 +161,6 @@ else
[Parameter] public Guid Id { get; set; }
[Parameter] public string Panel { get; set; }
bool Loaded = false;
bool Success;
string[] Errors = { };
@ -207,13 +206,8 @@ else
});
} }
protected override async Task OnParametersSetAsync()
protected override async Task OnInitializedAsync()
{
if (!Loaded)
await LoadData();
}
private async Task LoadData() {
if (Id == Guid.Empty)
Game = new Game();
else
@ -229,8 +223,6 @@ else
Description = r.Description,
Key = r.Id.ToString()
});
Loaded = true;
}
private async Task Save()

View File

@ -2,28 +2,18 @@
@using AntDesign.TableModels;
@using LANCommander.Extensions;
@using System.ComponentModel.DataAnnotations;
@using LANCommander.Models
@using LANCommander.Pages.Games.Components
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
@using Microsoft.EntityFrameworkCore;
@using System.Web
@attribute [Authorize]
@inject GameService GameService
@inject NavigationManager NavigationManager
@inject ModalService ModalService
@inject IMessageService MessageService
<PageHeader Title="Games" Subtitle="@Games.Count().ToString()">
<PageHeader Title="Games">
<PageHeaderExtra>
<Space Direction="DirectionVHType.Horizontal">
@if (Selected != null && Selected.Count() > 0)
{
<SpaceItem>
<Button OnClick="() => AddToCollection()" Type="@ButtonType.Primary">Add to Collection</Button>
</SpaceItem>
}
<SpaceItem>
<Search Placeholder="Search" @bind-Value="Search" BindOnInput DebounceMilliseconds="250" OnChange="SearchChanged" />
<Search Placeholder="Search" @bind-Value="Search" BindOnInput DebounceMilliseconds="150" OnChange="() => LoadData()" />
</SpaceItem>
<SpaceItem>
<Button OnClick="() => Add()" Type="@ButtonType.Primary">Add Game</Button>
@ -34,8 +24,7 @@
<TableColumnPicker @ref="Picker" Key="Games" @bind-Visible="ColumnPickerVisible" />
<Table TItem="Game" DataSource="@Games" @bind-SelectedRows="Selected" Loading="@Loading" PageSize="@PageSize" PageIndex="@PageIndex" OnPageIndexChange="PageIndexChanged" OnPageSizeChange="PageSizeChanged" Responsive>
<Selection Key="@(context.Id.ToString())" />
<Table TItem="Game" DataSource="@Games" Loading="@Loading" PageSize="25" Responsive>
<Column TData="string" Title="Icon" Hidden="@(Picker.IsColumnHidden("Icon"))">
<Image Src="@GetIcon(context)" Height="32" Width="32" Preview="false"></Image>
</Column>
@ -132,69 +121,27 @@
bool Loading = true;
string Search = "";
string Url;
bool Visibility = false;
IEnumerable<Game> Selected;
TableColumnPicker Picker;
bool ColumnPickerVisible = false;
int PageIndex = 1;
int PageSize = 25;
protected override async Task OnInitializedAsync()
protected override async Task OnAfterRenderAsync(bool firstRender)
{
Url = NavigationManager.Uri;
NavigationManager.LocationChanged += LocationChanged;
LoadTableParameter();
await LoadData();
if (firstRender)
{
LoadData();
Loading = false;
StateHasChanged();
}
}
private async Task LoadData()
{
Games = await GameService.Get(g => g.Title.ToLower().Contains(Search.ToLower().Trim()) || g.SortTitle.ToLower().Contains(Search.ToLower().Trim())).OrderBy(g => String.IsNullOrWhiteSpace(g.SortTitle) ? g.Title : g.SortTitle).ToListAsync();
await InvokeAsync(StateHasChanged);
}
private async void LocationChanged(object sender, LocationChangedEventArgs e)
{
Url = e.Location;
LoadTableParameter();
await LoadData();
}
private void LoadTableParameter()
{
var uri = NavigationManager.ToAbsoluteUri(Url);
var query = HttpUtility.ParseQueryString(uri.Query);
PageIndex = int.TryParse(query["Page"], out var index) ? index > 0 ? index : 1 : 1;
PageSize = int.TryParse(query["Size"], out var size) ? size > 0 ? size : 25 : 25;
if (query["Search"] != null)
Search = query["Search"];
else
Search = "";
}
private void PageIndexChanged(PaginationEventArgs args)
{
NavigationManager.NavigateTo($"Games?Page={args.Page}&Size={args.PageSize}{(Search != "" ? "&Search=" + Search : "")}");
}
private void PageSizeChanged(PaginationEventArgs args)
{
NavigationManager.NavigateTo($"Games?Page={args.Page}&Size={args.PageSize}{(Search != "" ? "&Search=" + Search : "")}");
}
private void SearchChanged()
{
NavigationManager.NavigateTo($"Games?Search={Search}");
}
private string GetIcon(Game game)
@ -242,31 +189,6 @@
Loading = false;
}
private async void AddToCollection()
{
var modalOptions = new ModalOptions()
{
Title = "Add to Collection",
Maximizable = false,
DefaultMaximized = false,
Closable = true,
OkText = "Add"
};
var options = new AddToCollectionOptions()
{
GameIds = Selected.Select(g => g.Id)
};
var modalRef = await ModalService.CreateModalAsync<AddToCollectionDialog, AddToCollectionOptions, Collection>(modalOptions, options);
modalRef.OnOk = async (collection) =>
{
Selected = null;
await LoadData();
};
}
private async Task OpenColumnPicker()
{
ColumnPickerVisible = true;
@ -276,9 +198,4 @@
{
ColumnPickerVisible = false;
}
public void Dispose()
{
NavigationManager.LocationChanged -= LocationChanged;
}
}

View File

@ -1,144 +0,0 @@
@page "/Settings/Roles"
@using LANCommander.Models;
@layout SettingsLayout
@inject RoleManager<Role> RoleManager
@inject UserManager<User> UserManager
@inject IMessageService MessageService
@inject NavigationManager NavigationManager
@attribute [Authorize(Roles = "Administrator")]
<PageHeader Title="Roles" Subtitle="@Roles.Count().ToString()">
<PageHeaderExtra>
<Space Direction="DirectionVHType.Horizontal">
<SpaceItem>
<Button OnClick="() => ShowNewRoleDialog()" Type="@ButtonType.Primary">Add Role</Button>
</SpaceItem>
</Space>
</PageHeaderExtra>
</PageHeader>
<div style="padding: 0 24px;">
<Table TItem="RoleViewModel" DataSource="@Roles" Loading="@(Loading)" Responsive>
<PropertyColumn Property="r => r.Name" Title="Name" />
<PropertyColumn Property="r => r.Collections" Title="Collections" />
<PropertyColumn Property="r => r.Users" Title="Users" />
<ActionColumn>
<Space Style="display: flex; justify-content: end">
<SpaceItem>
@if (context.Name != "Administrator")
{
<Popconfirm OnConfirm="() => DeleteRole(context)" Title="Are you sure you want to delete this role?">
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
</Popconfirm>
}
else
{
<Tooltip Title="The administrator role cannot be deleted.">
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Disabled />
</Tooltip>
}
</SpaceItem>
</Space>
</ActionColumn>
</Table>
</div>
<Modal Title="Add a Role" @bind-Visible="AddRoleDialogVisible" OnOk="AddRole" OnCancel="() => AddRoleDialogVisible = false">
<Form Model="NewRole">
<FormItem Label="Name">
<Input @bind-Value="@context.Name" />
</FormItem>
</Form>
</Modal>
@code {
ICollection<RoleViewModel> Roles { get; set; }
LANCommanderSettings Settings = SettingService.GetSettings();
bool Loading = true;
bool AddRoleDialogVisible = false;
RoleViewModel NewRole = new RoleViewModel();
protected override async Task OnInitializedAsync()
{
Roles = new List<RoleViewModel>();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
await LoadData();
}
private async Task LoadData()
{
Roles = new List<RoleViewModel>();
foreach (var role in RoleManager.Roles)
{
var users = await UserManager.GetUsersInRoleAsync(role.Name);
Roles.Add(new RoleViewModel()
{
Name = role.Name,
Collections = role.Collections != null ? role.Collections.Count : 0,
Users = users != null ? users.Count : 0
});
}
Loading = false;
StateHasChanged();
}
private async Task DeleteRole(RoleViewModel roleViewModel)
{
var role = await RoleManager.FindByNameAsync(roleViewModel.Name);
if (role.Name == "Administrator")
{
await MessageService.Error("Cannot delete the administrator role!");
}
else
{
await RoleManager.DeleteAsync(role);
await LoadData();
await MessageService.Success($"Deleted {role.Name}!");
}
}
private void ShowNewRoleDialog()
{
NewRole = new RoleViewModel();
AddRoleDialogVisible = true;
}
private async Task AddRole()
{
if (await RoleManager.RoleExistsAsync(NewRole.Name))
{
MessageService.Error("A role with that name already exists!");
AddRoleDialogVisible = false;
return;
}
try
{
await RoleManager.CreateAsync(new Role()
{
Name = NewRole.Name
});
await LoadData();
MessageService.Success("Role added!");
}
catch (Exception ex)
{
MessageService.Error("Could not added role!");
}
}
}

View File

@ -7,7 +7,6 @@
<Menu Mode=@MenuMode.Inline Style="height: 100%">
<MenuItem RouterLink="/Settings/General">General</MenuItem>
<MenuItem RouterLink="/Settings/Users">Users</MenuItem>
<MenuItem RouterLink="/Settings/Roles">Roles</MenuItem>
<MenuItem RouterLink="/Settings/Authentication">Authentication</MenuItem>
<MenuItem RouterLink="/Settings/UserSaves">User Saves</MenuItem>
<MenuItem RouterLink="/Settings/Archives">Archives</MenuItem>

View File

@ -40,7 +40,7 @@
<SpaceItem>
<Tooltip Title="Change Password">
<Button Icon="@IconType.Outline.Lock" Type="@ButtonType.Text" OnClick="() => ChangePassword(context)" />
<Button Icon="@IconType.Outline.Key" Type="@ButtonType.Text" OnClick="() => ChangePassword(context)" />
</Tooltip>
</SpaceItem>

View File

@ -133,7 +133,6 @@ namespace LANCommander
builder.Services.AddScoped<SettingService>();
builder.Services.AddScoped<ArchiveService>();
builder.Services.AddScoped<CategoryService>();
builder.Services.AddScoped<CollectionService>();
builder.Services.AddScoped<GameService>();
builder.Services.AddScoped<ScriptService>();
builder.Services.AddScoped<GenreService>();

View File

@ -1,12 +0,0 @@
using LANCommander.Data;
using LANCommander.Data.Models;
namespace LANCommander.Services
{
public class CollectionService : BaseDatabaseService<Collection>
{
public CollectionService(DatabaseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
{
}
}
}

View File

@ -9,7 +9,6 @@
@if (User != null && User.IsInRole("Administrator"))
{
<MenuItem RouterLink="/Games">Games</MenuItem>
<MenuItem RouterLink="/Collections">Collections</MenuItem>
<MenuItem RouterLink="/Redistributables">Redistributables</MenuItem>
<MenuItem RouterLink="/Servers">Servers</MenuItem>
<MenuItem RouterLink="/Files">Files</MenuItem>

View File

@ -1,2 +1,2 @@
# Bounds are accessible by $Display.Bounds.Width and $Display.Bounds.Height
# Bounds are accessible by $Display.Width and $Display.Height
$Display = Get-PrimaryDisplay

View File

@ -1,2 +1,2 @@
# Use regex to replace text within a file. Quotes are escaped by double quoting ("")
Write-ReplaceContentInFile -Pattern '^game.setPlayerName "(.+)"' -Substitution "game.setPlayerName ""$NewPlayerAlias""" -FilePath "$InstallDirectory\<File Path>"
Write-ReplaceContentInFile -Regex '^game.setPlayerName "(.+)"' -Replacement "game.setPlayerName ""$NewName""" -FilePath "$InstallDir\<File Path>"

View File

@ -18,11 +18,6 @@
background: #141414;
}
.ant-page-header-heading-title {
padding-bottom: 4px;
line-height: 26px;
}
label.ant-btn-icon-only {
display: inline-flex;
align-items: center;