diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml index 04efe1e..3bd4f83 100644 --- a/.github/workflows/development.yml +++ b/.github/workflows/development.yml @@ -25,7 +25,7 @@ jobs: azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_CALM_MUD_04916B210 }} repo_token: ${{ secrets.GITHUB_TOKEN }} action: "upload" - app_location: "IGP" + app_location: "Web" api_location: "" output_location: "./wwwroot" diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index fa90e0d..19e9ac6 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -25,7 +25,7 @@ jobs: azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_NICE_COAST_0F8B08010 }} repo_token: ${{ secrets.GITHUB_TOKEN }} action: "upload" - app_location: "IGP" + app_location: "Web" api_location: "" output_location: "./wwwroot" diff --git a/IGP/Localizations.properties b/.junie/memory/errors.md similarity index 100% rename from IGP/Localizations.properties rename to .junie/memory/errors.md diff --git a/.junie/memory/feedback.md b/.junie/memory/feedback.md new file mode 100644 index 0000000..e69de29 diff --git a/IGP/wwwroot/generated/NoteConnectionModels.json b/.junie/memory/language.json similarity index 100% rename from IGP/wwwroot/generated/NoteConnectionModels.json rename to .junie/memory/language.json diff --git a/.junie/memory/memory.version b/.junie/memory/memory.version new file mode 100644 index 0000000..f398a20 --- /dev/null +++ b/.junie/memory/memory.version @@ -0,0 +1 @@ +3.0 \ No newline at end of file diff --git a/.junie/memory/tasks.md b/.junie/memory/tasks.md new file mode 100644 index 0000000..e69de29 diff --git a/.vscode/tasks.json b/.vscode/tasks.json index eb03bb5..a97606d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/IGP/IGP.csproj", + "${workspaceFolder}/Web/Web.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -19,7 +19,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/IGP/IGP.csproj", + "${workspaceFolder}/Web/Web.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -33,7 +33,7 @@ "watch", "run", "--project", - "${workspaceFolder}/IGP/IGP.csproj" + "${workspaceFolder}/Web/Web.csproj" ], "problemMatcher": "$msCompile" } diff --git a/CLI/CLI.csproj b/CLI/CLI.csproj new file mode 100644 index 0000000..c9cdcb2 --- /dev/null +++ b/CLI/CLI.csproj @@ -0,0 +1,16 @@ + + + + Exe + net10.0 + enable + enable + IGP.Calculator.Cli + + + + + + + + diff --git a/IGP.Calculator.Cli/Program.cs b/CLI/Program.cs similarity index 98% rename from IGP.Calculator.Cli/Program.cs rename to CLI/Program.cs index 6f0d493..d399566 100644 --- a/IGP.Calculator.Cli/Program.cs +++ b/CLI/Program.cs @@ -1,9 +1,8 @@ +using IGP.Calculator.Cli.Services; using Model.Entity; using Model.Entity.Data; -using Services; using Services.Immortal; using Services.Website; -using IGP.Calculator.Cli.Services; var faction = DataType.FACTION_QRath; var immortal = DataType.IMMORTAL_Orzum; @@ -11,7 +10,6 @@ var attackTime = 1500; var entityNames = new List(); for (var i = 0; i < args.Length; i++) -{ switch (args[i].ToLower()) { case "--faction" when i + 1 < args.Length: @@ -48,7 +46,6 @@ for (var i = 0; i < args.Length; i++) entityNames.Add(args[i]); break; } -} var toastService = new ToastService(); var storageService = new NullStorageService(); @@ -124,12 +121,12 @@ var finalEconomy = economyService.GetEconomy(timingService.GetAttackTime()); var lastEconomy = economyService.GetEconomy(lastInterval); Console.WriteLine($"Army Attacking At: {timingService.GetAttackTime()}s"); -Console.WriteLine($""); +Console.WriteLine(""); Console.WriteLine($"At attack time ({timingService.GetAttackTime()}s):"); Console.WriteLine($" Alloy: {finalEconomy.Alloy,10:F1}"); Console.WriteLine($" Ether: {finalEconomy.Ether,10:F1}"); Console.WriteLine($" Pyre: {finalEconomy.Pyre,10:F1}"); -Console.WriteLine($""); +Console.WriteLine(""); Console.WriteLine($"At last build action ({lastInterval}s):"); Console.WriteLine($" Alloy: {lastEconomy.Alloy,10:F1}"); Console.WriteLine($" Ether: {lastEconomy.Ether,10:F1}"); @@ -155,4 +152,4 @@ static EntityModel? FindEntity(string name, string faction, string immortal) if (vanguardMatch != null) return vanguardMatch; return candidates.FirstOrDefault(e => e.VanguardAdded() == null); -} +} \ No newline at end of file diff --git a/IGP.Calculator.Cli/Services/NullStorageService.cs b/CLI/Services/NullStorageService.cs similarity index 71% rename from IGP.Calculator.Cli/Services/NullStorageService.cs rename to CLI/Services/NullStorageService.cs index 76a4115..496162e 100644 --- a/IGP.Calculator.Cli/Services/NullStorageService.cs +++ b/CLI/Services/NullStorageService.cs @@ -6,8 +6,13 @@ public class NullStorageService : IStorageService { private readonly Dictionary _store = new(); - public void Subscribe(Action action) { } - public void Unsubscribe(Action action) { } + public void Subscribe(Action action) + { + } + + public void Unsubscribe(Action action) + { + } public T GetValue(string forKey) { @@ -21,5 +26,8 @@ public class NullStorageService : IStorageService _store[key] = value; } - public Task Load() => Task.CompletedTask; -} + public Task Load() + { + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Components/Components.csproj b/Components/Components.csproj index 2e69dd8..1da8a21 100644 --- a/Components/Components.csproj +++ b/Components/Components.csproj @@ -4,6 +4,7 @@ net10.0 enable enable + Components @@ -29,8 +30,8 @@ - - + + diff --git a/Components/Form/FormGuessComponent.razor b/Components/Form/FormGuessComponent.razor index 940c923..08dc4ac 100644 --- a/Components/Form/FormGuessComponent.razor +++ b/Components/Form/FormGuessComponent.razor @@ -13,7 +13,7 @@ }
- - - Exe - net10.0 - enable - enable - IGP.Calculator.Cli - - - - - - - - diff --git a/IGP.sln b/IGP.sln new file mode 100644 index 0000000..e2caf1f --- /dev/null +++ b/IGP.sln @@ -0,0 +1,107 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32112.339 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{F4D758C2-349F-49F2-86E2-7DAB2B53BB61}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Services\Services.csproj", "{4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "Web\Web.csproj", "{4A54E237-4FF6-4459-91D9-9249AE3E72E0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLI", "CLI\CLI.csproj", "{F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Components", "Components\Components.csproj", "{C0ACFFEB-8098-4119-9C28-3A4D671C2514}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{1460CB4C-7E8E-41F0-8DF2-174C69A3E366}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Debug|x64.ActiveCfg = Debug|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Debug|x64.Build.0 = Debug|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Debug|x86.ActiveCfg = Debug|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Debug|x86.Build.0 = Debug|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Release|Any CPU.Build.0 = Release|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Release|x64.ActiveCfg = Release|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Release|x64.Build.0 = Release|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Release|x86.ActiveCfg = Release|Any CPU + {F4D758C2-349F-49F2-86E2-7DAB2B53BB61}.Release|x86.Build.0 = Release|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Debug|x64.ActiveCfg = Debug|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Debug|x64.Build.0 = Debug|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Debug|x86.ActiveCfg = Debug|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Debug|x86.Build.0 = Debug|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Release|Any CPU.Build.0 = Release|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Release|x64.ActiveCfg = Release|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Release|x64.Build.0 = Release|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Release|x86.ActiveCfg = Release|Any CPU + {4F56F39D-D34C-4987-8C3F-3A8E03A2D7E6}.Release|x86.Build.0 = Release|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Debug|x64.ActiveCfg = Debug|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Debug|x64.Build.0 = Debug|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Debug|x86.ActiveCfg = Debug|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Debug|x86.Build.0 = Debug|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Release|Any CPU.Build.0 = Release|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Release|x64.ActiveCfg = Release|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Release|x64.Build.0 = Release|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Release|x86.ActiveCfg = Release|Any CPU + {4A54E237-4FF6-4459-91D9-9249AE3E72E0}.Release|x86.Build.0 = Release|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Debug|x64.ActiveCfg = Debug|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Debug|x64.Build.0 = Debug|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Debug|x86.ActiveCfg = Debug|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Debug|x86.Build.0 = Debug|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Release|Any CPU.Build.0 = Release|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Release|x64.ActiveCfg = Release|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Release|x64.Build.0 = Release|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Release|x86.ActiveCfg = Release|Any CPU + {F8A23FFE-7FCC-4C28-B5CF-DBE435284AFA}.Release|x86.Build.0 = Release|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Debug|x64.ActiveCfg = Debug|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Debug|x64.Build.0 = Debug|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Debug|x86.ActiveCfg = Debug|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Debug|x86.Build.0 = Debug|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Release|Any CPU.Build.0 = Release|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Release|x64.ActiveCfg = Release|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Release|x64.Build.0 = Release|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Release|x86.ActiveCfg = Release|Any CPU + {C0ACFFEB-8098-4119-9C28-3A4D671C2514}.Release|x86.Build.0 = Release|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Debug|x64.ActiveCfg = Debug|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Debug|x64.Build.0 = Debug|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Debug|x86.ActiveCfg = Debug|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Debug|x86.Build.0 = Debug|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Release|Any CPU.Build.0 = Release|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Release|x64.ActiveCfg = Release|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Release|x64.Build.0 = Release|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Release|x86.ActiveCfg = Release|Any CPU + {1460CB4C-7E8E-41F0-8DF2-174C69A3E366}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {19100811-B909-4D20-9AE0-2EB579A55B3A} + EndGlobalSection +EndGlobal diff --git a/IGP/IGP.sln b/IGP/IGP.sln deleted file mode 100644 index 8694309..0000000 --- a/IGP/IGP.sln +++ /dev/null @@ -1,93 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32112.339 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IGP", "IGP.csproj", "{172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "..\Model\Model.csproj", "{77395F7A-BE93-470C-9F10-F48FFA445B63}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components", "..\Components\Components.csproj", "{0419E7CD-0971-4A56-A61F-C090DF60FAF6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Services", "..\Services\Services.csproj", "{621178C8-4E8B-478E-80E5-7478F0E7B67E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IGP.Calculator.Cli", "..\IGP.Calculator.Cli\IGP.Calculator.Cli.csproj", "{9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Debug|x64.ActiveCfg = Debug|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Debug|x64.Build.0 = Debug|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Debug|x86.ActiveCfg = Debug|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Debug|x86.Build.0 = Debug|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Release|Any CPU.Build.0 = Release|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Release|x64.ActiveCfg = Release|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Release|x64.Build.0 = Release|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Release|x86.ActiveCfg = Release|Any CPU - {172D35E4-8E7B-40D1-96D6-BE2A2043CFCA}.Release|x86.Build.0 = Release|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Debug|Any CPU.Build.0 = Debug|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Debug|x64.ActiveCfg = Debug|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Debug|x64.Build.0 = Debug|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Debug|x86.ActiveCfg = Debug|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Debug|x86.Build.0 = Debug|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Release|Any CPU.ActiveCfg = Release|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Release|Any CPU.Build.0 = Release|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Release|x64.ActiveCfg = Release|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Release|x64.Build.0 = Release|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Release|x86.ActiveCfg = Release|Any CPU - {77395F7A-BE93-470C-9F10-F48FFA445B63}.Release|x86.Build.0 = Release|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Debug|x64.ActiveCfg = Debug|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Debug|x64.Build.0 = Debug|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Debug|x86.ActiveCfg = Debug|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Debug|x86.Build.0 = Debug|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Release|Any CPU.Build.0 = Release|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Release|x64.ActiveCfg = Release|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Release|x64.Build.0 = Release|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Release|x86.ActiveCfg = Release|Any CPU - {0419E7CD-0971-4A56-A61F-C090DF60FAF6}.Release|x86.Build.0 = Release|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Debug|x64.ActiveCfg = Debug|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Debug|x64.Build.0 = Debug|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Debug|x86.ActiveCfg = Debug|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Debug|x86.Build.0 = Debug|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Release|Any CPU.Build.0 = Release|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Release|x64.ActiveCfg = Release|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Release|x64.Build.0 = Release|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Release|x86.ActiveCfg = Release|Any CPU - {621178C8-4E8B-478E-80E5-7478F0E7B67E}.Release|x86.Build.0 = Release|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Debug|x64.ActiveCfg = Debug|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Debug|x64.Build.0 = Debug|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Debug|x86.ActiveCfg = Debug|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Debug|x86.Build.0 = Debug|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Release|Any CPU.Build.0 = Release|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Release|x64.ActiveCfg = Release|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Release|x64.Build.0 = Release|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Release|x86.ActiveCfg = Release|Any CPU - {9AA71488-E2F5-43C0-8E40-43E72DB2E3CC}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {19100811-B909-4D20-9AE0-2EB579A55B3A} - EndGlobalSection -EndGlobal diff --git a/Model/Entity/Parts/IEntityPartInterface.cs b/Model/Entity/Parts/IEntityPartInterface.cs index 0e88602..936936a 100644 --- a/Model/Entity/Parts/IEntityPartInterface.cs +++ b/Model/Entity/Parts/IEntityPartInterface.cs @@ -4,6 +4,5 @@ namespace Model.Entity.Parts; public class IEntityPartInterface { - [JsonIgnore] - public EntityModel Parent { get; set; } + [JsonIgnore] public EntityModel Parent { get; set; } } \ No newline at end of file diff --git a/Model/Model.csproj b/Model/Model.csproj index 0a5dca0..98fb82d 100644 --- a/Model/Model.csproj +++ b/Model/Model.csproj @@ -2,6 +2,7 @@ net10.0 + Model diff --git a/Playwright/debug-tab.js b/Playwright/debug-tab.js deleted file mode 100644 index 3166563..0000000 --- a/Playwright/debug-tab.js +++ /dev/null @@ -1,38 +0,0 @@ -const { chromium } = require('playwright'); -(async () => { - const browser = await chromium.launch({ headless: true }); - const page = await browser.newPage(); - await page.goto('https://calm-mud-04916b210.1.azurestaticapps.net/build-calculator', { timeout: 15000 }); - await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {}); - - await page.locator('select').nth(0).selectOption("Q'Rath"); - await page.waitForTimeout(300); - await page.locator('select').nth(1).selectOption('Orzum'); - await page.waitForTimeout(1000); - - const keys = await page.locator('.keyContainer > div > div').all(); - for (const key of keys) { - const text = await key.textContent(); - if (text && text.trim().startsWith('TAB')) { - console.log('TAB key textContent:', text.substring(0, 500)); - const innerHtml = await key.evaluate(el => el.innerHTML); - console.log('TAB key innerHTML (first 2000):', innerHtml.substring(0, 2000)); - const childDivs = await key.locator('> div').all(); - console.log('Entity div count:', childDivs.length); - for (const div of childDivs) { - const t = await div.textContent(); - const s = await div.getAttribute('style'); - console.log(' Entity:', (t || '').trim(), 'Style:', (s || 'none').substring(0, 100)); - } - } - } - - await page.locator('.keyContainer > div > div').filter({ hasText: 'TAB' }).first().click(); - await page.waitForTimeout(1000); - const entityViewName = await page.locator('.entityClickView #entityName').textContent(); - console.log('Entity view shows:', entityViewName); - const entityViewHtml = await page.locator('.entityClickView').evaluate(el => el.innerHTML.substring(0, 1000)); - console.log('Entity view HTML:', entityViewHtml); - - await browser.close(); -})().catch(e => { console.error(e.message); process.exit(1); }); diff --git a/Playwright/debug_initial_state.js b/Playwright/debug_initial_state.js deleted file mode 100644 index af77dd2..0000000 --- a/Playwright/debug_initial_state.js +++ /dev/null @@ -1,51 +0,0 @@ -const { chromium } = require('playwright'); -(async () => { - const browser = await chromium.launch({ headless: true }); - const page = await browser.newPage(); - - page.on('console', msg => { - if (msg.type() === 'error' || msg.type() === 'warning') - console.log(msg.type().toUpperCase() + ':', msg.text().substring(0, 300)); - }); - - page.on('pageerror', err => console.log('PAGE_ERR:', err.message)); - - await page.goto('http://localhost:5111/build-calculator', { timeout: 30000, waitUntil: 'load' }); - console.log('Page load event fired'); - - // Read button text immediately - let buttons = page.locator('.keyContainer > div > div'); - let count = await buttons.count(); - console.log('Button count:', count); - let qBtn = buttons.filter({ hasText: /^Q/ }).first(); - console.log('Immediate Q button text:', JSON.stringify(await qBtn.textContent())); - - // Wait for Blazor to finish initializing - look for .blazor-error-boundary or just wait - // Actually, let's poll for the button text changing from what it is now - for (let i = 0; i < 15; i++) { - await page.waitForTimeout(1000); - const text = (await buttons.nth(0).textContent() || '').trim(); - // Check all 19 buttons for Q and F keys - const allTexts = []; - for (let j = 0; j < count; j++) { - const t = (await buttons.nth(j).textContent() || '').trim(); - if (t.toUpperCase().startsWith('Q') || t.toUpperCase().startsWith('F') || t.toUpperCase().startsWith('W') || t.toUpperCase().startsWith('E')) { - allTexts.push(` B${j}: "${t.substring(0,30)}"`); - } - } - console.log(`After ${i+1}s:`); - allTexts.forEach(t => console.log(t)); - } - - // Now check what the filter is currently showing - const selects = page.locator('select'); - console.log('\nSelect values:'); - for (let s = 0; s < await selects.count(); s++) { - const val = await selects.nth(s).inputValue(); - const opts = await selects.nth(s).locator('option').allTextContents(); - const selectedIdx = await selects.nth(s).evaluate(el => el.selectedIndex); - console.log(` Select ${s}: value=${val}, selectedIndex=${selectedIdx}, options=${JSON.stringify(opts.map(o=>o.trim()))}`); - } - - await browser.close(); -})(); diff --git a/Playwright/debug_qclick.js b/Playwright/debug_qclick.js deleted file mode 100644 index a6e1eba..0000000 --- a/Playwright/debug_qclick.js +++ /dev/null @@ -1,74 +0,0 @@ -const { chromium } = require('playwright'); -(async () => { - const browser = await chromium.launch({ headless: true }); - const page = await browser.newPage(); - page.on('pageerror', err => console.log('PAGE_ERR:', err.message)); - page.on('console', msg => { - if (msg.type() === 'error') console.log('CONSOLE_ERR:', msg.text().substring(0,200)); - }); - - try { - await page.goto('http://localhost:5111/build-calculator', { timeout: 30000, waitUntil: 'load' }); - console.log('Page loaded'); - } catch (e) { - console.log('Page load error:', e.message); - } - - await page.waitForTimeout(10000); - console.log('Waited 10s'); - - const selCount = await page.locator('select').count(); - console.log('Select elements count:', selCount); - - if (selCount > 0) { - for (let s = 0; s < selCount; s++) { - const opts = await page.locator('select').nth(s).locator('option').allTextContents(); - console.log('Select', s, 'options:', JSON.stringify(opts.map(o => o.trim()))); - } - - await page.locator('select').nth(0).selectOption("Q'Rath"); - console.log('Selected Q\' Rath'); - await page.waitForTimeout(500); - - await page.locator('select').nth(1).selectOption('Orzum'); - console.log('Selected Orzum'); - await page.waitForTimeout(2000); - - // Log all key buttons - const buttons = page.locator('.keyContainer > div > div'); - const count = await buttons.count(); - console.log('=== All key buttons (' + count + ') ==='); - for (let i = 0; i < count; i++) { - const txt = (await buttons.nth(i).textContent() || '').trim(); - console.log('Button', i, ':', JSON.stringify(txt.substring(0,60))); - } - - // Find Q button - for (let i = 0; i < count; i++) { - const txt = (await buttons.nth(i).textContent() || ''); - if (txt.trim().toUpperCase().startsWith('Q')) { - console.log('\nFound Q button at index', i, ':', JSON.stringify(txt.trim().substring(0,60))); - console.log('Clicking it...'); - await buttons.nth(i).click({ force: true }); - break; - } - } - - await page.waitForTimeout(1000); - - // Check entity view - const evCount = await page.locator('.entityClickView #entityName').count(); - console.log('entityName count:', evCount); - if (evCount > 0) { - const name = (await page.locator('.entityClickView #entityName').textContent() || '').trim(); - console.log('entityName text:', JSON.stringify(name)); - } - } else { - console.log('No select elements found!'); - console.log('URL:', page.url()); - const body = await page.evaluate(() => document.body.innerText.substring(0, 500)); - console.log('Body text:', JSON.stringify(body)); - } - - await browser.close(); -})(); diff --git a/Playwright/debug_tab.js b/Playwright/debug_tab.js deleted file mode 100644 index ff28c22..0000000 --- a/Playwright/debug_tab.js +++ /dev/null @@ -1,59 +0,0 @@ -const { chromium } = require('playwright'); -(async () => { - const browser = await chromium.launch({ headless: true }); - const context = await browser.newContext({ viewport: { width: 1920, height: 1080 } }); - const page = await context.newPage(); - console.log('Navigating...'); - await page.goto('https://calm-mud-04916b210.1.azurestaticapps.net/build-calculator', { timeout: 30000, waitUntil: 'domcontentloaded' }); - console.log('Page loaded, waiting for Blazor...'); - await page.waitForTimeout(8000); - - console.log('Selecting Q\'Rath...'); - await page.locator('select').nth(0).selectOption("Q'Rath"); - await page.waitForTimeout(500); - await page.locator('select').nth(1).selectOption('Orzum'); - await page.waitForTimeout(3000); - - console.log('Looking for TAB key...'); - const allKeys = await page.locator('.keyContainer > div > div').all(); - console.log('Total key divs found:', allKeys.length); - for (let i = 0; i < allKeys.length; i++) { - const text = await allKeys[i].textContent(); - const preview = (text || '').trim().substring(0, 100); - console.log('Key ' + i + ' starts with:', preview.replace(/\n/g, ' ')); - if (text && text.trim().startsWith('TAB')) { - console.log('FOUND TAB KEY at index ' + i); - const entityDivs = await allKeys[i].locator('> div').all(); - console.log('Entity divs:', entityDivs.length); - for (const d of entityDivs) { - const t = await d.textContent(); - console.log(' Entity:', (t || '').trim()); - } - } - } - - console.log('Clicking TAB key...'); - try { - const tabKey = page.locator('.keyContainer > div > div').filter({ hasText: 'TAB' }).first(); - await tabKey.click({ timeout: 5000 }); - console.log('Click succeeded'); - } catch (e) { - console.log('Click failed:', e.message.substring(0, 200)); - } - - await page.waitForTimeout(3000); - const entityViewCount = await page.locator('.entityClickView').count(); - console.log('entityClickView count:', entityViewCount); - if (entityViewCount > 0) { - const ev = await page.locator('.entityClickView #entityName').textContent(); - console.log('Entity view name:', ev); - const id = await page.locator('.entityClickView .entitiesContainer').getAttribute('id'); - console.log('Entity container id:', id); - } else { - console.log('Entity click view NOT found - checking for errors...'); - const errorEls = await page.locator('[class*=\"error\"], [class*=\"Error\"]').count(); - console.log('Error elements:', errorEls); - } - - await browser.close(); -})().catch(e => { console.error(e.message); process.exit(1); }); diff --git a/Playwright/debug_timeline.js b/Playwright/debug_timeline.js deleted file mode 100644 index 5c7351e..0000000 --- a/Playwright/debug_timeline.js +++ /dev/null @@ -1,69 +0,0 @@ -const { chromium } = require('playwright'); -(async () => { - const browser = await chromium.launch({ headless: true }); - const page = await browser.newPage(); - await page.goto('http://localhost:5111/build-calculator', { timeout: 30000, waitUntil: 'networkidle' }); - await page.waitForTimeout(10000); - - const selects = page.locator('select'); - await selects.nth(0).selectOption("Q'Rath"); - await page.waitForTimeout(500); - await selects.nth(1).selectOption('Orzum'); - await page.waitForTimeout(2000); - - // Check entity view before adding - let evCount = await page.locator('.entityClickView #entityName').count(); - console.log('entityName count before add:', evCount); - if (evCount > 0) console.log('entityName text:', (await page.locator('.entityClickView #entityName').textContent() || '').trim()); - - // Check timeline intervals before - let intervals = page.locator('[class*="interval"], .timelineInterval'); - console.log('interval count before add:', await intervals.count()); - if ((await intervals.count()) > 0) { - console.log('first interval text:', ((await intervals.first().textContent()) || '').trim().substring(0,100)); - } - - // Click Q - const buttons = page.locator('.keyContainer > div > div'); - const count = await buttons.count(); - for (let i = 0; i < count; i++) { - const txt = (await buttons.nth(i).textContent()) || ''; - if (txt.trim().toUpperCase().startsWith('Q')) { - await buttons.nth(i).click({ force: true }); - console.log('Clicked Q button at index', i); - break; - } - } - - await page.waitForTimeout(2000); - - // Check entity view after adding - evCount = await page.locator('.entityClickView #entityName').count(); - console.log('entityName count after add:', evCount); - if (evCount > 0) console.log('entityName text:', ((await page.locator('.entityClickView #entityName').textContent()) || '').trim()); - - // Check timeline intervals after - intervals = page.locator('[class*="interval"], .timelineInterval'); - console.log('interval count after add:', await intervals.count()); - if ((await intervals.count()) > 0) { - const ic = await intervals.count(); - for (let i = 0; i < Math.min(ic, 3); i++) { - console.log('interval', i, 'text:', ((await intervals.nth(i).textContent()) || '').trim().substring(0,120)); - } - } - - // Click Clear Build Order - await page.locator('button').filter({ hasText: 'Clear Build Order' }).click(); - await page.waitForTimeout(2000); - - // Check entity view after clear - evCount = await page.locator('.entityClickView #entityName').count(); - console.log('entityName count after clear:', evCount); - if (evCount > 0) console.log('entityName text:', ((await page.locator('.entityClickView #entityName').textContent()) || '').trim()); - - // Check timeline intervals after clear - intervals = page.locator('[class*="interval"], .timelineInterval'); - console.log('interval count after clear:', await intervals.count()); - - await browser.close(); -})(); diff --git a/Playwright/debug_timeline2.js b/Playwright/debug_timeline2.js deleted file mode 100644 index 41c3cb9..0000000 --- a/Playwright/debug_timeline2.js +++ /dev/null @@ -1,39 +0,0 @@ -const { chromium } = require('playwright'); -(async () => { - const browser = await chromium.launch({ headless: true }); - const page = await browser.newPage(); - await page.goto('http://localhost:5111/build-calculator', { timeout: 30000, waitUntil: 'networkidle' }); - await page.waitForTimeout(10000); - - const selects = page.locator('select'); - await selects.nth(0).selectOption("Q'Rath"); - await page.waitForTimeout(500); - await selects.nth(1).selectOption('Orzum'); - await page.waitForTimeout(2000); - - const grid = page.locator('.calculatorGrid > div'); - const gCount = await grid.count(); - console.log('calculatorGrid child divs:', gCount); - for (let i = 0; i < gCount; i++) { - const cls = await grid.nth(i).getAttribute('class'); - const text = (await grid.nth(i).textContent() || '').trim().substring(0,80); - console.log(' child', i, 'class:', JSON.stringify(cls), 'text:', JSON.stringify(text)); - } - - // Check for interval-related elements - for (const sel of ['[class*="interval"]', '[class*="Interval"]', '[class*="timeline"]', '[class*="Timeline"]']) { - console.log(sel, 'count:', await page.locator(sel).count()); - } - - // Also check displayContainer children - const dc = page.locator('.displayContainer'); - const dcCount = await dc.count(); - console.log('displayContainer count:', dcCount); - for (let i = 0; i < dcCount; i++) { - const cls = await dc.nth(i).getAttribute('class'); - const text = (await dc.nth(i).textContent() || '').trim().substring(0,150); - console.log(' dc', i, 'class:', JSON.stringify(cls), 'text:', JSON.stringify(text)); - } - - await browser.close(); -})(); diff --git a/Playwright/debug_timeline3.js b/Playwright/debug_timeline3.js deleted file mode 100644 index 53514c1..0000000 --- a/Playwright/debug_timeline3.js +++ /dev/null @@ -1,90 +0,0 @@ -const { chromium } = require('playwright'); -(async () => { - const browser = await chromium.launch({ headless: true }); - const page = await browser.newPage(); - await page.goto('http://localhost:5111/build-calculator', { timeout: 30000, waitUntil: 'networkidle' }); - await page.waitForTimeout(10000); - - const selects = page.locator('select'); - await selects.nth(0).selectOption("Q'Rath"); - await page.waitForTimeout(500); - await selects.nth(1).selectOption('Orzum'); - await page.waitForTimeout(2000); - - const gridItems = page.locator('.calculatorGrid > div'); - const gCount = await gridItems.count(); - - // Find the timeline section (has "Shows economy" text) - let timelineIdx = -1; - for (let i = 0; i < gCount; i++) { - const txt = (await gridItems.nth(i).textContent() || ''); - if (txt.includes('economy')) { - timelineIdx = i; - break; - } - } - console.log('Timeline grid item index:', timelineIdx); - - // Get full timeline text before adding - if (timelineIdx >= 0) { - const text = (await gridItems.nth(timelineIdx).textContent() || '').trim(); - console.log('Timeline text before add (first 500 chars):'); - console.log(text.substring(0, 500)); - console.log('...'); - console.log('Contains Acropolis:', text.includes('Acropolis')); - console.log('Contains Requested:', text.includes('Requested')); - } - - // Click Q to add Acropolis - const buttons = page.locator('.keyContainer > div > div'); - const count = await buttons.count(); - for (let i = 0; i < count; i++) { - const txt = (await buttons.nth(i).textContent()) || ''; - if (txt.trim().toUpperCase().startsWith('Q')) { - await buttons.nth(i).click({ force: true }); - console.log('Clicked Q at index', i); - break; - } - } - await page.waitForTimeout(2000); - - // Check entity view - const evName = (await page.locator('.entityClickView #entityName').textContent() || '').trim(); - console.log('EntityView name after add:', evName); - - // Get timeline text after adding - if (timelineIdx >= 0) { - const text = (await gridItems.nth(timelineIdx).textContent() || '').trim(); - console.log('Timeline text after add (first 500 chars):'); - console.log(text.substring(0, 500)); - console.log('Contains Acropolis:', text.includes('Acropolis')); - console.log('Contains Requested:', text.includes('Requested')); - console.log('Contains New:', text.includes('New')); - } - - // Count Virtualize items in timeline - const virtualItems = page.locator('[style*="grid-template-columns: 1fr 1fr"]'); - console.log('Virtualize items (grid items):', await virtualItems.count()); - - // Click Clear Build Order - await page.locator('button').filter({ hasText: 'Clear Build Order' }).click(); - await page.waitForTimeout(2000); - - // Check entity view after clear - const evAfterClear = await page.locator('.entityClickView #entityName').count(); - console.log('EntityView #entityName count after clear:', evAfterClear); - if (evAfterClear > 0) { - console.log('EntityView name after clear:', (await page.locator('.entityClickView #entityName').textContent() || '').trim()); - } - - // Check timeline after clear - if (timelineIdx >= 0) { - const text = (await gridItems.nth(timelineIdx).textContent() || '').trim(); - console.log('Timeline text after clear (first 300 chars):'); - console.log(text.substring(0, 300)); - console.log('Contains Acropolis:', text.includes('Acropolis')); - console.log('Virtualize items:', await virtualItems.count()); - } - - await browser.close(); -})(); diff --git a/Playwright/debug_timeline4.js b/Playwright/debug_timeline4.js deleted file mode 100644 index fab3d11..0000000 --- a/Playwright/debug_timeline4.js +++ /dev/null @@ -1,64 +0,0 @@ -const { chromium } = require('playwright'); -(async () => { - const browser = await chromium.launch({ headless: true }); - const page = await browser.newPage(); - await page.goto('http://localhost:5111/build-calculator', { timeout: 30000, waitUntil: 'networkidle' }); - await page.waitForTimeout(10000); - - const selects = page.locator('select'); - await selects.nth(0).selectOption("Q'Rath"); - await page.waitForTimeout(500); - await selects.nth(1).selectOption('Orzum'); - await page.waitForTimeout(2000); - - const gridItems = page.locator('.calculatorGrid > div'); - const gCount = await gridItems.count(); - - for (let i = 0; i < gCount; i++) { - const txt = (await gridItems.nth(i).textContent() || '').trim(); - const cls = await gridItems.nth(i).getAttribute('class'); - console.log('=== Grid Item', i, 'class:', cls, '==='); - console.log(txt.substring(0, 200)); - console.log('---'); - } - - console.log('\n=== Clicking Q ==='); - const buttons = page.locator('.keyContainer > div > div'); - const count = await buttons.count(); - for (let i = 0; i < count; i++) { - const txt = (await buttons.nth(i).textContent()) || ''; - if (txt.trim().toUpperCase().startsWith('Q')) { - await buttons.nth(i).click({ force: true }); - break; - } - } - await page.waitForTimeout(2000); - - console.log('\n=== After Q click ==='); - for (let i = 0; i < gCount; i++) { - const txt = (await gridItems.nth(i).textContent() || '').trim(); - console.log('Grid', i, '- contains Acropolis:', txt.includes('Acropolis')); - if (txt.includes('Acropolis')) { - console.log(' Text around Acropolis:'); - const idx = txt.indexOf('Acropolis'); - console.log(' ', txt.substring(Math.max(0, idx - 40), idx + 40)); - } - } - - // Entity view - console.log('\nEntityView name:', (await page.locator('.entityClickView #entityName').textContent() || '').trim()); - - // Click Clear - await page.locator('button').filter({ hasText: 'Clear Build Order' }).click(); - await page.waitForTimeout(2000); - - console.log('\n=== After Clear ==='); - for (let i = 0; i < gCount; i++) { - const txt = (await gridItems.nth(i).textContent() || '').trim(); - console.log('Grid', i, '- contains Acropolis:', txt.includes('Acropolis')); - } - - console.log('\nEntityView after clear count:', await page.locator('.entityClickView #entityName').count()); - - await browser.close(); -})(); diff --git a/Services/IServices.cs b/Services/IServices.cs index 72c9a40..eb4e3cc 100644 --- a/Services/IServices.cs +++ b/Services/IServices.cs @@ -114,7 +114,6 @@ public interface IEntityDialogService public bool HasHistory(); } - public interface INoteService { public List NoteContentModels { get; set; } diff --git a/Services/Immortal/BuildOrderService.cs b/Services/Immortal/BuildOrderService.cs index 4be1a93..e503d21 100644 --- a/Services/Immortal/BuildOrderService.cs +++ b/Services/Immortal/BuildOrderService.cs @@ -294,11 +294,11 @@ public class BuildOrderService : IBuildOrderService where ordersAtTime.Key + (orders.Production() == null ? 0 : orders.Production().BuildTime) <= interval - && !orders.Harvest().IsDepleted( - interval, - ordersAtTime.Key + (orders.Production() == null - ? 0 - : orders.Production().BuildTime)) + && !orders.Harvest().IsDepleted( + interval, + ordersAtTime.Key + (orders.Production() == null + ? 0 + : orders.Production().BuildTime)) select orders).ToList(); } diff --git a/Services/Immortal/EconomyComparisonService.cs b/Services/Immortal/EconomyComparisonService.cs index 0d5e477..789b2a4 100644 --- a/Services/Immortal/EconomyComparisonService.cs +++ b/Services/Immortal/EconomyComparisonService.cs @@ -192,7 +192,7 @@ public class EconomyComparisionService : IEconomyComparisonService if (usedWorkers < harvester.Slots) workersNeeded += 1; } - if (harvester.RequiresWorker == false) + if (!harvester.RequiresWorker) { if (harvester.Resource == ResourceType.Ether) economyAtSecond.Ether += harvester.HarvestedPerInterval * harvester.Slots; diff --git a/Services/Services.csproj b/Services/Services.csproj index a62a0c4..4aada11 100644 --- a/Services/Services.csproj +++ b/Services/Services.csproj @@ -4,6 +4,7 @@ net10.0 enable enable + Services @@ -22,7 +23,7 @@ - + diff --git a/Tests/GlobalSetup.cs b/Tests/GlobalSetup.cs new file mode 100644 index 0000000..a064273 --- /dev/null +++ b/Tests/GlobalSetup.cs @@ -0,0 +1,23 @@ +using NUnit.Framework; +using Tests.Helpers; + +namespace Tests; + +[SetUpFixture] +public class GlobalSetup +{ + [OneTimeSetUp] + public async Task GlobalStart() + { + if (Environment.GetEnvironmentVariable("RUN_AGAINST_PRODUCTION") != "true") + { + await LocalServer.StartAsync(); + } + } + + [OneTimeTearDown] + public void GlobalStop() + { + LocalServer.Stop(); + } +} diff --git a/Tests/Helpers/LocalServer.cs b/Tests/Helpers/LocalServer.cs new file mode 100644 index 0000000..f2657d7 --- /dev/null +++ b/Tests/Helpers/LocalServer.cs @@ -0,0 +1,106 @@ +using System.Diagnostics; +using System.Text.RegularExpressions; + +namespace Tests.Helpers; + +public static class LocalServer +{ + private static Process? _process; + public static string? BaseUrl { get; private set; } + + public static async Task StartAsync() + { + if (_process != null) return; + + var root = FindProjectRoot(); + var webProject = Path.Combine(root, "Web"); + + Console.WriteLine($"[DEBUG_LOG] Starting local server for project: {webProject}"); + + _process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "dotnet", + Arguments = $"run --project \"{webProject}\" --urls http://127.0.0.1:0", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + WorkingDirectory = root + } + }; + + var tcs = new TaskCompletionSource(); + + _process.OutputDataReceived += (s, e) => + { + if (string.IsNullOrEmpty(e.Data)) return; + Console.WriteLine($"[SERVER] {e.Data}"); + var match = Regex.Match(e.Data, @"Now listening on:\s+(http://127.0.0.1:\d+)"); + if (match.Success) + { + tcs.TrySetResult(match.Groups[1].Value); + } + }; + + _process.ErrorDataReceived += (s, e) => + { + if (!string.IsNullOrEmpty(e.Data)) + Console.Error.WriteLine($"[SERVER ERROR] {e.Data}"); + }; + + _process.Start(); + _process.BeginOutputReadLine(); + _process.BeginErrorReadLine(); + + // Wait for the URL to be parsed from output + BaseUrl = await Task.WhenAny(tcs.Task, Task.Delay(30000)) == tcs.Task + ? tcs.Task.Result + : null; + + if (BaseUrl == null) + { + Stop(); + throw new Exception("Timeout waiting for local server to start and provide a URL."); + } + + Console.WriteLine($"[DEBUG_LOG] Local server started at: {BaseUrl}"); + } + + public static void Stop() + { + if (_process != null && !_process.HasExited) + { + Console.WriteLine("[DEBUG_LOG] Stopping local server..."); + _process.Kill(true); + _process.Dispose(); + _process = null; + } + } + + private static string FindProjectRoot() + { + var current = AppDomain.CurrentDomain.BaseDirectory; + while (!string.IsNullOrEmpty(current) && !File.Exists(Path.Combine(current, "IGP.sln"))) + { + var parent = Path.GetDirectoryName(current); + if (parent == current) break; + current = parent; + } + + if (string.IsNullOrEmpty(current) || !File.Exists(Path.Combine(current, "IGP.sln"))) + { + // Fallback to searching up from current directory if BaseDirectory fails + current = Directory.GetCurrentDirectory(); + while (!string.IsNullOrEmpty(current) && !File.Exists(Path.Combine(current, "IGP.sln"))) + { + var parent = Path.GetDirectoryName(current); + if (parent == current) break; + current = parent; + } + } + + return current ?? throw new Exception("Could not find project root containing IGP.sln"); + } +} diff --git a/Tests/Helpers/Website.cs b/Tests/Helpers/Website.cs new file mode 100644 index 0000000..5b91215 --- /dev/null +++ b/Tests/Helpers/Website.cs @@ -0,0 +1,50 @@ +using Microsoft.Playwright; +using Tests.Pages; +using Tests.Shared; + +namespace Tests.Helpers; + +public class Website +{ + public IPage Page { get; } + public bool RunAgainstProduction { get; } + public string BaseUrl { get; } + + public Website(IPage page) + { + Page = page; + RunAgainstProduction = Environment.GetEnvironmentVariable("RUN_AGAINST_PRODUCTION") == "true"; + + BaseUrl = RunAgainstProduction ? "https://igpfanreference.ca" : (LocalServer.BaseUrl ?? "http://localhost:5234"); + + NavigationBar = new NavigationBar(this); + SearchDialog = new SearchDialog(this); + BuildCalculatorPage = new BuildCalculatorPage(this); + HarassCalculatorPage = new HarassCalculatorPage(this); + DatabasePage = new DatabasePage(this); + DatabaseSinglePage = new DatabaseSinglePage(this); + } + + public ILocator Locator(string selector) => Page.Locator(selector); + public ILocator FindById(string id) => Page.Locator($"#{id}"); + public NavigationBar NavigationBar { get; } + public SearchDialog SearchDialog { get; } + public BuildCalculatorPage BuildCalculatorPage { get; } + public HarassCalculatorPage HarassCalculatorPage { get; } + public DatabasePage DatabasePage { get; } + public DatabaseSinglePage DatabaseSinglePage { get; } + + public async Task GotoAsync(string? path = null) + { + var url = path is null ? BaseUrl : $"{BaseUrl}/{path}"; + await Page.GotoAsync(url); + } + + public async Task ClickElementAsync(ILocator locator) => await locator.ClickAsync(); + + public async Task EnterInputAsync(ILocator locator, string value) + { + await locator.FillAsync(value); + await locator.PressAsync("Enter"); + } +} diff --git a/Tests/Pages/BasePage.cs b/Tests/Pages/BasePage.cs new file mode 100644 index 0000000..51e92ba --- /dev/null +++ b/Tests/Pages/BasePage.cs @@ -0,0 +1,28 @@ +using Tests.Helpers; + +namespace Tests.Pages; + +public abstract class BasePage +{ + protected Website Website { get; } + + protected BasePage(Website website) + { + Website = website; + } + + public abstract string Url { get; } + + public virtual async Task GotoAsync() + { + await Website.GotoAsync(Url); + } + + public async Task> GetLinksAsync() + { + var content = Website.FindById("content"); + var links = content.Locator("a"); + var hrefs = await links.EvaluateAllAsync("els => els.map(el => el.getAttribute('href')).filter(Boolean)"); + return hrefs.ToList(); + } +} diff --git a/Tests/Pages/BuildCalculator/ArmyComponent.cs b/Tests/Pages/BuildCalculator/ArmyComponent.cs new file mode 100644 index 0000000..e9848a4 --- /dev/null +++ b/Tests/Pages/BuildCalculator/ArmyComponent.cs @@ -0,0 +1,48 @@ +namespace Tests.Pages.BuildCalculator; + +public class ArmyComponent +{ + private readonly Website _website; + public ArmyComponent(Website website) => _website = website; + + public ILocator ArmyView => _website.Locator(".armyView"); + + public ILocator DisplayValue(string label) => + _website.Locator(".displayContainer").Filter(new() { HasText = label }).Locator(".displayContent"); + + public ILocator ArmyCards => ArmyView.Locator(".armyCard"); + + public async Task GetArmyCompletedAtAsync() => + (await DisplayValue("Army Completed At").TextContentAsync())?.Trim() ?? ""; + + public async Task GetArmyAttackingAtAsync() => + (await DisplayValue("Army Attacking At").TextContentAsync())?.Trim() ?? ""; + + public async Task> GetArmyUnitNamesAsync() + { + var cards = await ArmyCards.AllAsync(); + var names = new List(); + foreach (var card in cards) + { + var text = (await card.InnerTextAsync()).Trim(); + var match = System.Text.RegularExpressions.Regex.Match(text, @"\d+x\s*(.+)"); + names.Add(match.Success ? match.Groups[1].Value.Trim() : text); + } + return names; + } + + public async Task> GetArmyUnitCountsAsync() + { + var cards = await ArmyCards.AllAsync(); + var counts = new List<(string, int)>(); + foreach (var card in cards) + { + var countEl = card.Locator(".armyCount"); + var nameEl = card.Locator("div").Last; + var count = (await countEl.TextContentAsync())?.Replace("x", "").Trim() ?? "0"; + var name = (await nameEl.TextContentAsync())?.Trim() ?? ""; + counts.Add((name, int.Parse(count))); + } + return counts; + } +} diff --git a/Tests/Pages/BuildCalculator/BankComponent.cs b/Tests/Pages/BuildCalculator/BankComponent.cs new file mode 100644 index 0000000..f24ed75 --- /dev/null +++ b/Tests/Pages/BuildCalculator/BankComponent.cs @@ -0,0 +1,27 @@ +namespace Tests.Pages.BuildCalculator; + +public class BankComponent +{ + private readonly Website _website; + public BankComponent(Website website) => _website = website; + + public ILocator BankContainer => _website.Locator(".bankContainer"); + + public ILocator DisplayValue(string label) => + BankContainer.Locator(".displayContainer").Filter(new() { HasText = label }).Locator(".displayContent"); + + public async Task GetTimeAsync() => (await DisplayValue("Time").TextContentAsync())?.Trim() ?? ""; + public async Task GetAlloyAsync() => (await DisplayValue("Alloy").TextContentAsync())?.Trim() ?? ""; + public async Task GetEtherAsync() => (await DisplayValue("Ether").TextContentAsync())?.Trim() ?? ""; + public async Task GetPyreAsync() => (await DisplayValue("Pyre").TextContentAsync())?.Trim() ?? ""; + public async Task GetSupplyAsync() => (await DisplayValue("Supply").TextContentAsync())?.Trim() ?? ""; + + public async Task GetWorkerCountAsync() => + (await BankContainer.Locator(".workerText").Locator(".displayContent").Nth(0).TextContentAsync())?.Trim() ?? ""; + + public async Task GetBusyWorkerCountAsync() => + (await BankContainer.Locator(".workerText").Locator(".displayContent").Nth(1).TextContentAsync())?.Trim() ?? ""; + + public async Task GetCreatingWorkerCountAsync() => + (await BankContainer.Locator(".workerText").Locator(".displayContent").Nth(2).TextContentAsync())?.Trim() ?? ""; +} diff --git a/Tests/Pages/BuildCalculator/BuildChartComponent.cs b/Tests/Pages/BuildCalculator/BuildChartComponent.cs new file mode 100644 index 0000000..e7c1733 --- /dev/null +++ b/Tests/Pages/BuildCalculator/BuildChartComponent.cs @@ -0,0 +1,20 @@ +namespace Tests.Pages.BuildCalculator; + +public class BuildChartComponent +{ + private readonly Website _website; + public BuildChartComponent(Website website) => _website = website; + + public ILocator ChartsContainer => _website.Locator(".chartsContainer"); + + public ILocator DisplayValue(string label) => + _website.Locator(".displayContainer").Filter(new() { HasText = label }).Locator(".displayContent"); + + public async Task GetHighestAlloyAsync() => (await DisplayValue("Highest Alloy").TextContentAsync())?.Trim() ?? ""; + public async Task GetHighestEtherAsync() => (await DisplayValue("Highest Ether").TextContentAsync())?.Trim() ?? ""; + public async Task GetHighestPyreAsync() => (await DisplayValue("Highest Pyre").TextContentAsync())?.Trim() ?? ""; + public async Task GetHighestArmyAsync() => (await DisplayValue("Highest Army").TextContentAsync())?.Trim() ?? ""; + + public async Task GetChartCountAsync() => + await ChartsContainer.Locator("> div").CountAsync(); +} diff --git a/Tests/Pages/BuildCalculator/BuildOrderComponent.cs b/Tests/Pages/BuildCalculator/BuildOrderComponent.cs new file mode 100644 index 0000000..42a6fea --- /dev/null +++ b/Tests/Pages/BuildCalculator/BuildOrderComponent.cs @@ -0,0 +1,12 @@ +namespace Tests.Pages.BuildCalculator; + +public class BuildOrderComponent +{ + private readonly Website _website; + public BuildOrderComponent(Website website) => _website = website; + + public ILocator JsonTextarea => _website.Locator("textarea"); + + public async Task GetJsonDataAsync() => + await JsonTextarea.InputValueAsync(); +} diff --git a/Tests/Pages/BuildCalculator/EntityClickViewComponent.cs b/Tests/Pages/BuildCalculator/EntityClickViewComponent.cs new file mode 100644 index 0000000..38fda19 --- /dev/null +++ b/Tests/Pages/BuildCalculator/EntityClickViewComponent.cs @@ -0,0 +1,31 @@ +namespace Tests.Pages.BuildCalculator; + +public class EntityClickViewComponent +{ + private readonly Website _website; + public EntityClickViewComponent(Website website) => _website = website; + + public ILocator EntityClickView => _website.Locator(".entityClickView"); + + public async Task GetEntityNameAsync() + { + var el = EntityClickView.Locator("#entityName"); + if (await el.CountAsync() == 0) return null; + return (await el.TextContentAsync())?.Trim(); + } + + public async Task GetEntityHealthAsync() + { + var healthText = EntityClickView.Locator("div").Filter(new() { HasTextRegex = new System.Text.RegularExpressions.Regex("Health", System.Text.RegularExpressions.RegexOptions.IgnoreCase) }).First; + if (await healthText.CountAsync() == 0) return null; + var text = (await healthText.TextContentAsync()) ?? ""; + var match = System.Text.RegularExpressions.Regex.Match(text, @"(\d+)"); + return match.Success ? match.Groups[1].Value : null; + } + + public async Task ClickDetailedViewAsync() => + await EntityClickView.Locator("button").Filter(new() { HasText = "Detailed" }).ClickAsync(); + + public async Task ClickPlainViewAsync() => + await EntityClickView.Locator("button").Filter(new() { HasText = "Plain" }).ClickAsync(); +} diff --git a/Tests/Pages/BuildCalculator/FilterComponent.cs b/Tests/Pages/BuildCalculator/FilterComponent.cs new file mode 100644 index 0000000..8c1a411 --- /dev/null +++ b/Tests/Pages/BuildCalculator/FilterComponent.cs @@ -0,0 +1,28 @@ +namespace Tests.Pages.BuildCalculator; + +public class FilterComponent +{ + private readonly Website _website; + public FilterComponent(Website website) => _website = website; + + private ILocator FactionSelect => + _website.Locator("select").Filter(new() { Has = _website.Locator("option:has-text('Aru'), option:has-text(\"Q'Rath\")") }); + + private ILocator ImmortalSelect => + _website.Locator("select").Filter(new() { Has = _website.Locator("option:has-text('Orzum'), option:has-text('Ajari'), option:has-text('Atzlan'), option:has-text('Mala'), option:has-text('Xol')") }); + + public async Task SelectFactionAsync(string faction) => + await FactionSelect.SelectOptionAsync(faction); + + public async Task SelectImmortalAsync(string immortal) => + await ImmortalSelect.SelectOptionAsync(immortal); + + public async Task GetSelectedFactionAsync() => + await FactionSelect.InputValueAsync(); + + public async Task GetSelectedImmortalAsync() => + await ImmortalSelect.InputValueAsync(); + + public async Task> GetAvailableImmortalsAsync() => + await ImmortalSelect.Locator("option").AllTextContentsAsync(); +} diff --git a/Tests/Pages/BuildCalculator/HighlightsComponent.cs b/Tests/Pages/BuildCalculator/HighlightsComponent.cs new file mode 100644 index 0000000..a8ec05f --- /dev/null +++ b/Tests/Pages/BuildCalculator/HighlightsComponent.cs @@ -0,0 +1,29 @@ +namespace Tests.Pages.BuildCalculator; + +public class HighlightsComponent +{ + private readonly Website _website; + public HighlightsComponent(Website website) => _website = website; + + public ILocator HighlightsContainer => _website.Locator(".highlightsContainer"); + public ILocator RequestedColumn => HighlightsContainer.Locator("div").Filter(new() { HasText = "Requested" }).Locator("+ div"); + public ILocator FinishedColumn => HighlightsContainer.Locator("div").Filter(new() { HasText = "Finished" }).Locator("+ div"); + + public async Task> GetRequestedItemsAsync() => + await GetHighlightItemsAsync(); + + public async Task> GetFinishedItemsAsync() => + await GetHighlightItemsAsync(); + + private async Task> GetHighlightItemsAsync() + { + var items = await _website.Locator(".highlightsContainer").Locator("div").Filter(new() { HasTextRegex = new System.Text.RegularExpressions.Regex(@"^\d+\s*\|") }).AllAsync(); + var result = new List(); + foreach (var item in items) + { + var text = (await item.TextContentAsync())?.Trim(); + if (text is not null) result.Add(text); + } + return result; + } +} diff --git a/Tests/Pages/BuildCalculator/HotkeyViewerComponent.cs b/Tests/Pages/BuildCalculator/HotkeyViewerComponent.cs new file mode 100644 index 0000000..8e85fd0 --- /dev/null +++ b/Tests/Pages/BuildCalculator/HotkeyViewerComponent.cs @@ -0,0 +1,54 @@ +namespace Tests.Pages.BuildCalculator; + +public class HotkeyViewerComponent +{ + private readonly Website _website; + public HotkeyViewerComponent(Website website) => _website = website; + + public ILocator KeyContainer => _website.Locator(".keyContainer"); + + public async Task FindKeyButtonAsync(string keyLabel) + { + var upper = keyLabel.ToUpperInvariant(); + var buttons = KeyContainer.Locator("> div > div"); + var count = await buttons.CountAsync(); + for (int i = 0; i < count; i++) + { + var btn = buttons.Nth(i); + var text = (await btn.TextContentAsync())?.Trim().ToUpperInvariant() ?? ""; + if (text.StartsWith(upper)) return btn; + } + return null; + } + + public async Task ClickKeyAsync(string keyText) + { + var btn = await FindKeyButtonAsync(keyText); + if (btn is null) throw new InvalidOperationException($"Key \"{keyText}\" not found"); + await btn.ClickAsync(new() { Force = true }); + } + + public async Task GetFirstEntityNameAsync(string keyText) + { + var btn = await FindKeyButtonAsync(keyText); + if (btn is null) return null; + var entities = btn.Locator("> div"); + if (await entities.CountAsync() == 0) return null; + return (await entities.First.TextContentAsync())?.Trim(); + } + + public async Task> GetEntityNamesOnKeyAsync(string keyText) + { + var btn = await FindKeyButtonAsync(keyText); + if (btn is null) return Array.Empty(); + var entities = btn.Locator("> div"); + var count = await entities.CountAsync(); + var names = new List(); + for (int i = 0; i < count; i++) + { + var text = (await entities.Nth(i).TextContentAsync())?.Trim(); + if (!string.IsNullOrEmpty(text)) names.Add(text); + } + return names; + } +} diff --git a/Tests/Pages/BuildCalculator/OptionsComponent.cs b/Tests/Pages/BuildCalculator/OptionsComponent.cs new file mode 100644 index 0000000..13e2988 --- /dev/null +++ b/Tests/Pages/BuildCalculator/OptionsComponent.cs @@ -0,0 +1,38 @@ +namespace Tests.Pages.BuildCalculator; + +public class OptionsComponent +{ + private readonly Website _website; + public OptionsComponent(Website website) => _website = website; + + private ILocator FormNumberInput(string label) => + _website.Locator(".formNumberContainer").Filter(new() { HasText = label }).Locator("input[type='number']"); + + private ILocator ButtonWithLabel(string label) => + _website.Locator("button").Filter(new() { HasText = label }); + + public ILocator BuildingInputDelayInput => FormNumberInput("Building Input Delay"); + public ILocator WaitTimeInput => FormNumberInput("Wait Time"); + public ILocator WaitToInput => FormNumberInput("Wait To"); + public ILocator AddWaitButton => ButtonWithLabel("Add Wait").First; + public ILocator AddWaitToButton => ButtonWithLabel("Add Wait").Last; + + public async Task SetBuildingInputDelayAsync(int value) + { + await BuildingInputDelayInput.FillAsync(value.ToString()); + await BuildingInputDelayInput.PressAsync("Enter"); + } + + public async Task SetWaitTimeAsync(int value) => + await WaitTimeInput.FillAsync(value.ToString()); + + public async Task SetWaitToAsync(int value) => + await WaitToInput.FillAsync(value.ToString()); + + public async Task ClickAddWaitAsync() => await AddWaitButton.ClickAsync(); + public async Task ClickAddWaitToAsync() => await AddWaitToButton.ClickAsync(); + + public async Task GetBuildingInputDelayAsync() => await BuildingInputDelayInput.InputValueAsync(); + public async Task GetWaitTimeAsync() => await WaitTimeInput.InputValueAsync(); + public async Task GetWaitToAsync() => await WaitToInput.InputValueAsync(); +} diff --git a/Tests/Pages/BuildCalculator/TimelineComponent.cs b/Tests/Pages/BuildCalculator/TimelineComponent.cs new file mode 100644 index 0000000..b91c8fd --- /dev/null +++ b/Tests/Pages/BuildCalculator/TimelineComponent.cs @@ -0,0 +1,16 @@ +namespace Tests.Pages.BuildCalculator; + +public class TimelineComponent +{ + private readonly Website _website; + public TimelineComponent(Website website) => _website = website; + + public ILocator Container => + _website.Locator(".calculatorGrid > div").Filter(new() { HasText = "Timeline highlights" }); + + public async Task ContainsEntityAsync(string name) + { + var text = (await Container.TextContentAsync()) ?? ""; + return text.Contains(name); + } +} diff --git a/Tests/Pages/BuildCalculator/TimingComponent.cs b/Tests/Pages/BuildCalculator/TimingComponent.cs new file mode 100644 index 0000000..2baf0e6 --- /dev/null +++ b/Tests/Pages/BuildCalculator/TimingComponent.cs @@ -0,0 +1,28 @@ +namespace Tests.Pages.BuildCalculator; + +public class TimingComponent +{ + private readonly Website _website; + public TimingComponent(Website website) => _website = website; + + private ILocator FormNumberInput(string label) => + _website.Locator(".formNumberContainer").Filter(new() { HasText = label }).Locator("input[type='number']"); + + public ILocator AttackTimeInput => FormNumberInput("Attack Time"); + public ILocator TravelTimeInput => FormNumberInput("Travel Time"); + + public async Task SetAttackTimeAsync(int value) + { + await AttackTimeInput.FillAsync(value.ToString()); + await AttackTimeInput.PressAsync("Enter"); + } + + public async Task SetTravelTimeAsync(int value) + { + await TravelTimeInput.FillAsync(value.ToString()); + await TravelTimeInput.PressAsync("Enter"); + } + + public async Task GetAttackTimeAsync() => await AttackTimeInput.InputValueAsync(); + public async Task GetTravelTimeAsync() => await TravelTimeInput.InputValueAsync(); +} diff --git a/Tests/Pages/BuildCalculatorPage.cs b/Tests/Pages/BuildCalculatorPage.cs new file mode 100644 index 0000000..6f4431a --- /dev/null +++ b/Tests/Pages/BuildCalculatorPage.cs @@ -0,0 +1,43 @@ +using Tests.Pages.BuildCalculator; +using Tests.Shared; + +namespace Tests.Pages; + +public class BuildCalculatorPage : BasePage +{ + public BuildCalculatorPage(Website website) : base(website) + { + Timing = new TimingComponent(website); + Filter = new FilterComponent(website); + Options = new OptionsComponent(website); + Bank = new BankComponent(website); + Army = new ArmyComponent(website); + Highlights = new HighlightsComponent(website); + BuildOrder = new BuildOrderComponent(website); + Timeline = new TimelineComponent(website); + Hotkeys = new HotkeyViewerComponent(website); + EntityView = new EntityClickViewComponent(website); + Chart = new BuildChartComponent(website); + Toast = new ToastComponent(website); + } + + public override string Url => "build-calculator"; + + public TimingComponent Timing { get; } + public FilterComponent Filter { get; } + public OptionsComponent Options { get; } + public BankComponent Bank { get; } + public ArmyComponent Army { get; } + public HighlightsComponent Highlights { get; } + public BuildOrderComponent BuildOrder { get; } + public TimelineComponent Timeline { get; } + public HotkeyViewerComponent Hotkeys { get; } + public EntityClickViewComponent EntityView { get; } + public BuildChartComponent Chart { get; } + public ToastComponent Toast { get; } + + public ILocator CalculatorGrid => Website.Locator(".calculatorGrid"); + public ILocator ClearBuildOrderButton => Website.Locator("button").Filter(new() { HasText = "Clear Build Order" }); + + public async Task ClickClearBuildOrderAsync() => await ClearBuildOrderButton.ClickAsync(); +} diff --git a/Tests/Pages/DatabasePage.cs b/Tests/Pages/DatabasePage.cs new file mode 100644 index 0000000..8cc1c73 --- /dev/null +++ b/Tests/Pages/DatabasePage.cs @@ -0,0 +1,26 @@ +namespace Tests.Pages; + +public class DatabasePage : BasePage +{ + public DatabasePage(Website website) : base(website) { } + + public override string Url => "database"; + + public async Task FilterNameAsync(string name) + { + var input = Website.FindById("filterName").First; + await Website.EnterInputAsync(input, name); + } + + public async Task GetEntityNameAsync(string entityType, string entityName) + { + var el = Website.Locator($"#{entityType.ToLower()}-{entityName.ToLower()}").Locator("#entityName"); + return (await el.InnerTextAsync()).Trim(); + } + + public async Task GetEntityNameByIndexAsync(int index) + { + var el = Website.FindById("entityName").Nth(index); + return (await el.InnerTextAsync()).Trim(); + } +} diff --git a/Tests/Pages/DatabaseSinglePage.cs b/Tests/Pages/DatabaseSinglePage.cs new file mode 100644 index 0000000..5ee5ed0 --- /dev/null +++ b/Tests/Pages/DatabaseSinglePage.cs @@ -0,0 +1,25 @@ +namespace Tests.Pages; + +public class DatabaseSinglePage : BasePage +{ + public DatabaseSinglePage(Website website) : base(website) { } + + public override string Url => "database"; + + public async Task GotoWithSearchAsync(string searchText) + { + await Website.GotoAsync($"{Url}/{searchText}"); + } + + public async Task GetEntityNameAsync() => + (await Website.FindById("entityName").InnerTextAsync()).Trim(); + + public async Task GetEntityHealthAsync() => + (await Website.FindById("entityHealth").InnerTextAsync()).Trim(); + + public async Task GetInvalidSearchAsync() => + (await Website.FindById("invalidSearch").InnerTextAsync()).Trim(); + + public async Task GetValidSearchAsync() => + (await Website.FindById("validSearch").InnerTextAsync()).Trim(); +} diff --git a/Tests/Pages/HarassCalculatorPage.cs b/Tests/Pages/HarassCalculatorPage.cs new file mode 100644 index 0000000..fd2e78b --- /dev/null +++ b/Tests/Pages/HarassCalculatorPage.cs @@ -0,0 +1,48 @@ +namespace Tests.Pages; + +public class HarassCalculatorPage : BasePage +{ + public HarassCalculatorPage(Website website) : base(website) { } + + public override string Url => "harass-calculator"; + + public async Task SetWorkersLostToHarassAsync(int number) => + await EnterAndPressAsync("numberOfWorkersLostToHarass", number); + + public async Task SetNumberOfTownHallsExistingAsync(int number) => + await EnterAndPressAsync("numberOfTownHallsExisting", number); + + public async Task SetTownHallTravelTimeAsync(int index, int seconds) => + await EnterInputAtIndexAsync("numberOfTownHallTravelTimes", index, seconds); + + public async Task GetTotalAlloyHarassmentAsync() => await ReadIntAsync("totalAlloyHarassment"); + public async Task GetWorkerReplacementCostAsync() => await ReadIntAsync("workerReplacementCost"); + public async Task GetDelayedMiningCostAsync() => await ReadIntAsync("delayedMiningCost"); + public async Task GetAverageTravelTimeAsync() => await ReadIntAsync("getAverageTravelTime"); + public async Task GetExampleTotalAlloyLossAsync() => await ReadIntAsync("exampleTotalAlloyLoss"); + public async Task GetExampleWorkerCostAsync() => await ReadIntAsync("exampleWorkerCost"); + public async Task GetExampleMiningTimeCostAsync() => await ReadIntAsync("exampleMiningTimeCost"); + public async Task GetExampleTotalAlloyLossAccurateAsync() => await ReadIntAsync("exampleTotalAlloyLossAccurate"); + public async Task GetExampleTotalAlloyLossDifferenceAsync() => await ReadIntAsync("exampleTotalAlloyLossDifference"); + public async Task GetExampleTotalAlloyLossAccurateDifferenceAsync() => await ReadIntAsync("exampleTotalAlloyLossAccurateDifference"); + + private async Task EnterAndPressAsync(string id, int value) + { + var locator = Website.FindById(id); + await Website.EnterInputAsync(locator, value.ToString()); + } + + private async Task EnterInputAtIndexAsync(string parentId, int index, int value) + { + var inputs = Website.FindById(parentId).Locator("input"); + var input = inputs.Nth(index); + await input.FillAsync(value.ToString()); + await input.PressAsync("Enter"); + } + + private async Task ReadIntAsync(string id) + { + var text = await Website.FindById(id).TextContentAsync() ?? ""; + return int.Parse(text.Trim()); + } +} diff --git a/Tests/Shared/NavigationBar.cs b/Tests/Shared/NavigationBar.cs new file mode 100644 index 0000000..cc3945e --- /dev/null +++ b/Tests/Shared/NavigationBar.cs @@ -0,0 +1,20 @@ +namespace Tests.Shared; + +public class NavigationBar +{ + private readonly Website _website; + public NavigationBar(Website website) => _website = website; + + public ILocator SearchButton => _website.Locator("#desktop-searchButton"); + + public async Task ClickHomeLinkAsync() + { + await _website.Locator("a:has-text(\"IGP Fan Reference\")").ClickAsync(); + } + + public async Task ClickSearchButtonAsync() + { + await SearchButton.ClickAsync(); + return _website.SearchDialog; + } +} diff --git a/Tests/Shared/SearchDialog.cs b/Tests/Shared/SearchDialog.cs new file mode 100644 index 0000000..0c0cfa3 --- /dev/null +++ b/Tests/Shared/SearchDialog.cs @@ -0,0 +1,26 @@ +namespace Tests.Shared; + +public class SearchDialog +{ + private readonly Website _website; + public SearchDialog(Website website) => _website = website; + + public ILocator SearchBackground => _website.FindById("searchBackground"); + public ILocator SearchInput => _website.FindById("searchInput"); + + public async Task CloseDialogAsync() + { + await _website.ClickElementAsync(SearchBackground); + } + + public async Task SearchAsync(string text) + { + await _website.EnterInputAsync(SearchInput, text); + return this; + } + + public async Task SelectSearchEntityAsync(string label) + { + await _website.ClickElementAsync(_website.Locator($"button[label=\"{label}\"]")); + } +} diff --git a/Tests/Shared/ToastComponent.cs b/Tests/Shared/ToastComponent.cs new file mode 100644 index 0000000..c5eb73b --- /dev/null +++ b/Tests/Shared/ToastComponent.cs @@ -0,0 +1,36 @@ +namespace Tests.Shared; + +public class ToastComponent +{ + private readonly Website _website; + public ToastComponent(Website website) => _website = website; + + public ILocator Container => _website.Locator(".toastsContainer"); + public ILocator Toasts => _website.Locator(".toastsContainer .toastContainer"); + + public async Task> GetToastTitlesAsync() + { + var titles = await _website.Locator(".toastsContainer .toastTitle").AllTextContentsAsync(); + return titles.Select(t => t.Trim()).Where(t => !string.IsNullOrEmpty(t)).ToList(); + } + + public async Task HasToastContainingAsync(string text) + { + try + { + await _website.Page.WaitForFunctionAsync( + @"(expected) => { + const titles = document.querySelectorAll('.toastsContainer .toastTitle'); + return Array.from(titles).some(t => t.textContent.trim().includes(expected)); + }", + text, + new() { Timeout = 3000 } + ); + return true; + } + catch + { + return false; + } + } +} diff --git a/Tests/Specs/BuildCalculatorTests.cs b/Tests/Specs/BuildCalculatorTests.cs new file mode 100644 index 0000000..8b01cc1 --- /dev/null +++ b/Tests/Specs/BuildCalculatorTests.cs @@ -0,0 +1,115 @@ +using Microsoft.Playwright.NUnit; +using NUnit.Framework; + +namespace Tests.Specs; + +[Parallelizable(ParallelScope.Self)] +[FixtureLifeCycle(LifeCycle.SingleInstance)] +public class BuildCalculatorTests : PageTest +{ + private Helpers.Website _website = null!; + + [SetUp] + public void CreateWebsite() => _website = new Helpers.Website(Page); + + [Test] + public async Task AddEntitiesViaKeyboardQWE() + { + var calc = _website.BuildCalculatorPage; + await calc.GotoAsync(); + + await calc.Filter.SelectFactionAsync("Q'Rath"); + await calc.Filter.SelectImmortalAsync("Orzum"); + + await calc.Hotkeys.ClickKeyAsync("TAB"); + + var keyMap = new Dictionary { ["Q"] = "q", ["W"] = "w", ["E"] = "e", ["TAB"] = "Tab" }; + + foreach (var key in new[] { "Q", "W", "E", "TAB" }) + { + var entityNames = await calc.Hotkeys.GetEntityNamesOnKeyAsync(key); + if (entityNames.Count == 0) continue; + + await Page.Keyboard.PressAsync(keyMap[key]); + + var viewName = await calc.EntityView.GetEntityNameAsync(); + Assert.That(viewName, Is.Not.Null.And.Not.Empty); + Assert.That(entityNames, Does.Contain(viewName)); + } + } + + [Test] + public async Task AddEntitiesViaHotkeysClickTABQWE() + { + var calc = _website.BuildCalculatorPage; + await calc.GotoAsync(); + + await calc.Filter.SelectFactionAsync("Q'Rath"); + await calc.Filter.SelectImmortalAsync("Orzum"); + + foreach (var key in new[] { "TAB", "Q", "W", "E" }) + { + var entityNames = await calc.Hotkeys.GetEntityNamesOnKeyAsync(key); + if (entityNames.Count == 0) continue; + + await calc.Hotkeys.ClickKeyAsync(key); + + var viewName = await calc.EntityView.GetEntityNameAsync(); + Assert.That(viewName, Is.Not.Null.And.Not.Empty); + Assert.That(entityNames, Does.Contain(viewName)); + } + } + + [Test] + public async Task AddAcropolisViaQVerifyEntityViewAndTimelineThenClear() + { + var calc = _website.BuildCalculatorPage; + await calc.GotoAsync(); + + await calc.Filter.SelectFactionAsync("Q'Rath"); + await calc.Filter.SelectImmortalAsync("Orzum"); + + Assert.That(await calc.Timeline.ContainsEntityAsync("Acropolis"), Is.False); + + await calc.Hotkeys.ClickKeyAsync("Q"); + + Assert.That(await calc.EntityView.GetEntityNameAsync(), Is.EqualTo("Acropolis")); + Assert.That(await calc.Timeline.ContainsEntityAsync("Acropolis"), Is.True); + + await calc.ClickClearBuildOrderAsync(); + await Task.Delay(1000); + + Assert.That(await calc.Timeline.ContainsEntityAsync("Acropolis"), Is.False); + Assert.That(await calc.EntityView.GetEntityNameAsync(), Is.Null); + } + + [Test] + public async Task MissingRequirementsToastWhenBuildingSoulFoundryWithoutLegionHall() + { + var calc = _website.BuildCalculatorPage; + await calc.GotoAsync(); + + await calc.Filter.SelectFactionAsync("Q'Rath"); + await calc.Filter.SelectImmortalAsync("Orzum"); + + await calc.Hotkeys.ClickKeyAsync("E"); + var hasToast = await calc.Toast.HasToastContainingAsync("Missing Requirements"); + Assert.That(hasToast, Is.True); + } + + [Test] + public async Task NotEnoughEtherToastWhenBuildingSoulFoundryAfterLegionHall() + { + var calc = _website.BuildCalculatorPage; + await calc.GotoAsync(); + + await calc.Filter.SelectFactionAsync("Q'Rath"); + await calc.Filter.SelectImmortalAsync("Orzum"); + + await calc.Hotkeys.ClickKeyAsync("W"); + await calc.Hotkeys.ClickKeyAsync("E"); + + var hasToast = await calc.Toast.HasToastContainingAsync("Not Enough Ether"); + Assert.That(hasToast, Is.True); + } +} diff --git a/Tests/Specs/HarassCalculatorTests.cs b/Tests/Specs/HarassCalculatorTests.cs new file mode 100644 index 0000000..e7fbcab --- /dev/null +++ b/Tests/Specs/HarassCalculatorTests.cs @@ -0,0 +1,43 @@ +using Microsoft.Playwright.NUnit; +using NUnit.Framework; + +namespace Tests.Specs; + +[Parallelizable(ParallelScope.Self)] +[FixtureLifeCycle(LifeCycle.SingleInstance)] +public class HarassCalculatorTests : PageTest +{ + private Helpers.Website _website = null!; + + [SetUp] + public void CreateWebsite() => _website = new Helpers.Website(Page); + + [Test] + public async Task CalculatorInput() + { + var page = _website.HarassCalculatorPage; + await page.GotoAsync(); + await page.SetWorkersLostToHarassAsync(3); + await page.SetNumberOfTownHallsExistingAsync(2); + await page.SetTownHallTravelTimeAsync(0, 30); + var result = await page.GetTotalAlloyHarassmentAsync(); + Assert.That(result, Is.EqualTo(240)); + } + + [Test] + public async Task CalculatedExampleInformation() + { + var page = _website.HarassCalculatorPage; + await page.GotoAsync(); + + Assert.Multiple(async () => + { + Assert.That(await page.GetExampleTotalAlloyLossAsync(), Is.EqualTo(720)); + Assert.That(await page.GetExampleWorkerCostAsync(), Is.EqualTo(300)); + Assert.That(await page.GetExampleMiningTimeCostAsync(), Is.EqualTo(420)); + Assert.That(await page.GetExampleTotalAlloyLossAccurateAsync(), Is.EqualTo(450)); + Assert.That(await page.GetExampleTotalAlloyLossDifferenceAsync(), Is.EqualTo(300)); + Assert.That(await page.GetExampleTotalAlloyLossAccurateDifferenceAsync(), Is.EqualTo(270)); + }); + } +} diff --git a/Tests/Specs/LinksTests.cs b/Tests/Specs/LinksTests.cs new file mode 100644 index 0000000..6ff06ca --- /dev/null +++ b/Tests/Specs/LinksTests.cs @@ -0,0 +1,41 @@ +using Microsoft.Playwright.NUnit; +using NUnit.Framework; + +namespace Tests.Specs; + +[Parallelizable(ParallelScope.Self)] +[FixtureLifeCycle(LifeCycle.SingleInstance)] +public class LinksTests : PageTest +{ + private Helpers.Website _website = null!; + + [SetUp] + public void CreateWebsite() => _website = new Helpers.Website(Page); + + [Test] + public async Task VerifyPageLinks() + { + _website = new Helpers.Website(Page); + + await _website.HarassCalculatorPage.GotoAsync(); + var harassLinks = await _website.HarassCalculatorPage.GetLinksAsync(); + foreach (var link in harassLinks) await VerifyLinkAsync(link); + + await _website.DatabasePage.GotoAsync(); + var dbLinks = await _website.DatabasePage.GetLinksAsync(); + foreach (var link in dbLinks) await VerifyLinkAsync(link); + + await _website.DatabaseSinglePage.GotoWithSearchAsync("throne"); + var singleLinks = await _website.DatabaseSinglePage.GetLinksAsync(); + foreach (var link in singleLinks) await VerifyLinkAsync(link); + } + + private static async Task VerifyLinkAsync(string link) + { + if (link.StartsWith("mailto")) return; + + using var client = new System.Net.Http.HttpClient(); + var response = await client.GetAsync(link); + Assert.That(response.IsSuccessStatusCode, Is.True, $"Link '{link}' returned {response.StatusCode}"); + } +} diff --git a/Tests/Specs/SearchFeaturesTests.cs b/Tests/Specs/SearchFeaturesTests.cs new file mode 100644 index 0000000..00e4853 --- /dev/null +++ b/Tests/Specs/SearchFeaturesTests.cs @@ -0,0 +1,68 @@ +using Microsoft.Playwright.NUnit; +using NUnit.Framework; + +namespace Tests.Specs; + +[Parallelizable(ParallelScope.Self)] +[FixtureLifeCycle(LifeCycle.SingleInstance)] +public class SearchFeaturesTests : PageTest +{ + private Helpers.Website _website = null!; + + [SetUp] + public void CreateWebsite() => _website = new Helpers.Website(Page); + + [Test] + public async Task DesktopOpenCloseSearchDialog() + { + await _website.GotoAsync(); + await _website.NavigationBar.ClickSearchButtonAsync(); + await _website.SearchDialog.CloseDialogAsync(); + await _website.NavigationBar.ClickHomeLinkAsync(); + } + + [Test] + public async Task DesktopSearchForThrone() + { + await _website.GotoAsync(); + await _website.NavigationBar.ClickSearchButtonAsync(); + await _website.SearchDialog.SearchAsync("Throne"); + await _website.SearchDialog.SelectSearchEntityAsync("Throne"); + + var name = await _website.DatabaseSinglePage.GetEntityNameAsync(); + var health = await _website.DatabaseSinglePage.GetEntityHealthAsync(); + + Assert.That(name, Is.EqualTo("Throne")); + Assert.That(health.Trim(), Is.Not.Empty); + } + + [Test] + public async Task DesktopFilterForThrone() + { + var page = _website.DatabasePage; + await page.GotoAsync(); + await page.FilterNameAsync("Throne"); + var name = await page.GetEntityNameByIndexAsync(0); + Assert.That(name, Is.EqualTo("Throne")); + } + + [Test] + public async Task SeeThroneByDefault() + { + var page = _website.DatabasePage; + await page.GotoAsync(); + var name = await page.GetEntityNameAsync("army", "throne"); + Assert.That(name, Is.EqualTo("Throne")); + } + + [Test] + public async Task DirectLinkNotThroneFailure() + { + var page = _website.DatabaseSinglePage; + await page.GotoWithSearchAsync("not throne"); + var invalidSearch = await page.GetInvalidSearchAsync(); + var validSearch = await page.GetValidSearchAsync(); + Assert.That(invalidSearch, Is.EqualTo("not throne")); + Assert.That(validSearch, Is.EqualTo("Throne")); + } +} diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj new file mode 100644 index 0000000..e560989 --- /dev/null +++ b/Tests/Tests.csproj @@ -0,0 +1,21 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/IGP/App.razor b/Web/App.razor similarity index 99% rename from IGP/App.razor rename to Web/App.razor index 0717bce..eefd542 100644 --- a/IGP/App.razor +++ b/Web/App.razor @@ -48,11 +48,11 @@ --immortal-mala: #dc7a29; --immortal-xol: #87aa87; --immortal-atzlan: #8B7355; - + --faction-qrath: #8EACCD; --immortal-orzum: #4A6B8A; --immortal-ajari: #b4e2e3; - + --severity-warning-color: #2a2000; --severity-warning-border-color: #755c13; --severity-error-color: #290102; diff --git a/IGP/Dialog/ConfirmationDialogComponent.razor b/Web/Dialog/ConfirmationDialogComponent.razor similarity index 100% rename from IGP/Dialog/ConfirmationDialogComponent.razor rename to Web/Dialog/ConfirmationDialogComponent.razor diff --git a/IGP/Dialog/EntityDialogComponent.razor b/Web/Dialog/EntityDialogComponent.razor similarity index 100% rename from IGP/Dialog/EntityDialogComponent.razor rename to Web/Dialog/EntityDialogComponent.razor diff --git a/IGP/Dialog/EntityDialogComponent.razor.css b/Web/Dialog/EntityDialogComponent.razor.css similarity index 100% rename from IGP/Dialog/EntityDialogComponent.razor.css rename to Web/Dialog/EntityDialogComponent.razor.css diff --git a/IGP/Dialog/SearchDialogComponent.razor b/Web/Dialog/SearchDialogComponent.razor similarity index 100% rename from IGP/Dialog/SearchDialogComponent.razor rename to Web/Dialog/SearchDialogComponent.razor diff --git a/IGP/Index.razor b/Web/Index.razor similarity index 100% rename from IGP/Index.razor rename to Web/Index.razor diff --git a/IGP/Localizations.Designer.cs b/Web/Localizations.Designer.cs similarity index 100% rename from IGP/Localizations.Designer.cs rename to Web/Localizations.Designer.cs diff --git a/Web/Localizations.properties b/Web/Localizations.properties new file mode 100644 index 0000000..e69de29 diff --git a/IGP/Localizations.resx b/Web/Localizations.resx similarity index 100% rename from IGP/Localizations.resx rename to Web/Localizations.resx diff --git a/IGP/PageLayout.razor b/Web/PageLayout.razor similarity index 100% rename from IGP/PageLayout.razor rename to Web/PageLayout.razor diff --git a/IGP/PageLayout.razor.css b/Web/PageLayout.razor.css similarity index 100% rename from IGP/PageLayout.razor.css rename to Web/PageLayout.razor.css diff --git a/IGP/Pages/AboutPage.razor b/Web/Pages/AboutPage.razor similarity index 100% rename from IGP/Pages/AboutPage.razor rename to Web/Pages/AboutPage.razor diff --git a/IGP/Pages/BasePage.razor b/Web/Pages/BasePage.razor similarity index 100% rename from IGP/Pages/BasePage.razor rename to Web/Pages/BasePage.razor diff --git a/IGP/Pages/BuildCalculator/BuildCalculatorPage.razor b/Web/Pages/BuildCalculator/BuildCalculatorPage.razor similarity index 99% rename from IGP/Pages/BuildCalculator/BuildCalculatorPage.razor rename to Web/Pages/BuildCalculator/BuildCalculatorPage.razor index 21553c2..1a60739 100644 --- a/IGP/Pages/BuildCalculator/BuildCalculatorPage.razor +++ b/Web/Pages/BuildCalculator/BuildCalculatorPage.razor @@ -31,7 +31,7 @@ - + Clear Build Order diff --git a/IGP/Pages/BuildCalculator/Parts/ArmyComponent.razor b/Web/Pages/BuildCalculator/Parts/ArmyComponent.razor similarity index 100% rename from IGP/Pages/BuildCalculator/Parts/ArmyComponent.razor rename to Web/Pages/BuildCalculator/Parts/ArmyComponent.razor diff --git a/IGP/Pages/BuildCalculator/Parts/BankComponent.razor b/Web/Pages/BuildCalculator/Parts/BankComponent.razor similarity index 100% rename from IGP/Pages/BuildCalculator/Parts/BankComponent.razor rename to Web/Pages/BuildCalculator/Parts/BankComponent.razor diff --git a/IGP/Pages/BuildCalculator/Parts/BuildChartComponent.razor b/Web/Pages/BuildCalculator/Parts/BuildChartComponent.razor similarity index 98% rename from IGP/Pages/BuildCalculator/Parts/BuildChartComponent.razor rename to Web/Pages/BuildCalculator/Parts/BuildChartComponent.razor index 9377355..2669314 100644 --- a/IGP/Pages/BuildCalculator/Parts/BuildChartComponent.razor +++ b/Web/Pages/BuildCalculator/Parts/BuildChartComponent.razor @@ -231,13 +231,13 @@ else var alloyAutomaticHarvesters = from harvester in economyAtSecond.HarvestPoints where harvester.Harvest() != null - where harvester.Harvest().RequiresWorker == false + where !harvester.Harvest().RequiresWorker where harvester.Harvest().Resource == ResourceType.Alloy select harvester; var etherAutomaticHarvesters = from harvester in economyAtSecond.HarvestPoints where harvester.Harvest() != null - where harvester.Harvest().RequiresWorker == false + where !harvester.Harvest().RequiresWorker where harvester.Harvest().Resource == ResourceType.Ether select harvester; diff --git a/IGP/Pages/BuildCalculator/Parts/BuildOrderComponent.razor b/Web/Pages/BuildCalculator/Parts/BuildOrderComponent.razor similarity index 73% rename from IGP/Pages/BuildCalculator/Parts/BuildOrderComponent.razor rename to Web/Pages/BuildCalculator/Parts/BuildOrderComponent.razor index a58e8bf..81eca91 100644 --- a/IGP/Pages/BuildCalculator/Parts/BuildOrderComponent.razor +++ b/Web/Pages/BuildCalculator/Parts/BuildOrderComponent.razor @@ -9,14 +9,14 @@ @code { - /** - // TODO: Make this more elegant, and useful. Also, it currently doesn't clear properly - - - */ + /** + * // TODO: Make this more elegant, and useful. Also, it currently doesn't clear properly + * + * + */ protected override void OnInitialized() { base.OnInitialized(); diff --git a/IGP/Pages/BuildCalculator/Parts/Cosmetic/FactionBorderComponent.razor b/Web/Pages/BuildCalculator/Parts/Cosmetic/FactionBorderComponent.razor similarity index 99% rename from IGP/Pages/BuildCalculator/Parts/Cosmetic/FactionBorderComponent.razor rename to Web/Pages/BuildCalculator/Parts/Cosmetic/FactionBorderComponent.razor index f59b103..301fcfa 100644 --- a/IGP/Pages/BuildCalculator/Parts/Cosmetic/FactionBorderComponent.razor +++ b/Web/Pages/BuildCalculator/Parts/Cosmetic/FactionBorderComponent.razor @@ -28,4 +28,5 @@ var color = faction == DataType.FACTION_Aru ? "var(--faction-aru)" : "var(--faction-qrath)"; return $"border-top: 4px solid {color}; padding-top: 14px; margin-top: -12px;"; } + } diff --git a/IGP/Pages/BuildCalculator/Parts/Cosmetic/ImmortalBorderComponent.razor b/Web/Pages/BuildCalculator/Parts/Cosmetic/ImmortalBorderComponent.razor similarity index 99% rename from IGP/Pages/BuildCalculator/Parts/Cosmetic/ImmortalBorderComponent.razor rename to Web/Pages/BuildCalculator/Parts/Cosmetic/ImmortalBorderComponent.razor index f91b74e..4f5f4a8 100644 --- a/IGP/Pages/BuildCalculator/Parts/Cosmetic/ImmortalBorderComponent.razor +++ b/Web/Pages/BuildCalculator/Parts/Cosmetic/ImmortalBorderComponent.razor @@ -33,4 +33,5 @@ else if (immortal == DataType.IMMORTAL_Xol) color = "var(--immortal-xol)"; return $"border-top: 4px solid {color}; padding-top: 14px; margin-top: -12px;"; } + } diff --git a/IGP/Pages/BuildCalculator/Parts/EntityClickViewComponent.razor b/Web/Pages/BuildCalculator/Parts/EntityClickViewComponent.razor similarity index 99% rename from IGP/Pages/BuildCalculator/Parts/EntityClickViewComponent.razor rename to Web/Pages/BuildCalculator/Parts/EntityClickViewComponent.razor index 1581c32..3275e84 100644 --- a/IGP/Pages/BuildCalculator/Parts/EntityClickViewComponent.razor +++ b/Web/Pages/BuildCalculator/Parts/EntityClickViewComponent.razor @@ -55,7 +55,7 @@ StateHasChanged(); } } - + void RefreshDefaults() { _viewType = StorageService.GetValue(StorageKeys.IsPlainView) ? EntityViewType.Plain : EntityViewType.Detailed; @@ -77,4 +77,5 @@ StateHasChanged(); } } + } \ No newline at end of file diff --git a/IGP/Pages/BuildCalculator/Parts/FilterComponent.razor b/Web/Pages/BuildCalculator/Parts/FilterComponent.razor similarity index 100% rename from IGP/Pages/BuildCalculator/Parts/FilterComponent.razor rename to Web/Pages/BuildCalculator/Parts/FilterComponent.razor diff --git a/IGP/Pages/BuildCalculator/Parts/HighlightsComponent.razor b/Web/Pages/BuildCalculator/Parts/HighlightsComponent.razor similarity index 100% rename from IGP/Pages/BuildCalculator/Parts/HighlightsComponent.razor rename to Web/Pages/BuildCalculator/Parts/HighlightsComponent.razor diff --git a/IGP/Pages/BuildCalculator/Parts/HotkeyViewerComponent.razor b/Web/Pages/BuildCalculator/Parts/HotkeyViewerComponent.razor similarity index 100% rename from IGP/Pages/BuildCalculator/Parts/HotkeyViewerComponent.razor rename to Web/Pages/BuildCalculator/Parts/HotkeyViewerComponent.razor diff --git a/IGP/Pages/BuildCalculator/Parts/InputPanelComponent.razor b/Web/Pages/BuildCalculator/Parts/InputPanelComponent.razor similarity index 100% rename from IGP/Pages/BuildCalculator/Parts/InputPanelComponent.razor rename to Web/Pages/BuildCalculator/Parts/InputPanelComponent.razor diff --git a/IGP/Pages/BuildCalculator/Parts/OptionsComponent.razor b/Web/Pages/BuildCalculator/Parts/OptionsComponent.razor similarity index 100% rename from IGP/Pages/BuildCalculator/Parts/OptionsComponent.razor rename to Web/Pages/BuildCalculator/Parts/OptionsComponent.razor diff --git a/IGP/Pages/BuildCalculator/Parts/TimelineComponent.razor b/Web/Pages/BuildCalculator/Parts/TimelineComponent.razor similarity index 100% rename from IGP/Pages/BuildCalculator/Parts/TimelineComponent.razor rename to Web/Pages/BuildCalculator/Parts/TimelineComponent.razor diff --git a/IGP/Pages/BuildCalculator/Parts/TimingComponent.razor b/Web/Pages/BuildCalculator/Parts/TimingComponent.razor similarity index 100% rename from IGP/Pages/BuildCalculator/Parts/TimingComponent.razor rename to Web/Pages/BuildCalculator/Parts/TimingComponent.razor diff --git a/IGP/Pages/BuildCalculator/Parts/TutorialHelperComponent.razor b/Web/Pages/BuildCalculator/Parts/TutorialHelperComponent.razor similarity index 99% rename from IGP/Pages/BuildCalculator/Parts/TutorialHelperComponent.razor rename to Web/Pages/BuildCalculator/Parts/TutorialHelperComponent.razor index b863b67..5d6227d 100644 --- a/IGP/Pages/BuildCalculator/Parts/TutorialHelperComponent.razor +++ b/Web/Pages/BuildCalculator/Parts/TutorialHelperComponent.razor @@ -77,6 +77,6 @@ { FilterService.Unsubscribe(StateHasChanged); } - + } \ No newline at end of file diff --git a/IGP/Pages/ContactPage.razor b/Web/Pages/ContactPage.razor similarity index 100% rename from IGP/Pages/ContactPage.razor rename to Web/Pages/ContactPage.razor diff --git a/IGP/Pages/DataCollectionPage.razor b/Web/Pages/DataCollectionPage.razor similarity index 100% rename from IGP/Pages/DataCollectionPage.razor rename to Web/Pages/DataCollectionPage.razor diff --git a/IGP/Pages/DataTables/DataTablesPage.razor b/Web/Pages/DataTables/DataTablesPage.razor similarity index 100% rename from IGP/Pages/DataTables/DataTablesPage.razor rename to Web/Pages/DataTables/DataTablesPage.razor diff --git a/IGP/Pages/DataTables/Parts/MovementTable.razor b/Web/Pages/DataTables/Parts/MovementTable.razor similarity index 100% rename from IGP/Pages/DataTables/Parts/MovementTable.razor rename to Web/Pages/DataTables/Parts/MovementTable.razor diff --git a/IGP/Pages/DataTables/Parts/ProductionTable.razor b/Web/Pages/DataTables/Parts/ProductionTable.razor similarity index 100% rename from IGP/Pages/DataTables/Parts/ProductionTable.razor rename to Web/Pages/DataTables/Parts/ProductionTable.razor diff --git a/IGP/Pages/DataTables/Parts/VitalityTable.razor b/Web/Pages/DataTables/Parts/VitalityTable.razor similarity index 100% rename from IGP/Pages/DataTables/Parts/VitalityTable.razor rename to Web/Pages/DataTables/Parts/VitalityTable.razor diff --git a/IGP/Pages/DataTables/Parts/WeaponTable.razor b/Web/Pages/DataTables/Parts/WeaponTable.razor similarity index 100% rename from IGP/Pages/DataTables/Parts/WeaponTable.razor rename to Web/Pages/DataTables/Parts/WeaponTable.razor diff --git a/IGP/Pages/Database/DatabasePage.razor b/Web/Pages/Database/DatabasePage.razor similarity index 99% rename from IGP/Pages/Database/DatabasePage.razor rename to Web/Pages/Database/DatabasePage.razor index ac7c879..add55cc 100644 --- a/IGP/Pages/Database/DatabasePage.razor +++ b/Web/Pages/Database/DatabasePage.razor @@ -114,7 +114,7 @@ [Inject] public IEntityFilterService EntityFilterService { get; set; } = default!; readonly List defaults = (from entity in EntityModel.GetList() - where entity.IsSpeculative == false + where !entity.IsSpeculative select entity).ToList(); List factions = default!; diff --git a/IGP/Pages/Database/DatabaseSinglePage.razor b/Web/Pages/Database/DatabaseSinglePage.razor similarity index 100% rename from IGP/Pages/Database/DatabaseSinglePage.razor rename to Web/Pages/Database/DatabaseSinglePage.razor diff --git a/IGP/Pages/Database/Entity/EntityViewComponent.razor b/Web/Pages/Database/Entity/EntityViewComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/EntityViewComponent.razor rename to Web/Pages/Database/Entity/EntityViewComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityAbilitiesComponent.razor b/Web/Pages/Database/Entity/Parts/EntityAbilitiesComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityAbilitiesComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityAbilitiesComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityHeaderComponent.razor b/Web/Pages/Database/Entity/Parts/EntityHeaderComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityHeaderComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityHeaderComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityInfoComponent.razor b/Web/Pages/Database/Entity/Parts/EntityInfoComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityInfoComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityInfoComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityMechanicsComponent.razor b/Web/Pages/Database/Entity/Parts/EntityMechanicsComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityMechanicsComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityMechanicsComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityPassivesComponent.razor b/Web/Pages/Database/Entity/Parts/EntityPassivesComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityPassivesComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityPassivesComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityProductionComponent.razor b/Web/Pages/Database/Entity/Parts/EntityProductionComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityProductionComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityProductionComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityPyreSpellsComponent.razor b/Web/Pages/Database/Entity/Parts/EntityPyreSpellsComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityPyreSpellsComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityPyreSpellsComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityStatsComponent.razor b/Web/Pages/Database/Entity/Parts/EntityStatsComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityStatsComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityStatsComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityUpgradesComponent.razor b/Web/Pages/Database/Entity/Parts/EntityUpgradesComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityUpgradesComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityUpgradesComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityVanguardAddedComponent.razor b/Web/Pages/Database/Entity/Parts/EntityVanguardAddedComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityVanguardAddedComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityVanguardAddedComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityVanguardsComponent.razor b/Web/Pages/Database/Entity/Parts/EntityVanguardsComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityVanguardsComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityVanguardsComponent.razor diff --git a/IGP/Pages/Database/Entity/Parts/EntityWeaponsComponent.razor b/Web/Pages/Database/Entity/Parts/EntityWeaponsComponent.razor similarity index 100% rename from IGP/Pages/Database/Entity/Parts/EntityWeaponsComponent.razor rename to Web/Pages/Database/Entity/Parts/EntityWeaponsComponent.razor diff --git a/IGP/Pages/Database/Parts/EntityFilterComponent.razor b/Web/Pages/Database/Parts/EntityFilterComponent.razor similarity index 100% rename from IGP/Pages/Database/Parts/EntityFilterComponent.razor rename to Web/Pages/Database/Parts/EntityFilterComponent.razor diff --git a/IGP/Pages/Database/Parts/EntityFilterComponent.razor.css b/Web/Pages/Database/Parts/EntityFilterComponent.razor.css similarity index 100% rename from IGP/Pages/Database/Parts/EntityFilterComponent.razor.css rename to Web/Pages/Database/Parts/EntityFilterComponent.razor.css diff --git a/IGP/Pages/EconomyComparison/EconomyComparisonPage.razor b/Web/Pages/EconomyComparison/EconomyComparisonPage.razor similarity index 100% rename from IGP/Pages/EconomyComparison/EconomyComparisonPage.razor rename to Web/Pages/EconomyComparison/EconomyComparisonPage.razor diff --git a/IGP/Pages/EconomyComparison/Parts/ChartComponent.razor b/Web/Pages/EconomyComparison/Parts/ChartComponent.razor similarity index 98% rename from IGP/Pages/EconomyComparison/Parts/ChartComponent.razor rename to Web/Pages/EconomyComparison/Parts/ChartComponent.razor index 0f0b397..4902908 100644 --- a/IGP/Pages/EconomyComparison/Parts/ChartComponent.razor +++ b/Web/Pages/EconomyComparison/Parts/ChartComponent.razor @@ -139,7 +139,7 @@ var alloyAutomaticHarvesters = from harvester in economyAtSecond.HarvestPoints where harvester.Harvest() != null - where harvester.Harvest().RequiresWorker == false + where !harvester.Harvest().RequiresWorker where harvester.Harvest().Resource == ResourceType.Alloy select harvester; diff --git a/IGP/Pages/EconomyComparison/Parts/EconomyDifferenceComponent.razor b/Web/Pages/EconomyComparison/Parts/EconomyDifferenceComponent.razor similarity index 100% rename from IGP/Pages/EconomyComparison/Parts/EconomyDifferenceComponent.razor rename to Web/Pages/EconomyComparison/Parts/EconomyDifferenceComponent.razor diff --git a/IGP/Pages/EconomyComparison/Parts/EconomyInputComponent.razor b/Web/Pages/EconomyComparison/Parts/EconomyInputComponent.razor similarity index 100% rename from IGP/Pages/EconomyComparison/Parts/EconomyInputComponent.razor rename to Web/Pages/EconomyComparison/Parts/EconomyInputComponent.razor diff --git a/IGP/Pages/HarassCalculatorPage.razor b/Web/Pages/HarassCalculatorPage.razor similarity index 100% rename from IGP/Pages/HarassCalculatorPage.razor rename to Web/Pages/HarassCalculatorPage.razor diff --git a/IGP/Pages/Home/HomePage.razor b/Web/Pages/Home/HomePage.razor similarity index 100% rename from IGP/Pages/Home/HomePage.razor rename to Web/Pages/Home/HomePage.razor diff --git a/IGP/Pages/Home/Parts/ContentHighlightComponent.razor b/Web/Pages/Home/Parts/ContentHighlightComponent.razor similarity index 100% rename from IGP/Pages/Home/Parts/ContentHighlightComponent.razor rename to Web/Pages/Home/Parts/ContentHighlightComponent.razor diff --git a/IGP/Pages/MemoryTester/MemoryTesterPage.razor b/Web/Pages/MemoryTester/MemoryTesterPage.razor similarity index 100% rename from IGP/Pages/MemoryTester/MemoryTesterPage.razor rename to Web/Pages/MemoryTester/MemoryTesterPage.razor diff --git a/IGP/Pages/MemoryTester/Parts/UnitMemory.razor b/Web/Pages/MemoryTester/Parts/UnitMemory.razor similarity index 100% rename from IGP/Pages/MemoryTester/Parts/UnitMemory.razor rename to Web/Pages/MemoryTester/Parts/UnitMemory.razor diff --git a/IGP/Pages/MemoryTester/Parts/UnitMemoryManager.razor b/Web/Pages/MemoryTester/Parts/UnitMemoryManager.razor similarity index 100% rename from IGP/Pages/MemoryTester/Parts/UnitMemoryManager.razor rename to Web/Pages/MemoryTester/Parts/UnitMemoryManager.razor diff --git a/IGP/Pages/Notes/NotesIndexPage.razor b/Web/Pages/Notes/NotesIndexPage.razor similarity index 100% rename from IGP/Pages/Notes/NotesIndexPage.razor rename to Web/Pages/Notes/NotesIndexPage.razor diff --git a/IGP/Pages/Notes/NotesPage.razor b/Web/Pages/Notes/NotesPage.razor similarity index 100% rename from IGP/Pages/Notes/NotesPage.razor rename to Web/Pages/Notes/NotesPage.razor diff --git a/IGP/Pages/Notes/Parts/NoteComponent.razor b/Web/Pages/Notes/Parts/NoteComponent.razor similarity index 100% rename from IGP/Pages/Notes/Parts/NoteComponent.razor rename to Web/Pages/Notes/Parts/NoteComponent.razor diff --git a/IGP/Pages/Notes/Parts/NoteInnerNavComponent.razor b/Web/Pages/Notes/Parts/NoteInnerNavComponent.razor similarity index 100% rename from IGP/Pages/Notes/Parts/NoteInnerNavComponent.razor rename to Web/Pages/Notes/Parts/NoteInnerNavComponent.razor diff --git a/IGP/Pages/Notes/Parts/NoteNavComponent.razor b/Web/Pages/Notes/Parts/NoteNavComponent.razor similarity index 100% rename from IGP/Pages/Notes/Parts/NoteNavComponent.razor rename to Web/Pages/Notes/Parts/NoteNavComponent.razor diff --git a/IGP/Pages/PermissionsPage.razor b/Web/Pages/PermissionsPage.razor similarity index 100% rename from IGP/Pages/PermissionsPage.razor rename to Web/Pages/PermissionsPage.razor diff --git a/IGP/Pages/RawDatabase.razor b/Web/Pages/RawDatabase.razor similarity index 100% rename from IGP/Pages/RawDatabase.razor rename to Web/Pages/RawDatabase.razor diff --git a/IGP/Pages/RawDatabase.razor.css b/Web/Pages/RawDatabase.razor.css similarity index 100% rename from IGP/Pages/RawDatabase.razor.css rename to Web/Pages/RawDatabase.razor.css diff --git a/IGP/Pages/StoragePage.razor b/Web/Pages/StoragePage.razor similarity index 100% rename from IGP/Pages/StoragePage.razor rename to Web/Pages/StoragePage.razor diff --git a/IGP/Pages/StreamsPage.razor b/Web/Pages/StreamsPage.razor similarity index 100% rename from IGP/Pages/StreamsPage.razor rename to Web/Pages/StreamsPage.razor diff --git a/IGP/Portals/ConfirmationDialogPortal.razor b/Web/Portals/ConfirmationDialogPortal.razor similarity index 100% rename from IGP/Portals/ConfirmationDialogPortal.razor rename to Web/Portals/ConfirmationDialogPortal.razor diff --git a/IGP/Portals/EntityDialogPortal.razor b/Web/Portals/EntityDialogPortal.razor similarity index 100% rename from IGP/Portals/EntityDialogPortal.razor rename to Web/Portals/EntityDialogPortal.razor diff --git a/IGP/Portals/SearchPortal.razor b/Web/Portals/SearchPortal.razor similarity index 100% rename from IGP/Portals/SearchPortal.razor rename to Web/Portals/SearchPortal.razor diff --git a/IGP/Portals/ToastPortal.razor b/Web/Portals/ToastPortal.razor similarity index 100% rename from IGP/Portals/ToastPortal.razor rename to Web/Portals/ToastPortal.razor diff --git a/IGP/Program.cs b/Web/Program.cs similarity index 100% rename from IGP/Program.cs rename to Web/Program.cs diff --git a/IGP/Properties/PublishProfiles/FolderProfile.pubxml b/Web/Properties/PublishProfiles/FolderProfile.pubxml similarity index 100% rename from IGP/Properties/PublishProfiles/FolderProfile.pubxml rename to Web/Properties/PublishProfiles/FolderProfile.pubxml diff --git a/IGP/Properties/PublishProfiles/FolderProfile1.pubxml b/Web/Properties/PublishProfiles/FolderProfile1.pubxml similarity index 100% rename from IGP/Properties/PublishProfiles/FolderProfile1.pubxml rename to Web/Properties/PublishProfiles/FolderProfile1.pubxml diff --git a/IGP/Properties/launchSettings.json b/Web/Properties/launchSettings.json similarity index 98% rename from IGP/Properties/launchSettings.json rename to Web/Properties/launchSettings.json index 049c7ad..036f677 100644 --- a/IGP/Properties/launchSettings.json +++ b/Web/Properties/launchSettings.json @@ -8,7 +8,7 @@ } }, "profiles": { - "IGP": { + "Web": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, diff --git a/IGP/Utils/Interval.cs b/Web/Utils/Interval.cs similarity index 100% rename from IGP/Utils/Interval.cs rename to Web/Utils/Interval.cs diff --git a/IGP/Utils/Markdown.cs b/Web/Utils/Markdown.cs similarity index 100% rename from IGP/Utils/Markdown.cs rename to Web/Utils/Markdown.cs diff --git a/IGP/Utils/Project.cs b/Web/Utils/Project.cs similarity index 100% rename from IGP/Utils/Project.cs rename to Web/Utils/Project.cs diff --git a/IGP/IGP.csproj b/Web/Web.csproj similarity index 80% rename from IGP/IGP.csproj rename to Web/Web.csproj index ddd4f0f..f8ab8c9 100644 --- a/IGP/IGP.csproj +++ b/Web/Web.csproj @@ -6,6 +6,8 @@ enable service-worker-assets.js 12 + IGP.Web + IGP @@ -21,16 +23,16 @@ - - - - - - + + + + + + - + @@ -40,8 +42,8 @@ - - + + diff --git a/IGP/_Imports.cs b/Web/_Imports.cs similarity index 100% rename from IGP/_Imports.cs rename to Web/_Imports.cs diff --git a/IGP/_Imports.razor b/Web/_Imports.razor similarity index 100% rename from IGP/_Imports.razor rename to Web/_Imports.razor diff --git a/IGP/global.json b/Web/global.json similarity index 100% rename from IGP/global.json rename to Web/global.json diff --git a/IGP/staticwebapp.config.json b/Web/staticwebapp.config.json similarity index 100% rename from IGP/staticwebapp.config.json rename to Web/staticwebapp.config.json diff --git a/IGP/wwwroot/_redirects b/Web/wwwroot/_redirects similarity index 100% rename from IGP/wwwroot/_redirects rename to Web/wwwroot/_redirects diff --git a/IGP/wwwroot/appsettings.json b/Web/wwwroot/appsettings.json similarity index 100% rename from IGP/wwwroot/appsettings.json rename to Web/wwwroot/appsettings.json diff --git a/IGP/wwwroot/content/notes/coop/holdout.md b/Web/wwwroot/content/notes/coop/holdout.md similarity index 100% rename from IGP/wwwroot/content/notes/coop/holdout.md rename to Web/wwwroot/content/notes/coop/holdout.md diff --git a/IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/CoopBaseLarge.png b/Web/wwwroot/content/notes/coop/image/notes/coop-holdout/CoopBaseLarge.png similarity index 100% rename from IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/CoopBaseLarge.png rename to Web/wwwroot/content/notes/coop/image/notes/coop-holdout/CoopBaseLarge.png diff --git a/IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/DefendPoints.png b/Web/wwwroot/content/notes/coop/image/notes/coop-holdout/DefendPoints.png similarity index 100% rename from IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/DefendPoints.png rename to Web/wwwroot/content/notes/coop/image/notes/coop-holdout/DefendPoints.png diff --git a/IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/EnemySpawns.png b/Web/wwwroot/content/notes/coop/image/notes/coop-holdout/EnemySpawns.png similarity index 100% rename from IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/EnemySpawns.png rename to Web/wwwroot/content/notes/coop/image/notes/coop-holdout/EnemySpawns.png diff --git a/IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/Multipliers.png b/Web/wwwroot/content/notes/coop/image/notes/coop-holdout/Multipliers.png similarity index 100% rename from IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/Multipliers.png rename to Web/wwwroot/content/notes/coop/image/notes/coop-holdout/Multipliers.png diff --git a/IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/OpenBases.png b/Web/wwwroot/content/notes/coop/image/notes/coop-holdout/OpenBases.png similarity index 100% rename from IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/OpenBases.png rename to Web/wwwroot/content/notes/coop/image/notes/coop-holdout/OpenBases.png diff --git a/IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/Pyre.png b/Web/wwwroot/content/notes/coop/image/notes/coop-holdout/Pyre.png similarity index 100% rename from IGP/wwwroot/content/notes/coop/image/notes/coop-holdout/Pyre.png rename to Web/wwwroot/content/notes/coop/image/notes/coop-holdout/Pyre.png diff --git a/IGP/wwwroot/content/notes/settings/hotkeys.md b/Web/wwwroot/content/notes/settings/hotkeys.md similarity index 100% rename from IGP/wwwroot/content/notes/settings/hotkeys.md rename to Web/wwwroot/content/notes/settings/hotkeys.md diff --git a/IGP/wwwroot/content/notes/the-basics/armor-types.md b/Web/wwwroot/content/notes/the-basics/armor-types.md similarity index 100% rename from IGP/wwwroot/content/notes/the-basics/armor-types.md rename to Web/wwwroot/content/notes/the-basics/armor-types.md diff --git a/IGP/wwwroot/content/notes/the-basics/economy-overview.md b/Web/wwwroot/content/notes/the-basics/economy-overview.md similarity index 100% rename from IGP/wwwroot/content/notes/the-basics/economy-overview.md rename to Web/wwwroot/content/notes/the-basics/economy-overview.md diff --git a/IGP/wwwroot/content/notes/the-basics/families-factions-and-immortal-vanguards.md b/Web/wwwroot/content/notes/the-basics/families-factions-and-immortal-vanguards.md similarity index 100% rename from IGP/wwwroot/content/notes/the-basics/families-factions-and-immortal-vanguards.md rename to Web/wwwroot/content/notes/the-basics/families-factions-and-immortal-vanguards.md diff --git a/IGP/wwwroot/content/notes/the-basics/immortal-spells-and-pyre.md b/Web/wwwroot/content/notes/the-basics/immortal-spells-and-pyre.md similarity index 100% rename from IGP/wwwroot/content/notes/the-basics/immortal-spells-and-pyre.md rename to Web/wwwroot/content/notes/the-basics/immortal-spells-and-pyre.md diff --git a/IGP/wwwroot/content/notes/the-basics/timing-and-scouting.md b/Web/wwwroot/content/notes/the-basics/timing-and-scouting.md similarity index 100% rename from IGP/wwwroot/content/notes/the-basics/timing-and-scouting.md rename to Web/wwwroot/content/notes/the-basics/timing-and-scouting.md diff --git a/IGP/wwwroot/css/app.css b/Web/wwwroot/css/app.css similarity index 100% rename from IGP/wwwroot/css/app.css rename to Web/wwwroot/css/app.css diff --git a/IGP/wwwroot/css/bootstrap/bootstrap.min.css b/Web/wwwroot/css/bootstrap/bootstrap.min.css similarity index 100% rename from IGP/wwwroot/css/bootstrap/bootstrap.min.css rename to Web/wwwroot/css/bootstrap/bootstrap.min.css diff --git a/IGP/wwwroot/css/bootstrap/bootstrap.min.css.map b/Web/wwwroot/css/bootstrap/bootstrap.min.css.map similarity index 100% rename from IGP/wwwroot/css/bootstrap/bootstrap.min.css.map rename to Web/wwwroot/css/bootstrap/bootstrap.min.css.map diff --git a/IGP/wwwroot/css/components/table.css b/Web/wwwroot/css/components/table.css similarity index 100% rename from IGP/wwwroot/css/components/table.css rename to Web/wwwroot/css/components/table.css diff --git a/IGP/wwwroot/css/default.css b/Web/wwwroot/css/default.css similarity index 100% rename from IGP/wwwroot/css/default.css rename to Web/wwwroot/css/default.css diff --git a/IGP/wwwroot/css/open-iconic/FONT-LICENSE b/Web/wwwroot/css/open-iconic/FONT-LICENSE similarity index 100% rename from IGP/wwwroot/css/open-iconic/FONT-LICENSE rename to Web/wwwroot/css/open-iconic/FONT-LICENSE diff --git a/IGP/wwwroot/css/open-iconic/ICON-LICENSE b/Web/wwwroot/css/open-iconic/ICON-LICENSE similarity index 100% rename from IGP/wwwroot/css/open-iconic/ICON-LICENSE rename to Web/wwwroot/css/open-iconic/ICON-LICENSE diff --git a/IGP/wwwroot/css/open-iconic/README.md b/Web/wwwroot/css/open-iconic/README.md similarity index 100% rename from IGP/wwwroot/css/open-iconic/README.md rename to Web/wwwroot/css/open-iconic/README.md diff --git a/IGP/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css b/Web/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css similarity index 100% rename from IGP/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css rename to Web/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css diff --git a/IGP/wwwroot/css/open-iconic/font/fonts/open-iconic.eot b/Web/wwwroot/css/open-iconic/font/fonts/open-iconic.eot similarity index 100% rename from IGP/wwwroot/css/open-iconic/font/fonts/open-iconic.eot rename to Web/wwwroot/css/open-iconic/font/fonts/open-iconic.eot diff --git a/IGP/wwwroot/css/open-iconic/font/fonts/open-iconic.otf b/Web/wwwroot/css/open-iconic/font/fonts/open-iconic.otf similarity index 100% rename from IGP/wwwroot/css/open-iconic/font/fonts/open-iconic.otf rename to Web/wwwroot/css/open-iconic/font/fonts/open-iconic.otf diff --git a/IGP/wwwroot/css/open-iconic/font/fonts/open-iconic.svg b/Web/wwwroot/css/open-iconic/font/fonts/open-iconic.svg similarity index 100% rename from IGP/wwwroot/css/open-iconic/font/fonts/open-iconic.svg rename to Web/wwwroot/css/open-iconic/font/fonts/open-iconic.svg diff --git a/IGP/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf b/Web/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf similarity index 100% rename from IGP/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf rename to Web/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf diff --git a/IGP/wwwroot/css/open-iconic/font/fonts/open-iconic.woff b/Web/wwwroot/css/open-iconic/font/fonts/open-iconic.woff similarity index 100% rename from IGP/wwwroot/css/open-iconic/font/fonts/open-iconic.woff rename to Web/wwwroot/css/open-iconic/font/fonts/open-iconic.woff diff --git a/IGP/wwwroot/favicon.ico b/Web/wwwroot/favicon.ico similarity index 100% rename from IGP/wwwroot/favicon.ico rename to Web/wwwroot/favicon.ico diff --git a/IGP/wwwroot/fontawesome-pro-6.1.1-web/LICENSE.txt b/Web/wwwroot/fontawesome-pro-6.1.1-web/LICENSE.txt similarity index 100% rename from IGP/wwwroot/fontawesome-pro-6.1.1-web/LICENSE.txt rename to Web/wwwroot/fontawesome-pro-6.1.1-web/LICENSE.txt diff --git a/IGP/wwwroot/fontawesome-pro-6.1.1-web/css/all.min.css b/Web/wwwroot/fontawesome-pro-6.1.1-web/css/all.min.css similarity index 100% rename from IGP/wwwroot/fontawesome-pro-6.1.1-web/css/all.min.css rename to Web/wwwroot/fontawesome-pro-6.1.1-web/css/all.min.css diff --git a/IGP/wwwroot/fontawesome-pro-6.1.1-web/css/fontawesome.min.css b/Web/wwwroot/fontawesome-pro-6.1.1-web/css/fontawesome.min.css similarity index 100% rename from IGP/wwwroot/fontawesome-pro-6.1.1-web/css/fontawesome.min.css rename to Web/wwwroot/fontawesome-pro-6.1.1-web/css/fontawesome.min.css diff --git a/IGP/wwwroot/fontawesome-pro-6.1.1-web/css/solid.min.css b/Web/wwwroot/fontawesome-pro-6.1.1-web/css/solid.min.css similarity index 100% rename from IGP/wwwroot/fontawesome-pro-6.1.1-web/css/solid.min.css rename to Web/wwwroot/fontawesome-pro-6.1.1-web/css/solid.min.css diff --git a/IGP/wwwroot/fontawesome-pro-6.1.1-web/js/all.min.js b/Web/wwwroot/fontawesome-pro-6.1.1-web/js/all.min.js similarity index 100% rename from IGP/wwwroot/fontawesome-pro-6.1.1-web/js/all.min.js rename to Web/wwwroot/fontawesome-pro-6.1.1-web/js/all.min.js diff --git a/IGP/wwwroot/fontawesome-pro-6.1.1-web/js/brands.min.js b/Web/wwwroot/fontawesome-pro-6.1.1-web/js/brands.min.js similarity index 100% rename from IGP/wwwroot/fontawesome-pro-6.1.1-web/js/brands.min.js rename to Web/wwwroot/fontawesome-pro-6.1.1-web/js/brands.min.js diff --git a/IGP/wwwroot/fontawesome-pro-6.1.1-web/js/fontawesome.min.js b/Web/wwwroot/fontawesome-pro-6.1.1-web/js/fontawesome.min.js similarity index 100% rename from IGP/wwwroot/fontawesome-pro-6.1.1-web/js/fontawesome.min.js rename to Web/wwwroot/fontawesome-pro-6.1.1-web/js/fontawesome.min.js diff --git a/IGP/wwwroot/fontawesome-pro-6.1.1-web/js/solid.min.js b/Web/wwwroot/fontawesome-pro-6.1.1-web/js/solid.min.js similarity index 100% rename from IGP/wwwroot/fontawesome-pro-6.1.1-web/js/solid.min.js rename to Web/wwwroot/fontawesome-pro-6.1.1-web/js/solid.min.js diff --git a/Web/wwwroot/generated/NoteConnectionModels.json b/Web/wwwroot/generated/NoteConnectionModels.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/Web/wwwroot/generated/NoteConnectionModels.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/IGP/wwwroot/generated/NoteContentModels.json b/Web/wwwroot/generated/NoteContentModels.json similarity index 100% rename from IGP/wwwroot/generated/NoteContentModels.json rename to Web/wwwroot/generated/NoteContentModels.json diff --git a/IGP/wwwroot/generated/NoteSectionModels.json b/Web/wwwroot/generated/NoteSectionModels.json similarity index 100% rename from IGP/wwwroot/generated/NoteSectionModels.json rename to Web/wwwroot/generated/NoteSectionModels.json diff --git a/IGP/wwwroot/generated/Variables.json b/Web/wwwroot/generated/Variables.json similarity index 100% rename from IGP/wwwroot/generated/Variables.json rename to Web/wwwroot/generated/Variables.json diff --git a/IGP/wwwroot/icon-192.png b/Web/wwwroot/icon-192.png similarity index 100% rename from IGP/wwwroot/icon-192.png rename to Web/wwwroot/icon-192.png diff --git a/IGP/wwwroot/icon-512.png b/Web/wwwroot/icon-512.png similarity index 100% rename from IGP/wwwroot/icon-512.png rename to Web/wwwroot/icon-512.png diff --git a/IGP/wwwroot/image/hero/Build.png b/Web/wwwroot/image/hero/Build.png similarity index 100% rename from IGP/wwwroot/image/hero/Build.png rename to Web/wwwroot/image/hero/Build.png diff --git a/IGP/wwwroot/image/hero/Database.png b/Web/wwwroot/image/hero/Database.png similarity index 100% rename from IGP/wwwroot/image/hero/Database.png rename to Web/wwwroot/image/hero/Database.png diff --git a/IGP/wwwroot/image/hero/Notes.png b/Web/wwwroot/image/hero/Notes.png similarity index 100% rename from IGP/wwwroot/image/hero/Notes.png rename to Web/wwwroot/image/hero/Notes.png diff --git a/IGP/wwwroot/image/hero/Streams.png b/Web/wwwroot/image/hero/Streams.png similarity index 100% rename from IGP/wwwroot/image/hero/Streams.png rename to Web/wwwroot/image/hero/Streams.png diff --git a/IGP/wwwroot/image/notes/coop-holdout/CoopBaseLarge.png b/Web/wwwroot/image/notes/coop-holdout/CoopBaseLarge.png similarity index 100% rename from IGP/wwwroot/image/notes/coop-holdout/CoopBaseLarge.png rename to Web/wwwroot/image/notes/coop-holdout/CoopBaseLarge.png diff --git a/IGP/wwwroot/image/notes/coop-holdout/DefendPoints.png b/Web/wwwroot/image/notes/coop-holdout/DefendPoints.png similarity index 100% rename from IGP/wwwroot/image/notes/coop-holdout/DefendPoints.png rename to Web/wwwroot/image/notes/coop-holdout/DefendPoints.png diff --git a/IGP/wwwroot/image/notes/coop-holdout/EnemySpawns.png b/Web/wwwroot/image/notes/coop-holdout/EnemySpawns.png similarity index 100% rename from IGP/wwwroot/image/notes/coop-holdout/EnemySpawns.png rename to Web/wwwroot/image/notes/coop-holdout/EnemySpawns.png diff --git a/IGP/wwwroot/image/notes/coop-holdout/Multipliers.png b/Web/wwwroot/image/notes/coop-holdout/Multipliers.png similarity index 100% rename from IGP/wwwroot/image/notes/coop-holdout/Multipliers.png rename to Web/wwwroot/image/notes/coop-holdout/Multipliers.png diff --git a/IGP/wwwroot/image/notes/coop-holdout/OpenBases.png b/Web/wwwroot/image/notes/coop-holdout/OpenBases.png similarity index 100% rename from IGP/wwwroot/image/notes/coop-holdout/OpenBases.png rename to Web/wwwroot/image/notes/coop-holdout/OpenBases.png diff --git a/IGP/wwwroot/image/notes/coop-holdout/Pyre.png b/Web/wwwroot/image/notes/coop-holdout/Pyre.png similarity index 100% rename from IGP/wwwroot/image/notes/coop-holdout/Pyre.png rename to Web/wwwroot/image/notes/coop-holdout/Pyre.png diff --git a/IGP/wwwroot/index.html b/Web/wwwroot/index.html similarity index 100% rename from IGP/wwwroot/index.html rename to Web/wwwroot/index.html diff --git a/IGP/wwwroot/javascript/download.js b/Web/wwwroot/javascript/download.js similarity index 100% rename from IGP/wwwroot/javascript/download.js rename to Web/wwwroot/javascript/download.js diff --git a/IGP/wwwroot/manifest.json b/Web/wwwroot/manifest.json similarity index 100% rename from IGP/wwwroot/manifest.json rename to Web/wwwroot/manifest.json diff --git a/IGP/wwwroot/service-worker.js b/Web/wwwroot/service-worker.js similarity index 100% rename from IGP/wwwroot/service-worker.js rename to Web/wwwroot/service-worker.js diff --git a/IGP/wwwroot/service-worker.published.js b/Web/wwwroot/service-worker.published.js similarity index 100% rename from IGP/wwwroot/service-worker.published.js rename to Web/wwwroot/service-worker.published.js diff --git a/docs/.obsidian/workspace.json b/docs/.obsidian/workspace.json index 14d6326..e469f30 100644 --- a/docs/.obsidian/workspace.json +++ b/docs/.obsidian/workspace.json @@ -56,12 +56,12 @@ "state": { "type": "markdown", "state": { - "file": "Build Calculator CmdLine.md", + "file": "Feature Proposals.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "Build Calculator CmdLine" + "title": "Feature Proposals" } } ], @@ -240,44 +240,44 @@ "active": "b98a69cefb529fc8", "lastOpenFiles": [ "_Tasks Kanban.base", - "Build Calculator CmdLine.md", - "AI Help Docs/containerize-and-run.md", - "AI Help Docs/publish-and-serve.md", - "AI Gen Docs/test-multi-context-entity-comparison.md", - "AI Gen Docs/services.md", - "AI Gen Docs/recommendations.md", - "AI Gen Docs/development.md", - "AI Gen Docs/architecture.md", - "Images/Pasted image 20260601083005.png", - "Images/Pasted image 20260601082954.png", - "Tasks/Plan Calculator.md", - "Tasks/Remove Items from anywhere in the build calc timeline.md", - "Tasks/Top Borders in Calculator should change based on Selected Faction and Immortal.md", - "Tasks/Update the Reference Tables with Telerik.md", "Tasks/Worker Income UI and Tests.md", + "Tasks/Update the Reference Tables with Telerik.md", "Tasks/WebAssembly back to Azure.md", - "Tasks/Spells are currently a production item in data. Make the a ability item so they don't show under production table.md", - "Tasks/Nice looking map refrence.md", - "Tasks/Add an Ability to Favourite Data.md", - "Tasks/Add a Timeline Editor.md", - "Tasks/Add Co-op objective reference.md", - "Tasks/Entity Click View Tests.md", - "Tasks/Make a Plan to Fully Test the Calculator.md", - "Tasks/Make page object pattern structure for the Build Calculator and all it's components.md", - "Tasks/More Wait Tests.md", - "Images/Pasted image 20260601093510.png", + "Tasks/Top Borders in Calculator should change based on Selected Faction and Immortal.md", "Tasks/Timeline Tests.md", + "Tasks/Spells are currently a production item in data. Make the a ability item so they don't show under production table.md", + "Tasks/Remove Items from anywhere in the build calc timeline.md", + "Tasks/Plan Calculator.md", + "Tasks/More Wait Tests.md", + "Tasks/Nice looking map refrence.md", "Tasks/Make Tests for the Build Calculator.md", - "Images", - "Images/Pasted image 20260601083019.png", - "Images/Pasted image 20260601083046.png", - "Images/Pasted image 20260601083101.png", - "Images/Pasted image 20260601083113.png", + "Tasks/Make Examples be based on Database Information.md", + "Tasks/Make page object pattern structure for the Build Calculator and all it's components.md", + "Tasks/Language Support.md", + "Tasks/Jenkins CI.md", + "Tasks/Make a Plan to Fully Test the Calculator.md", + "Tasks/Improve your SEO.md", + "Tasks/Input building delay should have an effect on when a building is built. Tests against 0, 2, 4, 60.md", + "Tasks/Hotkey Tests.md", + "Tasks/Highest Alloy and Ether Tests.md", + "Tasks/Get AI to Add easy Test Tasks.md", + "Tasks/Helper Tutorial Info Improvements.md", + "Tasks/Fix Entity Recursion Error - Parent.md", + "Tasks/Fully Test the Build Calculator.md", + "Tasks/Ensure build order gets greyed out past the attack time. Clicking the cancel button will wipe the entire greyed out timeline..md", "Tasks", - "AI Help Docs", - "Images/Pasted image 20260601093506.png", + "Images/Pasted image 20260601093510.png", "Images/Pasted image 20260601083333.png", + "Images/Pasted image 20260601093506.png", "Images/Pasted image 20260601083206.png", + "Images/Pasted image 20260601083127.png", + "Images/Pasted image 20260601083147.png", + "Images/Pasted image 20260601083113.png", + "Images/Pasted image 20260601083101.png", + "Images/Pasted image 20260601083030.png", + "Images/Pasted image 20260601083046.png", + "Images", + "AI Help Docs", "AI Gen Docs", "AI Gen Tasks" ] diff --git a/docs/AI Help Docs/publish-and-serve.md b/docs/AI Help Docs/publish-and-serve.md index ff35ad1..b15798a 100644 --- a/docs/AI Help Docs/publish-and-serve.md +++ b/docs/AI Help Docs/publish-and-serve.md @@ -7,7 +7,7 @@ Ran `dotnet publish` targeting Release configuration, outputting to `publish_release/`: ``` -dotnet publish .\IGP\IGP.csproj -c Release -o .\publish_release +dotnet publish .\Web\Web.csproj -c Release -o .\publish_release ``` This produced a standard Blazor WASM publish layout: diff --git a/docs/Feature Proposals.md b/docs/Feature Proposals.md new file mode 100644 index 0000000..6d0acc5 --- /dev/null +++ b/docs/Feature Proposals.md @@ -0,0 +1,227 @@ +# Feature Proposals: Glossary & Tech Tree + +## Glossary / Mechanics Explainer + +### Goal + +Provide inline tooltips and a browsable reference for game-specific terms (resources, mechanics, roles, etc.) with automatic cross-linking whenever those terms appear in entity descriptions, notes, or tooltips. + +### Data Model + +Add a new model under `Model/`: + +**`Model/Glossary/GlossaryTermModel.cs`** +``` +- Id (string, e.g. "glossary_pyre") +- Term (string, e.g. "Pyre") +- ShortDefinition (string, ~1-2 sentences for tooltips) +- LongDefinition (string, markdown-capable for glossary page) +- Category (string, e.g. "Resource", "Mechanic", "Faction", "Role") +- RelatedTermIds (List — cross-links to other glossary terms) +- RelatedEntityIds (List — entities that exemplify this term) +``` + +**Term Catalog** — Seed ~20–40 terms covering: +- Resources: Alloy, Ether, Pyre, Energy, Supply +- Mechanics: Vanguard, Morph, Pyre Spells, Immortals, Suppression, Overgrowth, Shield +- Roles (from `DescriptiveType.cs`): Frontliner, Skirmisher, Support, Generalist, etc. +- Factions: Aru, Q'Rath, etc. +- Stats: Armor types (Light, Medium, Heavy, Etheric, Structure), Movement types +- RTS concepts: Tier, Tech, Morph, Harass, Timing + +### Service Layer + +**`Services/Website/GlossaryService.cs`** — implement `IGlossaryService` (add interface to `IServices.cs`): +- `GetTerm(string id) — GlossaryTermModel?` +- `SearchTerms(string query) — List` +- `GetTermsByCategory(string category) — List` +- `GetAllTerms() — List` +- `LinkifyText(string text) — MarkupString` — scans text for known terms and wraps them in tooltip/clickable links + +### Component Layer + +**`Components/Display/GlossaryTooltipComponent.razor`** +- Wraps a term name with a hover tooltip showing `ShortDefinition` +- On click, opens the glossary detail (either a dialog or navigates to a glossary page) +- Reuses the existing `InfoTooltipComponent` pattern (css hover) but upgraded to be interactive + +**`Components/Inputs/GlossaryLabelComponent.razor`** +- Like `EntityLabelComponent` but for glossary terms +- Renders a styled `