{ if (hotkey.KeyText.Equals(HotKeyType.SPACE.ToString())) { if (keyService.IsHoldingSpace()) { keyService.RemovePressedKey(hotkey.KeyText); } else { keyService.AddPressedKey(hotkey.KeyText); } } else { keyService.AddPressedKey(hotkey.KeyText); keyService.RemovePressedKey(hotkey.KeyText); }}" style="background-color:@color;
+
ButtonClicked(e, hotkey))" style="background-color:@color;
border: @border;
width: @Size.ToString()px;
height: @Size.ToString()px;
@@ -73,7 +75,7 @@
var isVanguard = entity.VanguardAdded() != null;
var style = isVanguard ? "font-weight: bold;" : "";
- if (buildOrderService.WillMeetRequirements(entity) == null)
+ if (BuildOrderService.WillMeetRequirements(entity) == null)
{
style += "color:gray; font-style: italic;";
}
@@ -122,25 +124,25 @@
{
base.OnInitialized();
- keyService.Subscribe(OnKeyPressed);
- filterService.Subscribe(StateHasChanged);
- buildOrderService.Subscribe(OnBuilderOrderChanged);
+ KeyService.Subscribe(OnKeyPressed);
+ FilterService.Subscribe(StateHasChanged);
+ BuildOrderService.Subscribe(OnBuilderOrderChanged);
}
void IDisposable.Dispose()
{
- keyService.Unsubscribe(OnKeyPressed);
- filterService.Unsubscribe(StateHasChanged);
- buildOrderService.Unsubscribe(OnBuilderOrderChanged);
+ KeyService.Unsubscribe(OnKeyPressed);
+ FilterService.Unsubscribe(StateHasChanged);
+ BuildOrderService.Unsubscribe(OnBuilderOrderChanged);
}
int completedTimeCount = 0;
void OnBuilderOrderChanged()
{
- if (buildOrderService.UniqueCompletedTimes.Count != completedTimeCount)
+ if (BuildOrderService.UniqueCompletedTimes.Count != completedTimeCount)
{
- completedTimeCount = buildOrderService.UniqueCompletedTimes.Count;
+ completedTimeCount = BuildOrderService.UniqueCompletedTimes.Count;
StateHasChanged();
}
}
@@ -148,7 +150,7 @@
protected override bool ShouldRender()
{
#if DEBUG
- jsRuntime.InvokeVoidAsync("console.time", "HotKeyViewerComponent");
+ JsRuntime.InvokeVoidAsync("console.time", "HotKeyViewerComponent");
#endif
return true;
@@ -157,14 +159,14 @@
protected override void OnAfterRender(bool firstRender)
{
#if DEBUG
- jsRuntime.InvokeVoidAsync("console.timeEnd", "HotKeyViewerComponent");
+ JsRuntime.InvokeVoidAsync("console.timeEnd", "HotKeyViewerComponent");
#endif
}
// Move to Filter Service
bool InvalidFaction(EntityModel entity)
{
- if (entity.Faction() != null && entity.Faction()?.Faction != filterService.GetFaction() && filterService.GetFaction() != DataType.Any)
+ if (entity.Faction() != null && entity.Faction()?.Faction != FilterService.GetFaction() && FilterService.GetFaction() != DataType.Any)
{
return true;
}
@@ -176,8 +178,8 @@
bool InvalidVanguard(EntityModel entity)
{
if (entity.VanguardAdded() != null
- && entity.VanguardAdded()?.ImmortalId != filterService.GetImmortal()
- && filterService.GetImmortal() != DataType.Any)
+ && entity.VanguardAdded()?.ImmortalId != FilterService.GetImmortal()
+ && FilterService.GetImmortal() != DataType.Any)
{
return true;
}
@@ -192,7 +194,7 @@
{
foreach (var replaced in entity.Replaceds())
{
- if (filterService.GetImmortal() == replaced.ImmortalId)
+ if (FilterService.GetImmortal() == replaced.ImmortalId)
{
return true;
}
@@ -241,7 +243,7 @@
bool InvalidHoldSpace(EntityModel entity)
{
- if (entity.Hotkey()?.HoldSpace == keyService.IsHoldingSpace())
+ if (entity.Hotkey()?.HoldSpace == KeyService.IsHoldingSpace())
{
return false;
}
@@ -254,44 +256,44 @@
var keyWas = key;
- if (keyService.GetAllPressedKeys().Contains("Z"))
+ if (KeyService.GetAllPressedKeys().Contains("Z"))
{
controlGroup = "Z";
}
- if (keyService.GetAllPressedKeys().Contains("TAB"))
+ if (KeyService.GetAllPressedKeys().Contains("TAB"))
{
controlGroup = "TAB";
}
- if (keyService.GetAllPressedKeys().Contains("C"))
+ if (KeyService.GetAllPressedKeys().Contains("C"))
{
controlGroup = "C";
}
- if (keyService.GetAllPressedKeys().Contains("D"))
+ if (KeyService.GetAllPressedKeys().Contains("D"))
{
controlGroup = "D";
}
- if (keyService.GetAllPressedKeys().Contains("1"))
+ if (KeyService.GetAllPressedKeys().Contains("1"))
{
controlGroup = "1";
}
//TODO This could be better. Duplicated code
- if (keyService.GetAllPressedKeys().Contains("2"))
+ if (KeyService.GetAllPressedKeys().Contains("2"))
{
controlGroup = "2";
}
- if (keyService.GetAllPressedKeys().Contains("SHIFT"))
+ if (KeyService.GetAllPressedKeys().Contains("SHIFT"))
{
controlGroup = "SHIFT";
}
- if (keyService.GetAllPressedKeys().Contains("CONTROL"))
+ if (KeyService.GetAllPressedKeys().Contains("CONTROL"))
{
controlGroup = "CONTROL";
}
- if (keyService.GetAllPressedKeys().Count > 0)
+ if (KeyService.GetAllPressedKeys().Count > 0)
{
- key = keyService.GetAllPressedKeys().First();
+ key = KeyService.GetAllPressedKeys().First();
}
if (controlGroupWas != controlGroup || keyWas != key)
@@ -303,7 +305,7 @@
private void HandleClick()
{
- var hotkey = keyService.GetHotkey();
+ var hotkey = KeyService.GetHotkey();
if (hotkey == "")
{
@@ -312,15 +314,15 @@
if (hotkey == "`")
{
- buildOrderService.RemoveLast();
- economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
+ BuildOrderService.RemoveLast();
+ EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
return;
}
- var hotkeyGroup = keyService.GetHotkeyGroup();
- var isHoldSpace = keyService.IsHoldingSpace();
- var faction = filterService.GetFaction();
- var immortal = filterService.GetImmortal();
+ var hotkeyGroup = KeyService.GetHotkeyGroup();
+ var isHoldSpace = KeyService.IsHoldingSpace();
+ var faction = FilterService.GetFaction();
+ var immortal = FilterService.GetImmortal();
var entity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal);
@@ -329,9 +331,35 @@
return;
}
- if (buildOrderService.Add(entity, economyService))
+ if (BuildOrderService.Add(entity, EconomyService))
{
- economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
+ EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
+ }
+ }
+
+ private void ButtonClicked(MouseEventArgs mouseEventArgs, HotkeyModel hotkey)
+ {
+ DataCollectionService.SendEvent(
+ DataCollectionKeys.BuildCalcInput,
+ new Dictionary
{{"key", hotkey.KeyText.ToLower()}, {"input-source", "mouse"}}
+ );
+
+
+ if (hotkey.KeyText.Equals(HotKeyType.SPACE.ToString()))
+ {
+ if (KeyService.IsHoldingSpace())
+ {
+ KeyService.RemovePressedKey(hotkey.KeyText);
+ }
+ else
+ {
+ KeyService.AddPressedKey(hotkey.KeyText);
+ }
+ }
+ else
+ {
+ KeyService.AddPressedKey(hotkey.KeyText);
+ KeyService.RemovePressedKey(hotkey.KeyText);
}
}
diff --git a/IGP/Pages/BuildCalculator/Parts/InputPanelComponent.razor b/IGP/Pages/BuildCalculator/Parts/InputPanelComponent.razor
index 3d763e5..8a5439c 100644
--- a/IGP/Pages/BuildCalculator/Parts/InputPanelComponent.razor
+++ b/IGP/Pages/BuildCalculator/Parts/InputPanelComponent.razor
@@ -1,6 +1,8 @@
-@inject IKeyService keyService
+@using Services.Website
+@inject IKeyService KeyService
-@inject IJSRuntime jsRuntime;
+@inject IDataCollectionService DataCollectionService
+@inject IJSRuntime JsRuntime
{{"key", e.Key.ToLower()}, {"input-source", "keyboard"}}
+ );
+
+ KeyService.AddPressedKey(e.Key);
}
private void HandleKeyUp(KeyboardEventArgs e)
{
- keyService.RemovePressedKey(e.Key);
+ KeyService.RemovePressedKey(e.Key);
}
protected override bool ShouldRender()
{
#if DEBUG
- jsRuntime.InvokeVoidAsync("console.time", "InputPanelComponent");
+ JsRuntime.InvokeVoidAsync("console.time", "InputPanelComponent");
#endif
return true;
@@ -39,7 +46,7 @@
protected override void OnAfterRender(bool firstRender)
{
#if DEBUG
- jsRuntime.InvokeVoidAsync("console.timeEnd", "InputPanelComponent");
+ JsRuntime.InvokeVoidAsync("console.timeEnd", "InputPanelComponent");
#endif
}
diff --git a/IGP/Pages/BuildCalculator/Parts/OptionsComponent.razor b/IGP/Pages/BuildCalculator/Parts/OptionsComponent.razor
index 3ca58ba..40c62d3 100644
--- a/IGP/Pages/BuildCalculator/Parts/OptionsComponent.razor
+++ b/IGP/Pages/BuildCalculator/Parts/OptionsComponent.razor
@@ -52,6 +52,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
TimingService.Subscribe(RefreshDefaults);
RefreshDefaults();
diff --git a/IGP/Pages/BuildCalculator/Parts/TimelineComponent.razor b/IGP/Pages/BuildCalculator/Parts/TimelineComponent.razor
index bbb9599..825d7f3 100644
--- a/IGP/Pages/BuildCalculator/Parts/TimelineComponent.razor
+++ b/IGP/Pages/BuildCalculator/Parts/TimelineComponent.razor
@@ -58,6 +58,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
economyService.Subscribe(StateHasChanged);
buildOrderService.Subscribe(StateHasChanged);
}
diff --git a/IGP/Pages/BuildCalculator/Parts/TimingComponent.razor b/IGP/Pages/BuildCalculator/Parts/TimingComponent.razor
index 9cdab07..c2e4850 100644
--- a/IGP/Pages/BuildCalculator/Parts/TimingComponent.razor
+++ b/IGP/Pages/BuildCalculator/Parts/TimingComponent.razor
@@ -33,6 +33,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
timingService.Subscribe(StateHasChanged);
}
diff --git a/IGP/Pages/ChangeLogPage.razor b/IGP/Pages/ChangeLogPage.razor
index 8b4b247..62c5611 100644
--- a/IGP/Pages/ChangeLogPage.razor
+++ b/IGP/Pages/ChangeLogPage.razor
@@ -1,11 +1,16 @@
@page "/changelog"
@implements IDisposable;
-@inject IGitService gitService;
+@inject IGitService GitService;
+
+@inherits BasePage
+
+@inject IDataCollectionService DataCollectionService
+
@layout PageLayout
-@if (gitService.IsLoaded())
+@if (GitService.IsLoaded())
{
Change Log
@@ -90,21 +95,22 @@ else
@code {
- private IEnumerable Patches => gitService.GitPatchModels;
+ private IEnumerable Patches => GitService.GitPatchModels;
- private List Changes => gitService.GitChangeModels;
+ private List Changes => GitService.GitChangeModels;
private bool isViewImportant = true;
protected override void OnInitialized()
{
- gitService.Subscribe(HasChanged);
+ base.OnInitialized();
+ GitService.Subscribe(HasChanged);
}
void IDisposable.Dispose()
{
- gitService.Unsubscribe(HasChanged);
+ GitService.Unsubscribe(HasChanged);
}
@@ -121,7 +127,7 @@ else
protected override async Task OnInitializedAsync()
{
- await gitService.Load();
+ await GitService.Load();
}
}
\ No newline at end of file
diff --git a/IGP/Pages/Comparision/ComparisionPage.razor b/IGP/Pages/Comparision/ComparisionPage.razor
index 49da43f..8545166 100644
--- a/IGP/Pages/Comparision/ComparisionPage.razor
+++ b/IGP/Pages/Comparision/ComparisionPage.razor
@@ -1,7 +1,8 @@
@layout PageLayout
+@inherits BasePage
@implements IDisposable
-@inject IToastService toastService
+@inject IToastService ToastService
protected override void OnInitialized()
{
+ base.OnInitialized();
KeyService.Subscribe(HandleClick);
FilterService.Subscribe(StateHasChanged);
EconomyService.Subscribe(StateHasChanged);
diff --git a/IGP/Pages/Comparision/Parts/BuildLoaderComponent.razor b/IGP/Pages/Comparision/Parts/BuildLoaderComponent.razor
index 0c222f6..229efff 100644
--- a/IGP/Pages/Comparision/Parts/BuildLoaderComponent.razor
+++ b/IGP/Pages/Comparision/Parts/BuildLoaderComponent.razor
@@ -20,6 +20,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
BuildComparisionService.Subscribe(StateHasChanged);
}
diff --git a/IGP/Pages/Comparision/Parts/SandComponent.razor b/IGP/Pages/Comparision/Parts/SandComponent.razor
index 1dae56d..e8fac2b 100644
--- a/IGP/Pages/Comparision/Parts/SandComponent.razor
+++ b/IGP/Pages/Comparision/Parts/SandComponent.razor
@@ -13,6 +13,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
BuildComparisonService.Subscribe(StateHasChanged);
}
diff --git a/IGP/Pages/ContactPage.razor b/IGP/Pages/ContactPage.razor
index 862a328..5bf660e 100644
--- a/IGP/Pages/ContactPage.razor
+++ b/IGP/Pages/ContactPage.razor
@@ -1,5 +1,8 @@
@layout PageLayout
+@inject IDataCollectionService DataCollectionService
+@inherits BasePage
+
@page "/contact"
diff --git a/IGP/Pages/DataCollectionPage.razor b/IGP/Pages/DataCollectionPage.razor
index 8d4fa5a..577b25e 100644
--- a/IGP/Pages/DataCollectionPage.razor
+++ b/IGP/Pages/DataCollectionPage.razor
@@ -1,5 +1,8 @@
@page "/data-collection"
+@inject IDataCollectionService DataCollectionService
+@inherits BasePage
+
@layout PageLayout
diff --git a/IGP/Pages/Database/DatabasePage.razor b/IGP/Pages/Database/DatabasePage.razor
index 0e0cc55..3d9d702 100644
--- a/IGP/Pages/Database/DatabasePage.razor
+++ b/IGP/Pages/Database/DatabasePage.razor
@@ -1,11 +1,12 @@
@layout PageLayout
-
+@inherits BasePage
@page "/database"
@implements IDisposable
-@inject IEntityDisplayService entityDisplayService
-@inject IVariableService variableService
+@inject IEntityDisplayService EntityDisplayService
+@inject IVariableService VariableService
+
Database
@@ -13,13 +14,13 @@
- Game Patch: @variableService.Variables["GamePatch"]
+ Game Patch: @VariableService.Variables["GamePatch"]
-
+
@@ -31,7 +32,7 @@
@foreach (var entity in searches)
{
-
+
@@ -67,7 +68,7 @@
Is this database updated to the latest version?
- Maybe. Check this @variableService.Variables["GamePatch"] version number, and compare it to the number on discord, in the #game-updates channel. That should give a general sense of how out of date the data is.
+ Maybe. Check this @VariableService.Variables["GamePatch"] version number, and compare it to the number on discord, in the #game-updates channel. That should give a general sense of how out of date the data is.
@@ -134,16 +135,17 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
RefreshFactionSearch();
EntityFilterService.Subscribe(OnChange);
- entityDisplayService.Subscribe(StateHasChanged);
+ EntityDisplayService.Subscribe(StateHasChanged);
}
void IDisposable.Dispose()
{
EntityFilterService.Unsubscribe(OnChange);
- entityDisplayService.Unsubscribe(StateHasChanged);
+ EntityDisplayService.Unsubscribe(StateHasChanged);
}
void OnChange(EntityFilterEvent filterEntityEvent)
diff --git a/IGP/Pages/Database/DatabaseSinglePage.razor b/IGP/Pages/Database/DatabaseSinglePage.razor
index 030916a..478dc71 100644
--- a/IGP/Pages/Database/DatabaseSinglePage.razor
+++ b/IGP/Pages/Database/DatabaseSinglePage.razor
@@ -1,24 +1,27 @@
@layout PageLayout
+@inherits BasePage
+
@page "/database/{text}"
-@inject IEntityDisplayService entityDisplayService
+@inject IEntityDisplayService EntityDisplayService
+@inject IVariableService VariableService
-@inject IVariableService variableService
@implements IDisposable
+
- Game Patch: @variableService.Variables["GamePatch"]
+ Game Patch: @VariableService.Variables["GamePatch"]
-
+
@@ -33,7 +36,7 @@
}
- else if (entity == null)
+ else if (_entity == null)
{
Invalid entity name entered: @Text
@@ -44,8 +47,8 @@
else
{
-
-
+
+
@@ -62,17 +65,28 @@
[Parameter]
public string? Text { get; set; }
- private EntityModel? entity;
+ private EntityModel? _entity;
protected override void OnInitialized()
{
- entityDisplayService.Subscribe(StateHasChanged);
+ EntityDisplayService.Subscribe(StateHasChanged);
+ }
+ protected override void OnParametersSet()
+ {
+ base.OnParametersSet();
+ base.OnInitialized();
+
+ FocusEntity();
+ }
+
+ private void FocusEntity()
+ {
foreach (var e in DATA.Get().Values)
{
if (e.Info().Name.ToLower().Equals(Text!.ToLower()))
{
- entity = e;
+ _entity = e;
return;
}
}
@@ -80,7 +94,7 @@
void IDisposable.Dispose()
{
- entityDisplayService.Unsubscribe(StateHasChanged);
+ EntityDisplayService.Unsubscribe(StateHasChanged);
}
}
\ No newline at end of file
diff --git a/IGP/Pages/Database/Entity/Parts/EntityWeaponsComponent.razor b/IGP/Pages/Database/Entity/Parts/EntityWeaponsComponent.razor
index 451b7df..b5d7cf2 100644
--- a/IGP/Pages/Database/Entity/Parts/EntityWeaponsComponent.razor
+++ b/IGP/Pages/Database/Entity/Parts/EntityWeaponsComponent.razor
@@ -244,6 +244,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
StorageService.Subscribe(RefreshDefaults);
}
diff --git a/IGP/Pages/Database/Parts/EntityFilterComponent.razor b/IGP/Pages/Database/Parts/EntityFilterComponent.razor
index cc3c3c4..f93436f 100644
--- a/IGP/Pages/Database/Parts/EntityFilterComponent.razor
+++ b/IGP/Pages/Database/Parts/EntityFilterComponent.razor
@@ -213,6 +213,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
}
void OnChangeFaction(string clickedFaction)
diff --git a/IGP/Pages/Documentation/DocumentationIndexPage.razor b/IGP/Pages/Documentation/DocumentationIndexPage.razor
index 9ed77b0..52b9588 100644
--- a/IGP/Pages/Documentation/DocumentationIndexPage.razor
+++ b/IGP/Pages/Documentation/DocumentationIndexPage.razor
@@ -1,11 +1,12 @@
@layout PageLayout
+@inherits BasePage
-@inject IDocumentationService documentationService
+@inject IDocumentationService DocumentationService
@implements IDisposable
@page "/docs"
-@if (!documentationService.IsLoaded())
+@if (!DocumentationService.IsLoaded())
{
}
@@ -13,7 +14,7 @@ else
{
- @foreach (var docSection in documentationService.DocSectionModels)
+ @foreach (var docSection in DocumentationService.DocSectionModels)
{
@docSection.Name
@@ -102,14 +103,15 @@ else
protected override void OnInitialized()
{
- documentationService.Subscribe(StateHasChanged);
+ base.OnInitialized();
+ DocumentationService.Subscribe(StateHasChanged);
- documentationService.Load();
+ DocumentationService.Load();
}
void IDisposable.Dispose()
{
- documentationService.Unsubscribe(StateHasChanged);
+ DocumentationService.Unsubscribe(StateHasChanged);
}
}
\ No newline at end of file
diff --git a/IGP/Pages/Documentation/DocumentationPage.razor b/IGP/Pages/Documentation/DocumentationPage.razor
index 3db1bb4..cde5e63 100644
--- a/IGP/Pages/Documentation/DocumentationPage.razor
+++ b/IGP/Pages/Documentation/DocumentationPage.razor
@@ -1,12 +1,13 @@
@layout PageLayout
+@inherits BasePage
-@inject IDocumentationService documentationService
+@inject IDocumentationService DocumentationService
@implements IDisposable
@page "/docs/{href1}/{href2?}/{href3?}/{href4?}/{href5?}"
-@if (!documentationService.IsLoaded())
+@if (!DocumentationService.IsLoaded())
{
}
@@ -15,12 +16,12 @@ else
+ Connections="DocumentationService.DocConnectionModels"
+ Documents="DocumentationService.DocContentModels"/>
- @foreach (var doc in documentationService.DocContentModels)
+ @foreach (var doc in DocumentationService.DocContentModels)
{
if (!doc.Href.Equals(Href))
{
@@ -108,14 +109,15 @@ else
protected override void OnInitialized()
{
- documentationService.Subscribe(StateHasChanged);
+ base.OnInitialized();
+ DocumentationService.Subscribe(StateHasChanged);
- documentationService.Load();
+ DocumentationService.Load();
}
void IDisposable.Dispose()
{
- documentationService.Unsubscribe(StateHasChanged);
+ DocumentationService.Unsubscribe(StateHasChanged);
}
}
\ No newline at end of file
diff --git a/IGP/Pages/EconomyComparison/EconomyComparisonPage.razor b/IGP/Pages/EconomyComparison/EconomyComparisonPage.razor
index 8564799..227ffc8 100644
--- a/IGP/Pages/EconomyComparison/EconomyComparisonPage.razor
+++ b/IGP/Pages/EconomyComparison/EconomyComparisonPage.razor
@@ -1,5 +1,7 @@
@page "/economy-comparison"
+@inherits BasePage
+
@implements IDisposable
@inject IEconomyComparisonService EconomyComparisonService
@layout PageLayout
@@ -40,6 +42,7 @@
@code {
protected override void OnInitialized()
{
+ base.OnInitialized();
EconomyComparisonService.Subscribe(StateHasChanged);
}
diff --git a/IGP/Pages/EconomyComparison/Parts/ChartComponent.razor b/IGP/Pages/EconomyComparison/Parts/ChartComponent.razor
index 14d2b39..8c360c3 100644
--- a/IGP/Pages/EconomyComparison/Parts/ChartComponent.razor
+++ b/IGP/Pages/EconomyComparison/Parts/ChartComponent.razor
@@ -62,6 +62,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
economyComparisonService.Subscribe(OnBuilderOrderChanged);
OnBuilderOrderChanged();
diff --git a/IGP/Pages/EconomyComparison/Parts/EconomyDifferenceComponent.razor b/IGP/Pages/EconomyComparison/Parts/EconomyDifferenceComponent.razor
index 6f5f158..324d0b2 100644
--- a/IGP/Pages/EconomyComparison/Parts/EconomyDifferenceComponent.razor
+++ b/IGP/Pages/EconomyComparison/Parts/EconomyDifferenceComponent.razor
@@ -72,6 +72,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
economyComparisonService.Subscribe(CalculateDifferences);
}
diff --git a/IGP/Pages/EconomyComparison/Parts/EconomyInputComponent.razor b/IGP/Pages/EconomyComparison/Parts/EconomyInputComponent.razor
index 6f62884..6451254 100644
--- a/IGP/Pages/EconomyComparison/Parts/EconomyInputComponent.razor
+++ b/IGP/Pages/EconomyComparison/Parts/EconomyInputComponent.razor
@@ -49,6 +49,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
economyComparisonService.Subscribe(StateHasChanged);
}
diff --git a/IGP/Pages/HarassCalculatorPage.razor b/IGP/Pages/HarassCalculatorPage.razor
index da13b9d..0363c68 100644
--- a/IGP/Pages/HarassCalculatorPage.razor
+++ b/IGP/Pages/HarassCalculatorPage.razor
@@ -1,5 +1,8 @@
@layout PageLayout
+@inject IDataCollectionService DataCollectionService
+@inherits BasePage
+
@page "/harass-calculator"
@using Model
@@ -261,6 +264,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
Calculate();
}
diff --git a/IGP/Pages/Home/HomePage.razor b/IGP/Pages/Home/HomePage.razor
index 9109b5d..67e08a6 100644
--- a/IGP/Pages/Home/HomePage.razor
+++ b/IGP/Pages/Home/HomePage.razor
@@ -1,5 +1,7 @@
@layout PageLayout;
+@inherits BasePage
+
@page "/immortal-home"
diff --git a/IGP/Pages/MakingOf/MakingOfPage.razor b/IGP/Pages/MakingOf/MakingOfPage.razor
index 8b9a9d9..6a58e9d 100644
--- a/IGP/Pages/MakingOf/MakingOfPage.razor
+++ b/IGP/Pages/MakingOf/MakingOfPage.razor
@@ -1,5 +1,9 @@
@page "/makingof"
+@inherits BasePage
+
+@inject IDataCollectionService DataCollectionService
+
@layout PageLayout
diff --git a/IGP/Pages/MemoryTester/MemoryTesterPage.razor b/IGP/Pages/MemoryTester/MemoryTesterPage.razor
index 3812188..b5d720c 100644
--- a/IGP/Pages/MemoryTester/MemoryTesterPage.razor
+++ b/IGP/Pages/MemoryTester/MemoryTesterPage.razor
@@ -1,5 +1,7 @@
@layout PageLayout
+@inherits BasePage
+
@page "/memory-tester"
diff --git a/IGP/Pages/MemoryTester/Parts/UnitMemory.razor b/IGP/Pages/MemoryTester/Parts/UnitMemory.razor
index b146c56..ed6becc 100644
--- a/IGP/Pages/MemoryTester/Parts/UnitMemory.razor
+++ b/IGP/Pages/MemoryTester/Parts/UnitMemory.razor
@@ -62,6 +62,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
MemoryTesterService.Subscribe(OnMemoryEvent);
OnRefresh();
diff --git a/IGP/Pages/MemoryTester/Parts/UnitMemoryManager.razor b/IGP/Pages/MemoryTester/Parts/UnitMemoryManager.razor
index 525abea..2900c96 100644
--- a/IGP/Pages/MemoryTester/Parts/UnitMemoryManager.razor
+++ b/IGP/Pages/MemoryTester/Parts/UnitMemoryManager.razor
@@ -64,6 +64,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
MemoryTesterService.Subscribe(OnMemoryEvent);
MemoryTesterService.GenerateQuiz();
diff --git a/IGP/Pages/Notes/NotesIndexPage.razor b/IGP/Pages/Notes/NotesIndexPage.razor
index 56ead8b..f32a826 100644
--- a/IGP/Pages/Notes/NotesIndexPage.razor
+++ b/IGP/Pages/Notes/NotesIndexPage.razor
@@ -1,12 +1,16 @@
@layout PageLayout
-@inject INoteService noteService
+@inherits BasePage
+
+@inject INoteService NoteService
@implements IDisposable
+@inject IDataCollectionService DataCollectionService
+
@page "/notes"
-@if (!noteService.IsLoaded())
+@if (!NoteService.IsLoaded())
{
}
@@ -15,7 +19,7 @@ else
- @foreach (var noteSection in noteService.NoteSectionModels)
+ @foreach (var noteSection in NoteService.NoteSectionModels)
{
@noteSection.Name
@@ -119,15 +123,16 @@ else
protected override void OnInitialized()
{
- noteService.Subscribe(StateHasChanged);
+ base.OnInitialized();
+ NoteService.Subscribe(StateHasChanged);
- noteService.Load();
+ NoteService.Load();
}
void IDisposable.Dispose()
{
- noteService.Unsubscribe(StateHasChanged);
+ NoteService.Unsubscribe(StateHasChanged);
}
diff --git a/IGP/Pages/Notes/NotesPage.razor b/IGP/Pages/Notes/NotesPage.razor
index 3c8c100..a9e9936 100644
--- a/IGP/Pages/Notes/NotesPage.razor
+++ b/IGP/Pages/Notes/NotesPage.razor
@@ -1,12 +1,16 @@
@layout PageLayout
-@inject INoteService noteService
+@inherits BasePage
+
+@inject INoteService NoteService
@implements IDisposable
+@inject IDataCollectionService DataCollectionService
+
@page "/notes/{href1}/{href2?}/{href3?}/{href4?}/{href5?}"
-@if (!noteService.IsLoaded())
+@if (!NoteService.IsLoaded())
{
}
@@ -15,12 +19,12 @@ else
+ Connections="NoteService.NoteConnectionModels"
+ Notes="NoteService.NoteContentModels"/>
- @foreach (var note in noteService.NoteContentModels)
+ @foreach (var note in NoteService.NoteContentModels)
{
if (!note.Href.Equals(Href))
{
@@ -107,14 +111,15 @@ else
protected override void OnInitialized()
{
- noteService.Subscribe(StateHasChanged);
+ base.OnInitialized();
+ NoteService.Subscribe(StateHasChanged);
- noteService.Load();
+ NoteService.Load();
}
void IDisposable.Dispose()
{
- noteService.Unsubscribe(StateHasChanged);
+ NoteService.Unsubscribe(StateHasChanged);
}
}
\ No newline at end of file
diff --git a/IGP/Pages/PermissionsPage.razor b/IGP/Pages/PermissionsPage.razor
index 97430bb..9652676 100644
--- a/IGP/Pages/PermissionsPage.razor
+++ b/IGP/Pages/PermissionsPage.razor
@@ -2,24 +2,27 @@
@inject IPermissionService PermissionService
@layout PageLayout
-@using Services.Website
-@inject Blazored.LocalStorage.ILocalStorageService LocalStorage
+@inject IDialogService DialogService
+
+@inherits BasePage
+@using Services.Website
@implements IDisposable
-
-
@@ -44,7 +47,10 @@
What data does this website collect?
- This website usages Google Analytics to collect data enabled on the Analytics page.
+ This website usages Google Analytics to collect data on usage of this website.
+
+ Items include: if people use keyboard or mouse in build calculator, what pages people visit, and other usages.
+
@@ -58,38 +64,60 @@
@code {
private bool _storageEnabled = false;
private bool _dataCollectionEnabled = false;
-
+
protected override void OnInitialized()
{
PermissionService.Subscribe(Update);
Update();
}
-
+
void Update()
{
_storageEnabled = PermissionService.GetIsStorageEnabled();
_dataCollectionEnabled = PermissionService.GetIsDataCollectionEnabled();
-
StateHasChanged();
}
-
+
void IDisposable.Dispose()
{
PermissionService.Unsubscribe(Update);
}
-
-
private void StoragePermissionChanged(ChangeEventArgs obj)
{
- PermissionService.SetIsStorageEnabled((bool)obj.Value!);
+ PermissionService.SetIsStorageEnabled(!PermissionService.GetIsStorageEnabled());
}
+
private void DataCollectionPermissionChanged(ChangeEventArgs obj)
{
- PermissionService.SetIsDataCollectionEnabled((bool)obj.Value!);
+ void OnDataCollectionConfirmClicked(MouseEventArgs mouseEventArgs)
+ {
+ PermissionService.SetIsDataCollectionEnabled(!PermissionService.GetIsDataCollectionEnabled());
+ DialogService.Hide();
+ }
+
+ void OnDataCollectionCancelClicked(MouseEventArgs mouseEventArgs)
+ {
+ DialogService.Hide();
+ }
+
+ if (_storageEnabled && !PermissionService.GetIsDataCollectionEnabled())
+ {
+ DialogService.Show(new DialogContents
+ {
+ Title = "Permission Request",
+ Message = "Are you sure you want to enable data collection? This feature is implemented with Google Analytics, and your data will be used to gauge interests, find bugs, and optimize updates in IGP Fan Reference.",
+ OnConfirm = new EventCallback(this, OnDataCollectionConfirmClicked),
+ OnCancel = new EventCallback(this, OnDataCollectionCancelClicked),
+ ConfirmButtonLabel = "Enable Data Collection"
+ });
+ }
+ else
+ {
+ PermissionService.SetIsDataCollectionEnabled(!PermissionService.GetIsDataCollectionEnabled());
+ }
}
-
}
\ No newline at end of file
diff --git a/IGP/Pages/RawDatabase.razor b/IGP/Pages/RawDatabase.razor
index 2d76508..5424025 100644
--- a/IGP/Pages/RawDatabase.razor
+++ b/IGP/Pages/RawDatabase.razor
@@ -1,4 +1,6 @@
-@page "/raw-database"
+@inherits BasePage
+
+@page "/raw-database"
diff --git a/IGP/Pages/RoadMap/RoadMapPage.razor b/IGP/Pages/RoadMap/RoadMapPage.razor
index cc7ea5d..2deeb68 100644
--- a/IGP/Pages/RoadMap/RoadMapPage.razor
+++ b/IGP/Pages/RoadMap/RoadMapPage.razor
@@ -1,5 +1,9 @@
@layout PageLayout
+@inherits BasePage
+
+@inject IDataCollectionService DataCollectionService
+
@page "/roadmap"
diff --git a/IGP/Pages/StoragePage.razor b/IGP/Pages/StoragePage.razor
index cfe6c7c..ba86ca0 100644
--- a/IGP/Pages/StoragePage.razor
+++ b/IGP/Pages/StoragePage.razor
@@ -1,5 +1,7 @@
@page "/storage"
+
+@inherits BasePage
@inject IStorageService StorageService
@using Services.Website
@implements IDisposable
@@ -145,6 +147,8 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
+
_enabledPermissions = StorageService.GetValue(StorageKeys.EnabledStorage);
RefreshDefaults();
diff --git a/IGP/Pages/StreamsPage.razor b/IGP/Pages/StreamsPage.razor
index d9a7732..fea5ba2 100644
--- a/IGP/Pages/StreamsPage.razor
+++ b/IGP/Pages/StreamsPage.razor
@@ -1,5 +1,7 @@
@page "/streams"
+@inherits BasePage
+
@layout PageLayout
diff --git a/IGP/Portals/ConfirmationDialogPortal.razor b/IGP/Portals/ConfirmationDialogPortal.razor
new file mode 100644
index 0000000..bf998ba
--- /dev/null
+++ b/IGP/Portals/ConfirmationDialogPortal.razor
@@ -0,0 +1,25 @@
+@implements IDisposable;
+
+@inject IDialogService DialogService
+
+
+
+@code {
+
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+ DialogService.Subscribe(OnUpdate);
+ }
+
+ void IDisposable.Dispose()
+ {
+ DialogService.Unsubscribe(OnUpdate);
+ }
+
+ void OnUpdate()
+ {
+ StateHasChanged();
+ }
+
+}
\ No newline at end of file
diff --git a/IGP/Portals/EntityDialogPortal.razor b/IGP/Portals/EntityDialogPortal.razor
index dbe7963..e7eedc6 100644
--- a/IGP/Portals/EntityDialogPortal.razor
+++ b/IGP/Portals/EntityDialogPortal.razor
@@ -12,6 +12,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
entityDialogService.Subscribe(OnUpdate);
}
diff --git a/IGP/Portals/SearchPortal.razor b/IGP/Portals/SearchPortal.razor
index edb81e2..e9a969d 100644
--- a/IGP/Portals/SearchPortal.razor
+++ b/IGP/Portals/SearchPortal.razor
@@ -1,29 +1,28 @@
@implements IDisposable;
-@inject ISearchService searchService
-@inject IJSRuntime jsRuntime
+@inject ISearchService SearchService
+@inject IJSRuntime JsRuntime
@code {
- private string test = "Q";
-
protected override void OnInitialized()
{
- searchService.Subscribe(OnUpdate);
+ base.OnInitialized();
+ SearchService.Subscribe(OnUpdate);
}
protected override async Task OnInitializedAsync()
{
- await searchService.Load();
- await jsRuntime.InvokeVoidAsync("SetDotnetReference", DotNetObjectReference.Create(this));
+ await SearchService.Load();
+ await JsRuntime.InvokeVoidAsync("SetDotnetReference", DotNetObjectReference.Create(this));
}
void IDisposable.Dispose()
{
- searchService.Unsubscribe(OnUpdate);
+ SearchService.Unsubscribe(OnUpdate);
}
void OnUpdate()
@@ -36,13 +35,13 @@
{
if (code.ToLower().Equals("k") && (ctrlKey || shiftKey || altKey || metaKey))
{
- if (searchService.IsVisible)
+ if (SearchService.IsVisible)
{
- searchService.Hide();
+ SearchService.Hide();
}
else
{
- searchService.Show();
+ SearchService.Show();
}
}
}
diff --git a/IGP/Portals/ToastPortal.razor b/IGP/Portals/ToastPortal.razor
index 48330a0..39d56e6 100644
--- a/IGP/Portals/ToastPortal.razor
+++ b/IGP/Portals/ToastPortal.razor
@@ -31,6 +31,7 @@
protected override void OnInitialized()
{
+ base.OnInitialized();
toastService.Subscribe(OnUpdate);
ageTimer = new Timer(10);
diff --git a/IGP/Program.cs b/IGP/Program.cs
index 9215e57..ba42259 100644
--- a/IGP/Program.cs
+++ b/IGP/Program.cs
@@ -1,6 +1,7 @@
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
+using Blazor.Analytics;
using Blazored.LocalStorage;
using IGP;
using Microsoft.AspNetCore.Components.Web;
@@ -9,6 +10,7 @@ using Services;
using Services.Development;
using Services.Immortal;
using Services.Website;
+
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");
@@ -19,8 +21,10 @@ builder.Logging.SetMinimumLevel(LogLevel.Warning);
builder.RootComponents.Add("#app");
builder.RootComponents.Add("head::after");
-builder.Services.AddSingleton(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
-builder.Services.AddSingleton();
+
+
+builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
+builder.Services.AddScoped();
builder.Services.AddProtectedBrowserStorage();
@@ -37,32 +41,40 @@ builder.Services.AddBlazoredLocalStorageAsSingleton(config =>
config.JsonSerializerOptions.WriteIndented = false;
});
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-
-builder.Services.AddSingleton();
-builder.Services.AddSingleton();
-
-builder.Services.AddSingleton();
-
-builder.Services.AddSingleton(new HttpClient
+#if DEBUG
+builder.Services.AddGoogleAnalytics("G-S96LW7TVFY");
+#else
+builder.Services.AddGoogleAnalytics(builder.Configuration["GA-Tag"]);
+#endif
+
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+
+builder.Services.AddScoped();
+
+
+builder.Services.AddScoped(sp => new HttpClient
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
diff --git a/IGP/_Imports.razor b/IGP/_Imports.razor
index 22c0c1c..74a4d0a 100644
--- a/IGP/_Imports.razor
+++ b/IGP/_Imports.razor
@@ -58,4 +58,7 @@
@using Services.Immortal
@using System.Globalization
@using System.Reflection
-@using System.Timers
\ No newline at end of file
+@using System.Timers
+@using Blazor.Analytics
+@using Blazor.Analytics.Components
+@using Blazor.Analytics.Abstractions
diff --git a/IGP/wwwroot/generated/AgileTaskModels.json b/IGP/wwwroot/generated/AgileTaskModels.json
index af482e7..66a9b0a 100644
--- a/IGP/wwwroot/generated/AgileTaskModels.json
+++ b/IGP/wwwroot/generated/AgileTaskModels.json
@@ -1 +1 @@
-[{"Id":1,"AgileSprintModelId":null,"Name":"Support Safari","Description":"Consider other web browsers.","Notes":"Added","Status":"Todo","Priority":"Low","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":"2022-02-20T00:00:00"},{"Id":2,"AgileSprintModelId":2,"Name":"Filter Patch Notes","Description":"You should be showing people what they really want to see in the patch notes.","Notes":"Added","Status":"Done","Priority":"Blocker","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-02-20T00:00:00"},{"Id":3,"AgileSprintModelId":5,"Name":"Consider Pyre","Description":"Add Pyre Income. Make it so you can take Pyre Camps and Pyre Miners","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-04-18T00:00:00"},{"Id":4,"AgileSprintModelId":5,"Name":"Optimizations","Description":"Build Calculator should be usable.","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-04-13T00:00:00"},{"Id":5,"AgileSprintModelId":5,"Name":"Change Attack Timing Interval","Description":"Be able to set attack timing.","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-04-15T00:00:00"},{"Id":6,"AgileSprintModelId":5,"Name":"Add Pyre Spells","Description":"Make Pyre Spells castable and consume Pyre on build order","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-04-18T00:00:00"},{"Id":7,"AgileSprintModelId":null,"Name":"Default builds (Rush Thrones)","Description":"Add a dropdown list of default builds.","Notes":"Add notes...","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":8,"AgileSprintModelId":null,"Name":"Load older builds","Description":"Be able to load older builds. How are you going to handle auto correct to current patch?","Notes":"Add notes...","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":9,"AgileSprintModelId":null,"Name":"How to use Build Calculator step by step","Description":"Need docs","Notes":"Add notes...","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":10,"AgileSprintModelId":null,"Name":"Compare Health and Damage","Description":"Refer to community example spreadsheet.","Notes":"Add notes...","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":11,"AgileSprintModelId":null,"Name":"Compare Unit\u0027s Damage with it\u0027s own costs","Description":"Refer to community example spreadsheet.","Notes":"Add notes...","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":12,"AgileSprintModelId":4,"Name":"View one unit stats from a link. Make YAML copy and paste","Description":"Design so people can easily copy and paste data into discord","Notes":"Ended up not using exact Yaml. Button in Database controls Detailed vs Plain display ","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-04-03T00:00:00"},{"Id":13,"AgileSprintModelId":2,"Name":"Look into SQL","Description":"You really should be using SQL.","Notes":"Agile and Change log pages now use SQL","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":14,"AgileSprintModelId":1,"Name":"Mobile Menu","Description":"You need a real mobile menu. Viewers don\u0027t scroll below the fold, so no one is going to know what happens when you click a button on phones.","Notes":"Added smaller menus for tablets and phones.","Status":"Done","Priority":"High","Task":"Feature","OrderPriority":3,"Created":"2022-02-18T00:00:00","Finished":"2022-02-19T00:00:00"},{"Id":15,"AgileSprintModelId":2,"Name":"Acropolis Consume Mote","Description":"The Mote is suppose to be consumed when making a Town Hall.","Notes":"Fixed","Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-02-18T00:00:00","Finished":"2022-02-20T00:00:00"},{"Id":16,"AgileSprintModelId":5,"Name":"Multiple Travel Time in Harass Calculator","Description":"Travel time should be based on the amount of bases used. 3 bases is 3 travel times.","Notes":"Add notes...","Status":"Done","Priority":"Low","Task":"Feature","OrderPriority":3,"Created":"2022-02-18T00:00:00","Finished":"2022-04-18T00:00:00"},{"Id":17,"AgileSprintModelId":1,"Name":"Update Database to 0.0.6.8375a","Description":"Xacal tech change, and Hallower damage change. Update Godhead text.","Notes":"Done","Status":"Done","Priority":"None","Task":"Feature","OrderPriority":3,"Created":"2022-02-18T00:00:00","Finished":"2022-02-18T00:00:00"},{"Id":18,"AgileSprintModelId":null,"Name":"Patch History Viewer","Description":"Add an ability to compare patches, to see all nerfs and buffs made between them.","Notes":"Inspired by Zkay\u0027s post on discord, where he details a possible \u0027patch history viewer\u0027 implementation.","Status":"Fun_Idea","Priority":"None","Task":"Feature","OrderPriority":5,"Created":"2022-02-16T00:00:00","Finished":null},{"Id":19,"AgileSprintModelId":1,"Name":"Twitch Page","Description":"Did a ~3 hour test stream, and was personal quite happy with the quality. Make Twitch page, and stream patch, sprint planning and development on Sunday.","Notes":"Page added under General, and named \u0022Streams\u0022.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-16T00:00:00","Finished":"2022-02-16T00:00:00"},{"Id":20,"AgileSprintModelId":1,"Name":"Finish the database","Description":"Add more descriptions for everything. Reduce any data duplication with ids. Add upgrade connections. Add ability connections. Add passives and passives connections.","Notes":"Good enough for now","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-11T00:00:00","Finished":"2022-02-19T00:00:00"},{"Id":21,"AgileSprintModelId":1,"Name":"Change Log View","Description":"Add a log to view last changes.","Notes":"Added changelog page. Shows Today, X Days Ago, or exact date if patch is over a week old.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-14T00:00:00","Finished":"2022-02-14T00:00:00"},{"Id":22,"AgileSprintModelId":1,"Name":"Agile View","Description":"Add the agile view.","Notes":"Finished.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-11T00:00:00","Finished":"2022-02-17T00:00:00"},{"Id":23,"AgileSprintModelId":1,"Name":"GUID for Ids","Description":"Stop using enums for ids, and start using guids. Enums are just too limited, I lose out on component and inheritance design with them. Replace all your enums with guids, rip off the bandaid.","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-11T00:00:00","Finished":"2022-02-18T00:00:00"},{"Id":24,"AgileSprintModelId":1,"Name":"Co-op overview","Description":"Write some sort of blog on co-op gameplay so you have something the feels very content-ish. Maybe make it a video.","Notes":"Finished and released early.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-11T00:00:00","Finished":"2022-02-12T00:00:00"},{"Id":25,"AgileSprintModelId":1,"Name":"Mobile UI","Description":"Make website work on mobile.","Notes":"Should be good. Will test on phone later.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-15T00:00:00","Finished":"2022-02-18T00:00:00"},{"Id":26,"AgileSprintModelId":1,"Name":"Add Making Of View","Description":"View to reference UI designs. Nicely encourages the pratice of making the UI code a lot cleaner.","Notes":"Good enough for now","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-11T00:00:00","Finished":"2022-02-19T00:00:00"},{"Id":27,"AgileSprintModelId":3,"Name":"Close Nav Menu on Navigation","Description":"Close Nav Menu on Navigation","Notes":null,"Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-03-27T00:00:00"},{"Id":28,"AgileSprintModelId":3,"Name":"Add Passive Descriptions and Passive","Description":"Have to guess on a bunch of passives","Notes":null,"Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-03-31T00:00:00"},{"Id":29,"AgileSprintModelId":3,"Name":"Tooltips that show referenced units","Description":"I should see any referenced unit by hovering over it","Notes":"Links can now go to links which can go to links.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-04-01T00:00:00"},{"Id":30,"AgileSprintModelId":null,"Name":"Update Logo for Website","Description":"After color scheme is picked","Notes":null,"Status":"Todo","Priority":"Low","Task":"Feature","OrderPriority":2,"Created":"2022-03-27T00:00:00","Finished":null},{"Id":31,"AgileSprintModelId":3,"Name":"Documentation page","Description":"Add documents on how to maintain website","Notes":"Added start of documents","Status":"Done","Priority":"Low","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-04-03T00:00:00"},{"Id":32,"AgileSprintModelId":6,"Name":"Test Automation","Description":"Selenium Tests","Notes":"Start adding IDs to everything","Status":"Todo","Priority":"Low","Task":"Feature","OrderPriority":2,"Created":"2022-03-27T00:00:00","Finished":null},{"Id":33,"AgileSprintModelId":6,"Name":"Unit Test","Description":"Add some unit tests","Notes":null,"Status":"Todo","Priority":"Low","Task":"Feature","OrderPriority":2,"Created":"2022-03-27T00:00:00","Finished":null},{"Id":34,"AgileSprintModelId":4,"Name":"Fully Transfer everything to SQL","Description":"Need to regenerate the database once everthing is fully transfered","Notes":null,"Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-04-09T00:00:00"},{"Id":35,"AgileSprintModelId":3,"Name":"Adding a loading Component","Description":"For JSON loading","Notes":"Added loading component to Agile and Changelog screens","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-03-27T00:00:00"},{"Id":36,"AgileSprintModelId":3,"Name":"Optimize Loading of Data","Description":"Currently loading non Agile stuff on Agile page","Notes":"Moved SQL database injection to app root","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-03-27T00:00:00"},{"Id":37,"AgileSprintModelId":3,"Name":"Convert Notes to Markdown","Description":"Using Markdown and generating the Note pages seems like a better solution to SQL or hardcoding data","Notes":null,"Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-04-01T00:00:00"},{"Id":38,"AgileSprintModelId":3,"Name":"Improve Entity Filter Options","Description":"The options I give you is strange, given it filers on Faction type","Notes":null,"Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-04-01T00:00:00","Finished":"2022-04-03T00:00:00"},{"Id":39,"AgileSprintModelId":4,"Name":"Refresh Database Bug","Description":"Database dialog UI isn\u0027t refreshing enough","Notes":null,"Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-04-03T00:00:00","Finished":"2022-04-03T00:00:00"},{"Id":40,"AgileSprintModelId":4,"Name":"Branding Stuff","Description":"Add a schedule, improving branding, etc, ","Notes":"Only improved Twitch overlays","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-03T00:00:00","Finished":"2022-04-10T00:00:00"},{"Id":41,"AgileSprintModelId":4,"Name":"Improve Documents/Notes UI","Description":"Should have a left navigation menu. And prev/next buttons","Notes":"Updated UI. Will added prev/next and breadcrumbs later","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-05T00:00:00","Finished":"2022-04-10T00:00:00"},{"Id":42,"AgileSprintModelId":5,"Name":"Add GitHub links instead of showing code","Description":"For all code examples","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-14T00:00:00"},{"Id":43,"AgileSprintModelId":5,"Name":"Research More used RTS calculations","Description":"What other calculators like the Harass Page can be added","Notes":"Do amount of hits to kill, between two units. Maybe time to regen spell uses","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-14T00:00:00"},{"Id":44,"AgileSprintModelId":5,"Name":"Add Error Toasts to Calculator","Description":"Not enough \u0022Ether\u0022","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-12T00:00:00"},{"Id":45,"AgileSprintModelId":5,"Name":"Handle Divide by Zero in Harass Calculator","Description":"addDescription","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-18T00:00:00"},{"Id":46,"AgileSprintModelId":null,"Name":"Harass Calculator first client experience","Description":"Navigate player though the harass calculator steps","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-10T00:00:00","Finished":null},{"Id":47,"AgileSprintModelId":5,"Name":"Training Queue","Description":"Add training queue times to the build calculator","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-24T00:00:00"},{"Id":48,"AgileSprintModelId":5,"Name":"Refresh Button for Build Calculator","Description":"Refresh to regenerate timeline and charts","Notes":"Adding a loading screen for charts. Remove redundant renders","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-13T00:00:00"},{"Id":49,"AgileSprintModelId":null,"Name":"Gameplay Warning State Toasts","Description":"\u0022You should upgrade your economy.\u0022 \u0022Your using too much ether, spend alloy\u0022","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-10T00:00:00","Finished":null},{"Id":50,"AgileSprintModelId":5,"Name":"Make desktop navigation buttons","Description":"It popping up all the time is a tad tedious","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-12T00:00:00"},{"Id":51,"AgileSprintModelId":5,"Name":"Working Timers","Description":"Toast dismiss timers not making sense. Look into proper Timers","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-13T00:00:00"},{"Id":52,"AgileSprintModelId":5,"Name":"Clean up Build Calculator code","Description":"Code needs to be easily readable so it can be updated, maintained, and optimized","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-12T00:00:00","Finished":null},{"Id":53,"AgileSprintModelId":0,"Name":"Armor Types","Description":"Explain Light, Medium and Heavy armor types, and damage works","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Document","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":54,"AgileSprintModelId":0,"Name":"Economy Overview","Description":"How long it takes bases to mine out. How good natruals area","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Document","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":55,"AgileSprintModelId":0,"Name":"Timing and Scouting","Description":"Attacking and reacting to what the enemy is doing","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Document","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":56,"AgileSprintModelId":0,"Name":"Families, Factions, and Immortal Vanguards","Description":"How factions could be viewed.","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Document","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":57,"AgileSprintModelId":0,"Name":"Immortals Spells and Pyre","Description":"Using your Immortal","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Document","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":58,"AgileSprintModelId":6,"Name":"Organize Sprint Order","Description":"Sprints should be ordered as, current sprint, previous sprint, backlog, easy tasks, future sprints, old sprints","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":59,"AgileSprintModelId":null,"Name":"Better Sorting Algorithms ","Description":"Be smarted with searching through and sorting lists","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":60,"AgileSprintModelId":6,"Name":"Settings Section","Description":"Add a settings area, for permission and cookie related content","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-14T00:00:00","Finished":"2022-04-24T00:00:00"},{"Id":61,"AgileSprintModelId":6,"Name":"Analytics","Description":"Track client going to each page.","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-14T00:00:00","Finished":null},{"Id":62,"AgileSprintModelId":6,"Name":"Cookies","Description":"Cookies to remember a the client permission options ","Notes":"Using local storage instead of cookies.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-14T00:00:00","Finished":"2022-04-24T00:00:00"},{"Id":63,"AgileSprintModelId":6,"Name":"Permission Controls Page","Description":"Allow clients to enable cookies, analytics, and perhaps make things more granular. ","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-14T00:00:00","Finished":"2022-04-24T00:00:00"},{"Id":64,"AgileSprintModelId":6,"Name":"Defaults Page","Description":"Let clients set a cookie for Plain/Detailed view. Perhaps default Immortal. Etc.","Notes":"Calling it Storage Page","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-14T00:00:00","Finished":"2022-04-24T00:00:00"},{"Id":65,"AgileSprintModelId":6,"Name":"Analytics Page","Description":"Let\u0027s have a page that shows the analytics collected during a client\u0027s session","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-14T00:00:00","Finished":null},{"Id":66,"AgileSprintModelId":5,"Name":"Economy Comparison","Description":"Compare different economies. Make this a page under resources","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-15T00:00:00","Finished":"2022-04-17T00:00:00"},{"Id":67,"AgileSprintModelId":5,"Name":"[Ctrl \u002B K] Search feature","Description":"WIP. Needs polish","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-16T00:00:00","Finished":"2022-04-16T00:00:00"},{"Id":68,"AgileSprintModelId":6,"Name":"Lighthouse Score","Description":"Lighthouse score is awful. Try to get to the green","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-16T00:00:00","Finished":null},{"Id":69,"AgileSprintModelId":6,"Name":"SEO","Description":"People might be trying to google this website instead of bookmarking it. Make sure its googleable","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-17T00:00:00","Finished":null},{"Id":70,"AgileSprintModelId":6,"Name":"AttacksPerSecond Format Setting","Description":"Make SunSpear\u0027s DPS formatting the default, and allow people to turn it off in settings, for people that don\u0027t like the SBA/APS swapping","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-17T00:00:00","Finished":null},{"Id":71,"AgileSprintModelId":5,"Name":"Fix Cancel Button Giving Money","Description":"Things can be built faster if you cancel","Notes":"addNotes","Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-04-17T00:00:00","Finished":"2022-04-18T00:00:00"},{"Id":72,"AgileSprintModelId":5,"Name":"Calculations Change Answers Over Time","Description":"Obviously a bug in the calculation logic","Notes":"addNotes","Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-04-17T00:00:00","Finished":"2022-04-18T00:00:00"}]
\ No newline at end of file
+[{"Id":1,"AgileSprintModelId":null,"Name":"Support Safari","Description":"Consider other web browsers.","Notes":"Added","Status":"Todo","Priority":"Low","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":"2022-02-20T00:00:00"},{"Id":2,"AgileSprintModelId":2,"Name":"Filter Patch Notes","Description":"You should be showing people what they really want to see in the patch notes.","Notes":"Added","Status":"Done","Priority":"Blocker","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-02-20T00:00:00"},{"Id":3,"AgileSprintModelId":5,"Name":"Consider Pyre","Description":"Add Pyre Income. Make it so you can take Pyre Camps and Pyre Miners","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-04-18T00:00:00"},{"Id":4,"AgileSprintModelId":5,"Name":"Optimizations","Description":"Build Calculator should be usable.","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-04-13T00:00:00"},{"Id":5,"AgileSprintModelId":5,"Name":"Change Attack Timing Interval","Description":"Be able to set attack timing.","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-04-15T00:00:00"},{"Id":6,"AgileSprintModelId":5,"Name":"Add Pyre Spells","Description":"Make Pyre Spells castable and consume Pyre on build order","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-04-18T00:00:00"},{"Id":7,"AgileSprintModelId":null,"Name":"Default builds (Rush Thrones)","Description":"Add a dropdown list of default builds.","Notes":"Add notes...","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":8,"AgileSprintModelId":null,"Name":"Load older builds","Description":"Be able to load older builds. How are you going to handle auto correct to current patch?","Notes":"Add notes...","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":9,"AgileSprintModelId":null,"Name":"How to use Build Calculator step by step","Description":"Need docs","Notes":"Add notes...","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":10,"AgileSprintModelId":null,"Name":"Compare Health and Damage","Description":"Refer to community example spreadsheet.","Notes":"Add notes...","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":11,"AgileSprintModelId":null,"Name":"Compare Unit\u0027s Damage with it\u0027s own costs","Description":"Refer to community example spreadsheet.","Notes":"Add notes...","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":12,"AgileSprintModelId":4,"Name":"View one unit stats from a link. Make YAML copy and paste","Description":"Design so people can easily copy and paste data into discord","Notes":"Ended up not using exact Yaml. Button in Database controls Detailed vs Plain display ","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":"2022-04-03T00:00:00"},{"Id":13,"AgileSprintModelId":2,"Name":"Look into SQL","Description":"You really should be using SQL.","Notes":"Agile and Change log pages now use SQL","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-20T00:00:00","Finished":null},{"Id":14,"AgileSprintModelId":1,"Name":"Mobile Menu","Description":"You need a real mobile menu. Viewers don\u0027t scroll below the fold, so no one is going to know what happens when you click a button on phones.","Notes":"Added smaller menus for tablets and phones.","Status":"Done","Priority":"High","Task":"Feature","OrderPriority":3,"Created":"2022-02-18T00:00:00","Finished":"2022-02-19T00:00:00"},{"Id":15,"AgileSprintModelId":2,"Name":"Acropolis Consume Mote","Description":"The Mote is suppose to be consumed when making a Town Hall.","Notes":"Fixed","Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-02-18T00:00:00","Finished":"2022-02-20T00:00:00"},{"Id":16,"AgileSprintModelId":5,"Name":"Multiple Travel Time in Harass Calculator","Description":"Travel time should be based on the amount of bases used. 3 bases is 3 travel times.","Notes":"Add notes...","Status":"Done","Priority":"Low","Task":"Feature","OrderPriority":3,"Created":"2022-02-18T00:00:00","Finished":"2022-04-18T00:00:00"},{"Id":17,"AgileSprintModelId":1,"Name":"Update Database to 0.0.6.8375a","Description":"Xacal tech change, and Hallower damage change. Update Godhead text.","Notes":"Done","Status":"Done","Priority":"None","Task":"Feature","OrderPriority":3,"Created":"2022-02-18T00:00:00","Finished":"2022-02-18T00:00:00"},{"Id":18,"AgileSprintModelId":null,"Name":"Patch History Viewer","Description":"Add an ability to compare patches, to see all nerfs and buffs made between them.","Notes":"Inspired by Zkay\u0027s post on discord, where he details a possible \u0027patch history viewer\u0027 implementation.","Status":"Fun_Idea","Priority":"None","Task":"Feature","OrderPriority":5,"Created":"2022-02-16T00:00:00","Finished":null},{"Id":19,"AgileSprintModelId":1,"Name":"Twitch Page","Description":"Did a ~3 hour test stream, and was personal quite happy with the quality. Make Twitch page, and stream patch, sprint planning and development on Sunday.","Notes":"Page added under General, and named \u0022Streams\u0022.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-16T00:00:00","Finished":"2022-02-16T00:00:00"},{"Id":20,"AgileSprintModelId":1,"Name":"Finish the database","Description":"Add more descriptions for everything. Reduce any data duplication with ids. Add upgrade connections. Add ability connections. Add passives and passives connections.","Notes":"Good enough for now","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-11T00:00:00","Finished":"2022-02-19T00:00:00"},{"Id":21,"AgileSprintModelId":1,"Name":"Change Log View","Description":"Add a log to view last changes.","Notes":"Added changelog page. Shows Today, X Days Ago, or exact date if patch is over a week old.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-14T00:00:00","Finished":"2022-02-14T00:00:00"},{"Id":22,"AgileSprintModelId":1,"Name":"Agile View","Description":"Add the agile view.","Notes":"Finished.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-11T00:00:00","Finished":"2022-02-17T00:00:00"},{"Id":23,"AgileSprintModelId":1,"Name":"GUID for Ids","Description":"Stop using enums for ids, and start using guids. Enums are just too limited, I lose out on component and inheritance design with them. Replace all your enums with guids, rip off the bandaid.","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-11T00:00:00","Finished":"2022-02-18T00:00:00"},{"Id":24,"AgileSprintModelId":1,"Name":"Co-op overview","Description":"Write some sort of blog on co-op gameplay so you have something the feels very content-ish. Maybe make it a video.","Notes":"Finished and released early.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-11T00:00:00","Finished":"2022-02-12T00:00:00"},{"Id":25,"AgileSprintModelId":1,"Name":"Mobile UI","Description":"Make website work on mobile.","Notes":"Should be good. Will test on phone later.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-15T00:00:00","Finished":"2022-02-18T00:00:00"},{"Id":26,"AgileSprintModelId":1,"Name":"Add Making Of View","Description":"View to reference UI designs. Nicely encourages the pratice of making the UI code a lot cleaner.","Notes":"Good enough for now","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-02-11T00:00:00","Finished":"2022-02-19T00:00:00"},{"Id":27,"AgileSprintModelId":3,"Name":"Close Nav Menu on Navigation","Description":"Close Nav Menu on Navigation","Notes":null,"Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-03-27T00:00:00"},{"Id":28,"AgileSprintModelId":3,"Name":"Add Passive Descriptions and Passive","Description":"Have to guess on a bunch of passives","Notes":null,"Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-03-31T00:00:00"},{"Id":29,"AgileSprintModelId":3,"Name":"Tooltips that show referenced units","Description":"I should see any referenced unit by hovering over it","Notes":"Links can now go to links which can go to links.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-04-01T00:00:00"},{"Id":30,"AgileSprintModelId":null,"Name":"Update Logo for Website","Description":"After color scheme is picked","Notes":null,"Status":"Todo","Priority":"Low","Task":"Feature","OrderPriority":2,"Created":"2022-03-27T00:00:00","Finished":null},{"Id":31,"AgileSprintModelId":3,"Name":"Documentation page","Description":"Add documents on how to maintain website","Notes":"Added start of documents","Status":"Done","Priority":"Low","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-04-03T00:00:00"},{"Id":32,"AgileSprintModelId":6,"Name":"Test Automation","Description":"Selenium Tests","Notes":"Start adding IDs to everything","Status":"Todo","Priority":"Low","Task":"Feature","OrderPriority":2,"Created":"2022-03-27T00:00:00","Finished":null},{"Id":33,"AgileSprintModelId":6,"Name":"Unit Test","Description":"Add some unit tests","Notes":null,"Status":"Todo","Priority":"Low","Task":"Feature","OrderPriority":2,"Created":"2022-03-27T00:00:00","Finished":null},{"Id":34,"AgileSprintModelId":4,"Name":"Fully Transfer everything to SQL","Description":"Need to regenerate the database once everthing is fully transfered","Notes":null,"Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-04-09T00:00:00"},{"Id":35,"AgileSprintModelId":3,"Name":"Adding a loading Component","Description":"For JSON loading","Notes":"Added loading component to Agile and Changelog screens","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-03-27T00:00:00"},{"Id":36,"AgileSprintModelId":3,"Name":"Optimize Loading of Data","Description":"Currently loading non Agile stuff on Agile page","Notes":"Moved SQL database injection to app root","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-03-27T00:00:00"},{"Id":37,"AgileSprintModelId":3,"Name":"Convert Notes to Markdown","Description":"Using Markdown and generating the Note pages seems like a better solution to SQL or hardcoding data","Notes":null,"Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-03-27T00:00:00","Finished":"2022-04-01T00:00:00"},{"Id":38,"AgileSprintModelId":3,"Name":"Improve Entity Filter Options","Description":"The options I give you is strange, given it filers on Faction type","Notes":null,"Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-04-01T00:00:00","Finished":"2022-04-03T00:00:00"},{"Id":39,"AgileSprintModelId":4,"Name":"Refresh Database Bug","Description":"Database dialog UI isn\u0027t refreshing enough","Notes":null,"Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-04-03T00:00:00","Finished":"2022-04-03T00:00:00"},{"Id":40,"AgileSprintModelId":4,"Name":"Branding Stuff","Description":"Add a schedule, improving branding, etc, ","Notes":"Only improved Twitch overlays","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-03T00:00:00","Finished":"2022-04-10T00:00:00"},{"Id":41,"AgileSprintModelId":4,"Name":"Improve Documents/Notes UI","Description":"Should have a left navigation menu. And prev/next buttons","Notes":"Updated UI. Will added prev/next and breadcrumbs later","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-05T00:00:00","Finished":"2022-04-10T00:00:00"},{"Id":42,"AgileSprintModelId":5,"Name":"Add GitHub links instead of showing code","Description":"For all code examples","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-14T00:00:00"},{"Id":43,"AgileSprintModelId":5,"Name":"Research More used RTS calculations","Description":"What other calculators like the Harass Page can be added","Notes":"Do amount of hits to kill, between two units. Maybe time to regen spell uses","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-14T00:00:00"},{"Id":44,"AgileSprintModelId":5,"Name":"Add Error Toasts to Calculator","Description":"Not enough \u0022Ether\u0022","Notes":"Add notes...","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-12T00:00:00"},{"Id":45,"AgileSprintModelId":5,"Name":"Handle Divide by Zero in Harass Calculator","Description":"addDescription","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-18T00:00:00"},{"Id":46,"AgileSprintModelId":null,"Name":"Harass Calculator first client experience","Description":"Navigate player though the harass calculator steps","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-10T00:00:00","Finished":null},{"Id":47,"AgileSprintModelId":5,"Name":"Training Queue","Description":"Add training queue times to the build calculator","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-24T00:00:00"},{"Id":48,"AgileSprintModelId":5,"Name":"Refresh Button for Build Calculator","Description":"Refresh to regenerate timeline and charts","Notes":"Adding a loading screen for charts. Remove redundant renders","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-13T00:00:00"},{"Id":49,"AgileSprintModelId":null,"Name":"Gameplay Warning State Toasts","Description":"\u0022You should upgrade your economy.\u0022 \u0022Your using too much ether, spend alloy\u0022","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-10T00:00:00","Finished":null},{"Id":50,"AgileSprintModelId":5,"Name":"Make desktop navigation buttons","Description":"It popping up all the time is a tad tedious","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-12T00:00:00"},{"Id":51,"AgileSprintModelId":5,"Name":"Working Timers","Description":"Toast dismiss timers not making sense. Look into proper Timers","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-10T00:00:00","Finished":"2022-04-13T00:00:00"},{"Id":52,"AgileSprintModelId":5,"Name":"Clean up Build Calculator code","Description":"Code needs to be easily readable so it can be updated, maintained, and optimized","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-12T00:00:00","Finished":null},{"Id":53,"AgileSprintModelId":0,"Name":"Armor Types","Description":"Explain Light, Medium and Heavy armor types, and damage works","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Document","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":54,"AgileSprintModelId":0,"Name":"Economy Overview","Description":"How long it takes bases to mine out. How good natruals area","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Document","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":55,"AgileSprintModelId":0,"Name":"Timing and Scouting","Description":"Attacking and reacting to what the enemy is doing","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Document","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":56,"AgileSprintModelId":0,"Name":"Families, Factions, and Immortal Vanguards","Description":"How factions could be viewed.","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Document","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":57,"AgileSprintModelId":0,"Name":"Immortals Spells and Pyre","Description":"Using your Immortal","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Document","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":58,"AgileSprintModelId":6,"Name":"Organize Sprint Order","Description":"Sprints should be ordered as, current sprint, previous sprint, backlog, easy tasks, future sprints, old sprints","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":59,"AgileSprintModelId":null,"Name":"Better Sorting Algorithms ","Description":"Be smarted with searching through and sorting lists","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-13T00:00:00","Finished":null},{"Id":60,"AgileSprintModelId":6,"Name":"Settings Section","Description":"Add a settings area, for permission and cookie related content","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-14T00:00:00","Finished":"2022-04-24T00:00:00"},{"Id":61,"AgileSprintModelId":6,"Name":"Analytics","Description":"Track client going to each page.","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-14T00:00:00","Finished":"2022-04-25T00:00:00"},{"Id":62,"AgileSprintModelId":6,"Name":"Cookies","Description":"Cookies to remember a the client permission options ","Notes":"Using local storage instead of cookies.","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-14T00:00:00","Finished":"2022-04-24T00:00:00"},{"Id":63,"AgileSprintModelId":6,"Name":"Permission Controls Page","Description":"Allow clients to enable cookies, analytics, and perhaps make things more granular. ","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-14T00:00:00","Finished":"2022-04-24T00:00:00"},{"Id":64,"AgileSprintModelId":6,"Name":"Defaults Page","Description":"Let clients set a cookie for Plain/Detailed view. Perhaps default Immortal. Etc.","Notes":"Calling it Storage Page","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-14T00:00:00","Finished":"2022-04-24T00:00:00"},{"Id":65,"AgileSprintModelId":null,"Name":"Analytics Page","Description":"Let\u0027s have a page that shows the analytics collected during a client\u0027s session","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-14T00:00:00","Finished":null},{"Id":66,"AgileSprintModelId":5,"Name":"Economy Comparison","Description":"Compare different economies. Make this a page under resources","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-15T00:00:00","Finished":"2022-04-17T00:00:00"},{"Id":67,"AgileSprintModelId":5,"Name":"[Ctrl \u002B K] Search feature","Description":"WIP. Needs polish","Notes":"addNotes","Status":"Done","Priority":"Medium","Task":"Feature","OrderPriority":3,"Created":"2022-04-16T00:00:00","Finished":"2022-04-16T00:00:00"},{"Id":68,"AgileSprintModelId":6,"Name":"Lighthouse Score","Description":"Lighthouse score is awful. Try to get to the green","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-16T00:00:00","Finished":null},{"Id":69,"AgileSprintModelId":6,"Name":"SEO","Description":"People might be trying to google this website instead of bookmarking it. Make sure its googleable","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-17T00:00:00","Finished":null},{"Id":70,"AgileSprintModelId":6,"Name":"AttacksPerSecond Format Setting","Description":"Make SunSpear\u0027s DPS formatting the default, and allow people to turn it off in settings, for people that don\u0027t like the SBA/APS swapping","Notes":"addNotes","Status":"Todo","Priority":"Medium","Task":"Feature","OrderPriority":2,"Created":"2022-04-17T00:00:00","Finished":null},{"Id":71,"AgileSprintModelId":5,"Name":"Fix Cancel Button Giving Money","Description":"Things can be built faster if you cancel","Notes":"addNotes","Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-04-17T00:00:00","Finished":"2022-04-18T00:00:00"},{"Id":72,"AgileSprintModelId":5,"Name":"Calculations Change Answers Over Time","Description":"Obviously a bug in the calculation logic","Notes":"addNotes","Status":"Done","Priority":"High","Task":"Bug","OrderPriority":3,"Created":"2022-04-17T00:00:00","Finished":"2022-04-18T00:00:00"}]
\ No newline at end of file
diff --git a/IGP/wwwroot/generated/WebPageModels.json b/IGP/wwwroot/generated/WebPageModels.json
index 752ac0d..dac45f8 100644
--- a/IGP/wwwroot/generated/WebPageModels.json
+++ b/IGP/wwwroot/generated/WebPageModels.json
@@ -1 +1 @@
-[{"Id":1,"WebSectionModelId":2,"Name":"Database","Description":"Database of game information","Href":"database","IsPrivate":"False"},{"Id":2,"WebSectionModelId":1,"Name":"Build Calculator","Description":"Build order calculator for determining army timings","Href":"build-calculator","IsPrivate":"False"},{"Id":3,"WebSectionModelId":1,"Name":"Harass Calculator","Description":"Alloy harassment calculator","Href":"harass-calculator","IsPrivate":"False"},{"Id":4,"WebSectionModelId":1,"Name":"Memory Tester","Description":"Testing memory","Href":"memory-tester","IsPrivate":"False"},{"Id":5,"WebSectionModelId":1,"Name":"Comparion Charts","Description":"Ecnomy charts to compare build orders","Href":"comparison-charts","IsPrivate":"True"},{"Id":6,"WebSectionModelId":2,"Name":"Notes","Description":"General player notes","Href":"notes","IsPrivate":"False"},{"Id":7,"WebSectionModelId":2,"Name":"Key Mapping","Description":"General key mapping info","Href":"keymapping","IsPrivate":"True"},{"Id":8,"WebSectionModelId":4,"Name":"Road Map","Description":"Plans for this website","Href":"roadmap","IsPrivate":"False"},{"Id":9,"WebSectionModelId":4,"Name":"Change Log","Description":"Past updates to the website","Href":"changelog","IsPrivate":"False"},{"Id":10,"WebSectionModelId":4,"Name":"Agile","Description":"Showing agile view of this website","Href":"agile","IsPrivate":"False"},{"Id":11,"WebSectionModelId":4,"Name":"Making Of","Description":"Explaining development details of this website","Href":"makingof","IsPrivate":"False"},{"Id":12,"WebSectionModelId":2,"Name":"Documentation","Description":"Explaining how to use this website","Href":"documentation","IsPrivate":"True"},{"Id":13,"WebSectionModelId":3,"Name":"About","Description":"Answering general questions on the website","Href":"about","IsPrivate":"False"},{"Id":14,"WebSectionModelId":3,"Name":"Contact","Description":"My contact info","Href":"contact","IsPrivate":"False"},{"Id":15,"WebSectionModelId":3,"Name":"Streams","Description":"Stream info","Href":"streams","IsPrivate":"False"},{"Id":16,"WebSectionModelId":4,"Name":"Documentation","Description":"Development information","Href":"docs","IsPrivate":"False"},{"Id":17,"WebSectionModelId":5,"Name":"Permissions","Description":"Permission Settings","Href":"permissions","IsPrivate":"False"},{"Id":18,"WebSectionModelId":5,"Name":"Data Collection","Description":"Data Collection Settings","Href":"data-collection","IsPrivate":"False"},{"Id":19,"WebSectionModelId":5,"Name":"Storage","Description":"Storage Settings","Href":"storage","IsPrivate":"False"},{"Id":20,"WebSectionModelId":1,"Name":"Economy Comparison","Description":"Compare economies","Href":"economy-comparison","IsPrivate":"False"}]
\ No newline at end of file
+[{"Id":1,"WebSectionModelId":2,"Name":"Database","Description":"Database of game information","Href":"database","IsPrivate":"False"},{"Id":2,"WebSectionModelId":1,"Name":"Build Calculator","Description":"Build order calculator for determining army timings","Href":"build-calculator","IsPrivate":"False"},{"Id":3,"WebSectionModelId":1,"Name":"Harass Calculator","Description":"Alloy harassment calculator","Href":"harass-calculator","IsPrivate":"False"},{"Id":4,"WebSectionModelId":1,"Name":"Memory Tester","Description":"Testing memory","Href":"memory-tester","IsPrivate":"False"},{"Id":5,"WebSectionModelId":1,"Name":"Comparion Charts","Description":"Ecnomy charts to compare build orders","Href":"comparison-charts","IsPrivate":"True"},{"Id":6,"WebSectionModelId":2,"Name":"Notes","Description":"General player notes","Href":"notes","IsPrivate":"False"},{"Id":7,"WebSectionModelId":2,"Name":"Key Mapping","Description":"General key mapping info","Href":"keymapping","IsPrivate":"True"},{"Id":8,"WebSectionModelId":4,"Name":"Road Map","Description":"Plans for this website","Href":"roadmap","IsPrivate":"False"},{"Id":9,"WebSectionModelId":4,"Name":"Change Log","Description":"Past updates to the website","Href":"changelog","IsPrivate":"False"},{"Id":10,"WebSectionModelId":4,"Name":"Agile","Description":"Showing agile view of this website","Href":"agile","IsPrivate":"False"},{"Id":11,"WebSectionModelId":4,"Name":"Making Of","Description":"Explaining development details of this website","Href":"makingof","IsPrivate":"False"},{"Id":12,"WebSectionModelId":2,"Name":"Documentation","Description":"Explaining how to use this website","Href":"documentation","IsPrivate":"True"},{"Id":13,"WebSectionModelId":3,"Name":"About","Description":"Answering general questions on the website","Href":"about","IsPrivate":"False"},{"Id":14,"WebSectionModelId":3,"Name":"Contact","Description":"My contact info","Href":"contact","IsPrivate":"False"},{"Id":15,"WebSectionModelId":3,"Name":"Streams","Description":"Stream info","Href":"streams","IsPrivate":"False"},{"Id":16,"WebSectionModelId":4,"Name":"Documentation","Description":"Development information","Href":"docs","IsPrivate":"False"},{"Id":17,"WebSectionModelId":5,"Name":"Permissions","Description":"Permission Settings","Href":"permissions","IsPrivate":"False"},{"Id":18,"WebSectionModelId":5,"Name":"Data Collection","Description":"Data Collection Settings","Href":"data-collection","IsPrivate":"True"},{"Id":19,"WebSectionModelId":5,"Name":"Storage","Description":"Storage Settings","Href":"storage","IsPrivate":"False"},{"Id":20,"WebSectionModelId":1,"Name":"Economy Comparison","Description":"Compare economies","Href":"economy-comparison","IsPrivate":"False"}]
\ No newline at end of file
diff --git a/IGP/wwwroot/index.html b/IGP/wwwroot/index.html
index fbeb2d0..1537ee3 100644
--- a/IGP/wwwroot/index.html
+++ b/IGP/wwwroot/index.html
@@ -31,6 +31,7 @@
integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2"
src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js">
+