Skip to content

Commit 77950d4

Browse files
committed
Add EntityFramework Tracker sample projects
1 parent bd31982 commit 77950d4

File tree

212 files changed

+8789
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

212 files changed

+8789
-1
lines changed

Foundatio.CommandQuery.slnx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@
44
<File Path="Directory.Build.props" />
55
<File Path="README.md" />
66
</Folder>
7+
<Folder Name="/Samples/" />
8+
<Folder Name="/Samples/EntityFramework/">
9+
<Project Path="samples/EntityFramework/Tracker.Client/Tracker.Client.csproj" />
10+
<Project Path="samples/EntityFramework/Tracker.Core/Tracker.Core.csproj" />
11+
<Project Path="samples/EntityFramework/Tracker.Database/Tracker.Database.sqlproj" Id="0210d856-b45c-49d0-a208-1eb435cbb3f1">
12+
<Build />
13+
<Deploy />
14+
</Project>
15+
<Project Path="samples/EntityFramework/Tracker.Host/Tracker.Host.csproj" />
16+
<Project Path="samples/EntityFramework/Tracker.Service/Tracker.Service.csproj" />
17+
<Project Path="samples/EntityFramework/Tracker.Shared/Tracker.Shared.csproj" />
18+
<Project Path="samples/EntityFramework/Tracker.Web/Tracker.Web.csproj" />
19+
</Folder>
720
<Folder Name="/Tests/">
821
<Project Path="tests/Foundatio.CommandQuery.Dispatcher.Tests/Foundatio.CommandQuery.Dispatcher.Tests.csproj" Id="e2b348b0-8337-4d9f-ad43-a9cf5e13abd6" />
922
<Project Path="tests/Foundatio.CommandQuery.Endpoints.Tests/Foundatio.CommandQuery.Endpoints.Tests.csproj" Id="7349ebc3-b53d-4b7a-8f88-6bbfe75e6e7c" />
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<Project>
2+
3+
<PropertyGroup Label="Package">
4+
<IsPackable>false</IsPackable>
5+
<TrimMode>partial</TrimMode>
6+
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
7+
<EnableTrimAnalyzer>false</EnableTrimAnalyzer>
8+
</PropertyGroup>
9+
10+
<PropertyGroup Label="Debug">
11+
<DebugType>embedded</DebugType>
12+
<EmbedUntrackedSources>true</EmbedUntrackedSources>
13+
<IncludeSymbols>false</IncludeSymbols>
14+
</PropertyGroup>
15+
16+
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
17+
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
18+
</PropertyGroup>
19+
20+
<PropertyGroup Label="Options">
21+
<DefaultLanguage>en-US</DefaultLanguage>
22+
<LangVersion>latest</LangVersion>
23+
<ImplicitUsings>enable</ImplicitUsings>
24+
<Nullable>enable</Nullable>
25+
<NoWarn>1591</NoWarn>
26+
</PropertyGroup>
27+
28+
<ItemGroup>
29+
<PackageReference Include="AssemblyMetadata.Generators" Version="2.1.0" PrivateAssets="All" />
30+
<PackageReference Include="Equatable.Generator" Version="2.0.0" PrivateAssets="all" />
31+
<PackageReference Include="Injectio" Version="5.0.0" PrivateAssets="All" />
32+
</ItemGroup>
33+
34+
<ItemGroup>
35+
<Using Include="Equatable.Attributes" />
36+
</ItemGroup>
37+
</Project>
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using Foundatio.CommandQuery.Definitions;
2+
3+
using Microsoft.AspNetCore.Components.Forms;
4+
5+
using Tracker.Client.Extensions;
6+
using Tracker.Extensions;
7+
8+
9+
namespace Tracker.Client.Components.Abstracts;
10+
11+
public abstract class EditPageBase<TReadModel, TUpdateModel> : StorePageBase<TReadModel, TUpdateModel>
12+
where TReadModel : class, IHaveIdentifier<int>, new()
13+
where TUpdateModel : class, new()
14+
{
15+
protected EditContext? EditContext { get; set; }
16+
17+
protected abstract string ModelTypeName { get; }
18+
19+
protected abstract string? ModelInstanceName { get; }
20+
21+
22+
protected string PageTitle()
23+
{
24+
if (ModelInstanceName.HasValue() && Store.IsDirty)
25+
return $"{ModelTypeName} - {ModelInstanceName} *";
26+
27+
if (ModelInstanceName.HasValue())
28+
return $"{ModelTypeName} - {ModelInstanceName}";
29+
30+
return ModelTypeName;
31+
}
32+
33+
protected string EditLabel() => IsCreate ? "Create" : "Edit";
34+
35+
protected string EditTitle() => $"{ModelTypeName} {EditLabel()}";
36+
37+
protected override async Task OnInitializedAsync()
38+
{
39+
await base.OnInitializedAsync();
40+
41+
if (Store.Model == null)
42+
{
43+
Navigation.NavigateTo(Redirect);
44+
return;
45+
}
46+
47+
EditContext = new EditContext(Store.Model!);
48+
EditContext.OnFieldChanged += HandleFormChange;
49+
}
50+
51+
52+
protected virtual async Task HandleSave()
53+
{
54+
try
55+
{
56+
var originalId = Store.Original?.Id ?? default;
57+
58+
await Store.Save();
59+
60+
Notification.ShowSuccess($"{ModelTypeName} '{ModelInstanceName}' saved successfully");
61+
62+
var updatedId = Store.Original?.Id ?? default;
63+
if (updatedId == originalId)
64+
return;
65+
66+
Navigation.NavigateTo(Redirect);
67+
}
68+
catch (Exception ex)
69+
{
70+
Notification.ShowError(ex);
71+
}
72+
finally
73+
{
74+
await InvokeAsync(StateHasChanged);
75+
}
76+
}
77+
78+
protected virtual async Task HandleDelete()
79+
{
80+
try
81+
{
82+
if (IsCreate || Store.Model == null)
83+
return;
84+
85+
if (!await Modal.ConfirmDelete($"Are you sure you want to delete {ModelTypeName} '{ModelInstanceName}'?"))
86+
return;
87+
88+
await Store.Delete();
89+
90+
Notification.ShowSuccess($"{ModelTypeName} '{ModelInstanceName}' deleted successfully");
91+
Navigation.NavigateTo(Redirect);
92+
}
93+
catch (Exception ex)
94+
{
95+
Notification.ShowError(ex);
96+
}
97+
}
98+
99+
100+
protected void HandleFormChange(object? sender, FieldChangedEventArgs args)
101+
{
102+
Store.NotifyStateChanged();
103+
}
104+
105+
public override void Dispose()
106+
{
107+
base.Dispose();
108+
109+
if (EditContext != null)
110+
EditContext.OnFieldChanged -= HandleFormChange;
111+
112+
GC.SuppressFinalize(this);
113+
}
114+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
using Blazored.Modal.Services;
2+
3+
using Foundatio.CommandQuery.Definitions;
4+
5+
using LoreSoft.Blazor.Controls;
6+
7+
using Microsoft.AspNetCore.Components;
8+
using Microsoft.JSInterop;
9+
10+
using Tracker.Client.Extensions;
11+
using Tracker.Client.Services;
12+
13+
using Queries = Foundatio.CommandQuery.Queries;
14+
15+
namespace Tracker.Client.Components.Abstracts;
16+
17+
public abstract class ListPageBase<TReadModel>() : ListPageBase<TReadModel, TReadModel>
18+
where TReadModel : class, IHaveIdentifier<int>
19+
{ }
20+
21+
public abstract class ListPageBase<TListModel, TReadModel> : PrincipalBase
22+
where TListModel : class, IHaveIdentifier<int>
23+
where TReadModel : class, IHaveIdentifier<int>
24+
{
25+
protected ListPageBase()
26+
{
27+
SearchText = new DebounceValue<string>(HandleSearch);
28+
}
29+
30+
[CascadingParameter]
31+
public required IModalService Modal { get; set; }
32+
33+
[Inject]
34+
public required DataService DataService { get; set; }
35+
36+
[Inject]
37+
public required NotificationService Notification { get; set; }
38+
39+
[Inject]
40+
public required NavigationManager Navigation { get; set; }
41+
42+
[Inject]
43+
public required IJSRuntime JavaScript { get; set; }
44+
45+
46+
protected DataGrid<TListModel>? DataGrid { get; set; }
47+
48+
protected DebounceValue<string> SearchText { get; }
49+
50+
protected virtual string? ModelTypeName { get; }
51+
52+
53+
protected virtual async ValueTask<DataResult<TListModel>> LoadData(DataRequest request)
54+
{
55+
try
56+
{
57+
var query = request.ToQuery();
58+
query.Filter = RewriteFilter(query.Filter);
59+
60+
var results = await DataService.Query<TListModel>(query);
61+
62+
await LoadAdditionalData();
63+
64+
if (results == null)
65+
return new DataResult<TListModel>(0, []);
66+
67+
return results.ToResult();
68+
}
69+
catch (Exception ex)
70+
{
71+
Notification.ShowError(ex);
72+
return new DataResult<TListModel>(0, []);
73+
}
74+
finally
75+
{
76+
await InvokeAsync(StateHasChanged);
77+
}
78+
}
79+
80+
protected virtual Queries.QueryFilter? RewriteFilter(Queries.QueryFilter? originalFilter) => originalFilter;
81+
82+
protected virtual Task LoadAdditionalData() => Task.CompletedTask;
83+
84+
85+
protected async Task HandleDelete(TListModel model)
86+
{
87+
try
88+
{
89+
if (!await Modal.ConfirmDelete())
90+
return;
91+
92+
await DataService.Delete<int, TReadModel>(model.Id);
93+
94+
Notification.ShowSuccess($"Item deleted successfully");
95+
96+
if (DataGrid != null)
97+
await DataGrid.RefreshAsync();
98+
}
99+
catch (Exception ex)
100+
{
101+
Notification.ShowError(ex);
102+
}
103+
finally
104+
{
105+
await InvokeAsync(StateHasChanged);
106+
}
107+
}
108+
109+
protected void HandleSearch(string? searchText)
110+
{
111+
if (DataGrid == null)
112+
return;
113+
114+
InvokeAsync(async () => await DataGrid.QuickSearch(searchText));
115+
}
116+
117+
protected async Task HandelRefresh()
118+
{
119+
if (DataGrid == null)
120+
return;
121+
122+
await DataGrid.RefreshAsync();
123+
}
124+
125+
protected void ToggleFilter()
126+
{
127+
if (DataGrid == null)
128+
return;
129+
130+
DataGrid.ShowFilter();
131+
}
132+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System.Security.Claims;
2+
3+
using Microsoft.AspNetCore.Components;
4+
using Microsoft.AspNetCore.Components.Authorization;
5+
6+
namespace Tracker.Client.Components.Abstracts;
7+
8+
public abstract class PrincipalBase : ComponentBase
9+
{
10+
[CascadingParameter]
11+
protected Task<AuthenticationState>? AuthenticationState { get; set; }
12+
13+
protected async Task<ClaimsPrincipal?> GetUser()
14+
{
15+
if (AuthenticationState is null)
16+
return null;
17+
18+
var user = await AuthenticationState;
19+
return user?.User;
20+
}
21+
}

0 commit comments

Comments
 (0)