-
-
Notifications
You must be signed in to change notification settings - Fork 254
Add sync feature to bit Boilerplate client app offline database (#11779) #11780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughThis PR implements offline-first synchronization for Todo items in the Bit Boilerplate template. It introduces a new SyncService leveraging CommunityToolkit.DataSync, replaces the generic OfflineDatabaseDemoPage with a functional OfflineTodoPage, updates the database schema from UserDto to TodoItemDto with sync tables, and reconfigures navigation, URLs, and server-side APIs to support the feature. Changes
Sequence DiagramsequenceDiagram
actor User
participant OfflineTodoPage as Offline Todo Page
participant SyncService
participant DbContext as App Offline DbContext
participant LocalDb as SQLite (Local)
participant HttpClient
participant Server as Todo API Server
User->>OfflineTodoPage: Load page / Trigger sync
OfflineTodoPage->>SyncService: Call Sync()
rect rgb(200, 220, 240)
Note over SyncService,Server: Push Phase
SyncService->>DbContext: Create context
SyncService->>LocalDb: Read pending changes
SyncService->>HttpClient: POST changes to server
HttpClient->>Server: Send modified/added/deleted items
Server->>Server: Process & persist
Server-->>HttpClient: Return result
HttpClient-->>SyncService: Success/error response
end
rect rgb(220, 240, 200)
Note over SyncService,LocalDb: Pull Phase (optional)
SyncService->>HttpClient: GET recent changes
HttpClient->>Server: Request delta
Server-->>HttpClient: Return changes
HttpClient-->>SyncService: Changes received
SyncService->>LocalDb: Merge into local DB
SyncService->>DbContext: SaveChangesAsync()
end
alt Success
SyncService->>OfflineTodoPage: Show success message
OfflineTodoPage->>User: Display ✓ sync confirmation
else Error
SyncService->>OfflineTodoPage: Wrap error in BadRequestException
OfflineTodoPage->>User: Display ✗ error message
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Areas requiring extra attention:
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (14)
src/Templates/Boilerplate/Bit.Boilerplate/.github/copilot-instructions.md (1)
102-102: Clarify the relationship between this documentation change and the sync feature PR objective.This line adds guidance for RTL language handling in Copilot responses. While the directive is clearly worded and the technical content exclusion is well-specified, this documentation change appears orthogonal to the primary PR objective of adding offline-database sync functionality.
Consider clarifying whether this is:
- A necessary supporting change for the sync feature implementation, or
- A separate improvement that should be in its own PR for easier tracking and review.
If this belongs in this PR, consider updating the PR description to reflect the documentation improvement alongside the sync feature work.
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IClientCoreServiceCollectionExtensions.cs (3)
137-139: AvoidTask.RunaroundMigrateAsyncindbContextInitializer
dbContext.Database.MigrateAsync()is already asynchronous; wrapping it inTask.Runadds an extra layer of tasks, unnecessary thread-pool usage, and makes the initializer harder to read without functional benefit.You can simplify to a single await on the migrator:
- } - , dbContextInitializer: async (sp, dbContext) => await Task.Run(async () => await dbContext.Database.MigrateAsync()) - , lifetime: ServiceLifetime.Scoped); + } + , dbContextInitializer: async (sp, dbContext) => await dbContext.Database.MigrateAsync() + , lifetime: ServiceLifetime.Scoped);
137-139: Confirm intended lifetime forAppOfflineDbContextfactoryYou’ve explicitly set the BESQL DbContext factory lifetime to
ServiceLifetime.Scoped. That’s fine for Blazor Server/WebAssembly, but in Blazor Hybrid you currently useAddSessionedelsewhere to effectively share services between the two scopes for a single client app.If you want the offline DbContext factory to follow the same “per client session” semantics as other sessioned services, consider:
- , lifetime: ServiceLifetime.Scoped); + , lifetime: AppPlatform.IsBlazorHybrid ? ServiceLifetime.Singleton : ServiceLifetime.Scoped);Otherwise, please double-check that having separate scoped factories per Hybrid scope is intentional.
140-140: Consider usingAddSessionedforSyncServicein Hybrid scenarios
SyncServiceholds state (CancellationTokenSource) and coordinates sync across the client session. WithAddScoped<SyncService>(), Blazor Hybrid will get two separate instances (one per scope), unlike other “sessioned” services here that useAddSessionedto share a single instance across scopes.If you want consistent per-client behavior (especially for cancellation and snackbar feedback), consider:
- services.AddScoped<SyncService>(); + services.AddSessioned<SyncService>();If
SyncServiceis only ever used from the Blazor WebView scope, keeping it scoped is also fine—just confirm that’s the case.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor.scss (1)
1-53: LGTM!The SCSS follows project conventions with proper imports, responsive breakpoints, and Blazor-compatible
::deepscoping. The layout and responsive adjustments are well-structured.Consider extracting the magic numbers in height calculations (14rem, 17rem, 18rem on lines 44, 47, 51) into named SCSS variables for maintainability, especially if these offsets are reused elsewhere or need coordinated updates with header/footer heights.
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/TodoPage.razor (1)
90-90: Consider adding null safety forUpdatedAtdisplay.The null-forgiving operator (
!) assumesUpdatedAtis never null when rendering. While this may be valid for synced items, consider a safer approach to handle edge cases whereUpdatedAtmight be null (e.g., newly created items before first sync).-<BitText Typography="BitTypography.Body2">@todo.UpdatedAt!.Value.ToLocalTime().ToString("F")</BitText> +<BitText Typography="BitTypography.Body2">@(todo.UpdatedAt?.ToLocalTime().ToString("F") ?? "-")</BitText>src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Todo/TodoItemController.cs (2)
34-41: Consider adding input validation for the stringidparameter.The ID type change from
Guidtostringaligns with CommunityToolkit.Datasync requirements. However, string IDs should be validated for null/empty values before querying.[HttpGet("{id}")] public async Task<TodoItemDto> Get(string id, CancellationToken cancellationToken) { + ArgumentException.ThrowIfNullOrWhiteSpace(id); + var dto = await Get().FirstOrDefaultAsync(t => t.Id == id, cancellationToken) ?? throw new ResourceNotFoundException(Localizer[nameof(AppStrings.ToDoItemCouldNotBeFound)]); return dto; }
72-81: Add input validation for theDeletemethod as well.For consistency with the suggested change in
Get, theDeletemethod should also validate theidparameter.[HttpDelete("{id}")] public async Task Delete(string id, CancellationToken cancellationToken) { + ArgumentException.ThrowIfNullOrWhiteSpace(id); + DbContext.TodoItems.Remove(new() { Id = id }); var affectedRows = await DbContext.SaveChangesAsync(cancellationToken); if (affectedRows < 1) throw new ResourceNotFoundException(Localizer[nameof(AppStrings.ToDoItemCouldNotBeFound)]); }src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Todo/TodoItemDto.cs (1)
17-17: Default value forUpdatedAtis set at object construction time.Setting
DateTimeOffset.UtcNowas a default value means each newTodoItemDtoinstance captures the time when the object was instantiated, not when it's persisted. This is likely fine sinceSaveChangesAsyncinAppOfflineDbContextoverwritesUpdatedAtbefore saving. However, consider whether the default should benullinstead to make it clearer that the actual value is set during persistence.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/AppOfflineDbContext.cs (1)
48-54: Consider documenting theClientWinsConflictResolverstrategy.Using
ClientWinsConflictResolvermeans local offline changes always overwrite server data during sync conflicts. This is a valid strategy for offline-first apps, but it may cause unintended data loss if multiple clients edit the same item. Consider adding a code comment explaining this design decision, or evaluate whetherServerWinsConflictResolveror a custom resolver might be more appropriate depending on the use case.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs (2)
36-48: Potential race condition in CancellationTokenSource management.There's a race condition between lines 38-41: if
Syncis called concurrently from multiple threads, the assignmentcts = new()on line 41 could be interleaved with another thread readingctson line 38. Consider usingInterlocked.Exchangefor thread-safe swapping.private async Task Sync(CancellationToken cancellationToken, bool pullRecentChanges = true) { - using var localCts = cts; - await localCts.TryCancel(); - - cts = new(); + var newCts = new CancellationTokenSource(); + var oldCts = Interlocked.Exchange(ref cts, newCts); + await oldCts.TryCancel(); + oldCts.Dispose(); - using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cts.Token); + using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, newCts.Token); await using var dbContext = await dbContextFactory.CreateDbContextAsync(linkedCts.Token); await Sync(dbContext, pullRecentChanges, linkedCts.Token); }
21-24: Consider accepting a CancellationToken in Push() for consistency.Unlike
PullandSync,Pushpassesdefaultfor the cancellation token, meaning callers cannot cancel push operations. If this is intentional (e.g., pushes should always complete), consider documenting this behavior.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor (1)
86-89: Consider using Value instead of DefaultValue for checkbox.Using
DefaultValuemeans the checkbox won't update iftodo.IsDonechanges from an external source (e.g., pull sync). If bi-directional binding is needed, consider usingValuewith a controlled pattern.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor.cs (1)
189-205: Consider validatingunderEditTodoItemTitlebefore saving.
underEditTodoItemTitleis nullable (string?), and settingtodoItem.Titleto null when the schema requiresTitlecould cause database constraint violations. Consider adding validation similar toAddTodoItemwhich checksstring.IsNullOrWhiteSpace(newTodoTitle).private async Task SaveTodoItem(TodoItemDto todoItem) { - if (isLoading) return; + if (isLoading || string.IsNullOrWhiteSpace(underEditTodoItemTitle)) return; isLoading = true;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting
📒 Files selected for processing (50)
src/Templates/Boilerplate/Bit.Boilerplate/.docs/01- Entity Framework Core.md(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/.docs/08- Blazor Pages, Components, Styling & Navigation.md(0 hunks)src/Templates/Boilerplate/Bit.Boilerplate/.docs/12- Blazor Modes, PreRendering & PWA.md(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/.github/copilot-instructions.md(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/.github/prompts/getting-started.prompt.md(0 hunks)src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Boilerplate.Client.Core.csproj(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.items.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/NavBar.razor(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineDatabaseDemoPage.razor(0 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineDatabaseDemoPage.razor.cs(0 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineDatabaseDemoPage.razor.scss(0 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor.scss(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/TodoPage.razor(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/AppOfflineDbContext.cs(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/AppOfflineDbContextModel.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/AppOfflineDbContextModelBuilder.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/DatasyncDeltaTokenEntityType.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/DatasyncOperationEntityType.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/TodoItemDtoEntityType.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/UserDtoEntityType.cs(0 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251128225322_Initial.Designer.cs(0 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251128225322_Initial.cs(0 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251130225551_Initial.Designer.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251130225551_Initial.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/AppOfflineDbContextModelSnapshot.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IClientCoreServiceCollectionExtensions.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Platforms/Android/MainActivity.cs(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/manifest.json(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/service-worker.published.js(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Boilerplate.Server.Api.csproj(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Todo/TodoItemController.cs(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Todo/TodoItemTableController.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/AppDbContext.cs(5 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Chatbot/SystemPromptConfiguration.cs(4 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Mappers/TodoMapper.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Models/Identity/User.cs(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Models/Todo/TodoItem.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Controllers/Todo/ITodoItemController.cs(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/AppJsonContext.cs(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Todo/TodoItemDto.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/PageUrls.cs(1 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.fa.resx(2 hunks)src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.resx(2 hunks)src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/Urls.cs(1 hunks)
💤 Files with no reviewable changes (8)
- src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineDatabaseDemoPage.razor
- src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/UserDtoEntityType.cs
- src/Templates/Boilerplate/Bit.Boilerplate/.docs/08- Blazor Pages, Components, Styling & Navigation.md
- src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineDatabaseDemoPage.razor.scss
- src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251128225322_Initial.Designer.cs
- src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251128225322_Initial.cs
- src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineDatabaseDemoPage.razor.cs
- src/Templates/Boilerplate/Bit.Boilerplate/.github/prompts/getting-started.prompt.md
🧰 Additional context used
🧬 Code graph analysis (14)
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs (2)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Services/AppFeatures.cs (1)
Todo(47-50)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Todo/TodoItemTableController.cs (1)
TodoItemTableRepository(29-51)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IClientCoreServiceCollectionExtensions.cs (1)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs (1)
SyncService(11-87)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/AppOfflineDbContext.cs (5)
src/Besql/Demo/Bit.Besql.Demo.Client/Data/OfflineDbContext.cs (1)
OfflineDbContext(7-25)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Mappers/TodoMapper.cs (1)
TodoItemDto(14-14)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs (5)
Task(21-24)Task(26-29)Task(31-34)Task(36-48)Task(55-81)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/AppDbContext.cs (1)
Task(113-125)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AbsoluteServerAddressProvider.cs (1)
AbsoluteServerAddressProvider(10-28)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/TodoItemDtoEntityType.cs (3)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/DatasyncDeltaTokenEntityType.cs (4)
EntityFrameworkInternal(13-59)RuntimeEntityType(16-44)CreateAnnotations(46-56)Customize(58-58)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/DatasyncOperationEntityType.cs (4)
EntityFrameworkInternal(14-127)RuntimeEntityType(17-112)CreateAnnotations(114-124)Customize(126-126)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/AppOfflineDbContextModel.cs (1)
Customize(45-45)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/DatasyncOperationEntityType.cs (3)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/DatasyncDeltaTokenEntityType.cs (3)
RuntimeEntityType(16-44)CreateAnnotations(46-56)Customize(58-58)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/TodoItemDtoEntityType.cs (3)
RuntimeEntityType(17-72)CreateAnnotations(74-84)Customize(86-86)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/AppOfflineDbContextModel.cs (1)
Customize(45-45)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Todo/TodoItemDto.cs (2)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Categories/CategoryDto.cs (1)
DtoResourceType(3-19)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Mappers/TodoMapper.cs (1)
TodoItemDto(14-14)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor.cs (3)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs (1)
SyncService(11-87)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/AppOfflineDbContext.cs (1)
AppOfflineDbContext(11-56)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Mappers/TodoMapper.cs (1)
TodoItemDto(14-14)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.items.cs (1)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/PageUrls.cs (1)
PageUrls(4-47)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs (6)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SnackBarService.cs (1)
SnackBarService(3-15)src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/StringLocalizerProvider.cs (1)
IStringLocalizer(6-9)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/AppOfflineDbContext.cs (2)
AppOfflineDbContext(11-56)Task(24-35)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/AppDbContext.cs (1)
Task(113-125)src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Services/SharedExceptionHandler.cs (1)
Exception(34-46)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ClientExceptionHandlerBase.cs (1)
ExceptionDisplayKind(78-87)
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Models/Todo/TodoItem.cs (2)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Services/AppFeatures.cs (1)
Todo(47-50)src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Mappers/TodoMapper.cs (1)
TodoItem(15-15)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251130225551_Initial.Designer.cs (3)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/AppOfflineDbContextModel.cs (1)
DbContext(10-46)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/AppOfflineDbContextModelSnapshot.cs (1)
DbContext(11-109)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251130225551_Initial.cs (1)
Initial(8-80)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Platforms/Android/MainActivity.cs (1)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/PageUrls.cs (1)
PageUrls(4-47)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Controllers/Todo/ITodoItemController.cs (1)
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Todo/TodoItemController.cs (3)
HttpGet(11-19)HttpGet(21-32)HttpGet(34-41)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/AppOfflineDbContextModelBuilder.cs (4)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/AppOfflineDbContextModel.cs (2)
AppOfflineDbContextModel(16-38)Initialize(43-43)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/DatasyncDeltaTokenEntityType.cs (1)
CreateAnnotations(46-56)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/DatasyncOperationEntityType.cs (1)
CreateAnnotations(114-124)src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/TodoItemDtoEntityType.cs (1)
CreateAnnotations(74-84)
🪛 Biome (2.1.2)
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/manifest.json
[error] 45-45: Expected an array, an object, or a literal but instead found '//#if (offlineDb == true)'.
Expected an array, an object, or a literal here.
(parse)
[error] 46-49: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 49-50: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
🪛 LanguageTool
src/Templates/Boilerplate/Bit.Boilerplate/.docs/01- Entity Framework Core.md
[grammar] ~456-~456: Ensure spelling is correct
Context: ...r database. Conventions: - Entity must inhert from BaseEntityTableData Example: [`/...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build Bit.Websites
- GitHub Check: build Bit.Templates
🔇 Additional comments (54)
src/Templates/Boilerplate/Bit.Boilerplate/.docs/12- Blazor Modes, PreRendering & PWA.md (1)
208-208: Documentation URL update looks good.The URL change from
offline-database-demotooffline-todocorrectly reflects the page rename introduced by this PR, maintaining documentation accuracy aligned with the new offline-todo page implementation.src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/AppJsonContext.cs (2)
2-4: Broadened Todo using condition correctly covers offlineDb scenarioExtending the guard to
sample == true || offlineDb == trueensuresTodoItemDtois available whenever either sample or offline DB features are enabled, which matches the PR’s sync/offline intent, and the//#endifpairing is correct.
43-47: JsonSerializable entries now aligned with offlineDb conditionUsing the same
(sample == true || offlineDb == true)guard for theTodoItemDtoand relatedPagedResponse/Listserializations keeps the source-generated context in sync with the using directive above and correctly enables serialization for offline DB templates.src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json (1)
478-502: Verify intended exclusion logic—redundant path entries and conditional overlap detected.Lines 478–502 contain two conditional blocks with overlapping exclusions:
Redundant entries identified:
TodoMapper.csappears in block 1 (line 483) and block 2 (line 498)TodoPage.*appears in block 1 (line 487) and block 2 (line 499)Todo/**controllers appear in block 1 (line 486) and block 2 (line 500)Conditional logic overlap:
- Block 1 applies when:
sample=false AND offlineDb=false- Block 2 applies when:
offlineDb=false(any sample value)- Result: When
sample=true && offlineDb=false, only block 2 applies and excludesTodoMapper.cs,TodoPage.*, andTodoItemController.csVerify intent: Confirm whether
TodoPageandTodoMappershould be excluded in all scenarios whereofflineDb=false, or only when bothsample=falseandofflineDb=false. If the latter, remove the redundant entries from block 2 (lines 498–500).src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Chatbot/SystemPromptConfiguration.cs (3)
124-136: LGTM!The new Offline Todo List section is well-structured and correctly uses the
elseifpattern to ensure mutual exclusivity with the regular Todo section. The content aligns with the PR objective of adding offline sync support.
202-225: LGTM!The nested conditional structure is correctly implemented with matching
//#endifdirectives. The Car Recommendation Rules section will only be included when both conditions are satisfied.
95-136: The quote style in the changed lines (95–136) is actually consistent—all string comparisons use single quotes ('Admin','Sales'). Line 202, which the comment references as using double quotes, falls outside the provided changed lines and cannot be verified from this snippet. If line 202 uses a different quote style, it would be pre-existing code and not part of this change. Within the scope of this PR's modifications, no quote style inconsistency exists.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/service-worker.published.js (1)
107-107: LGTM!The documentation URL update aligns with the new offline Todo feature naming convention introduced in this PR.
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Mappers/TodoMapper.cs (1)
1-1: No substantive changes.This file only has a BOM (byte order mark) character added at the start. The mapper definitions remain unchanged and correctly map between
TodoItemandTodoItemDto.src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.resx (2)
275-286: LGTM!The sync-related resource strings are clear and user-friendly. The format placeholder
{0}inSyncPushSuccessis appropriate for displaying the change count.Consider whether a
SyncPullSuccessmessage is also needed to notify users when changes are successfully pulled from the server, for consistency withSyncPushSuccess. If the sync pull operation is silent by design, this can be ignored.
948-948: LGTM!Expanding the conditional to include
offlineDb == truecorrectly shares the Todo-related strings with the new OfflineTodo feature.src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs (2)
44-46: LGTM!The conditional using directive is properly scoped under the
offlineDbfeature flag.
290-295: LGTM! AddDatasyncServices() is the correct method name.The Datasync service registration is well-placed after the DbContext setup. The
AddDatasyncServices()extension method is provided byCommunityToolkit.Datasync.Serverand correctly registers OData support, protocol handlers, and required middleware dependencies. TheTodoItemTableRepositoryscoped registration aligns with its dependency onAppDbContext.src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/AppDbContext.cs (2)
6-8: LGTM: Conditional compilation extended for offlineDb support.The change to include
offlineDb == truealongsidesample == truealigns with the PR objective to enable Todo functionality for the offline database sync feature.
127-145: LGTM: Method renamed and extended for sync support.The changes look good:
- Renaming
SetConcurrencyStamptoOnSavingChangesbetter reflects the expanded responsibility.- Setting
UpdatedAtonDeletedentries is correct for soft-delete sync scenarios where the server needs to track when records were deleted.- The version handling simplification removes unnecessary provider-specific branching.
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/AppOfflineDbContextModel.cs (1)
1-46: Auto-generated EF Core compiled model.This is an auto-generated file from EF Core's compiled model tooling. The thread initialization pattern with the 10MB stack (lines 26-28) is EF Core's workaround for Issue 31751 (stack overflow during model initialization with complex models). No manual changes should be needed here.
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Boilerplate.Client.Core.csproj (1)
22-25: CommunityToolkit.Datasync.Client package reference is appropriate.The newly added
CommunityToolkit.Datasync.Client(v9.0.5 as of Nov 2025) is a legitimate and maintained package from the CommunityToolkit Datasync project, providing client-side data synchronization capabilities. The conditional pattern matches existing offlineDb-related dependencies on this file.src/Templates/Boilerplate/Bit.Boilerplate/.docs/01- Entity Framework Core.md (1)
451-466: The fourth file path contains a duplicate "Controllers" directory segment.The documentation references
/src/Server/Boilerplate.Server.Api/Controllers/Controllers/Todo/TodoItemTableController.csfor the Repository example, but this path hasControllers/Controllers, which appears to be a copy-paste error. Verify the correct path and update accordingly. Additionally, confirm the other referenced paths exist and are accurate:
/src/Server/Boilerplate.Server.Api/Models/Todo/TodoItem.cs/src/Shared/Dtos/Todo/TodoItemDto.cs/src/Server/Boilerplate.Server.Api/Controllers/Todo/TodoItemTableController.cssrc/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/manifest.json (1)
45-50: Static analysis errors are false positives.The Biome parse errors flagged by static analysis are expected because this file contains preprocessor directives (
//#if,//#elseif,//#endif) that will be processed by the template engine before the JSON is parsed. These directives are not valid JSON syntax but are intentionally used in template files.The URL change from
/offline-database-demoto/offline-todoand the preprocessor condition update align with the PR objectives.src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/Urls.cs (1)
52-52: LGTM!The URL update from
/offline-database-demoto/offline-todois consistent with the PR's objective to introduce a dedicated offline Todo synchronization feature.src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Models/Identity/User.cs (1)
2-4: LGTM!Expanding the preprocessor condition to include
offlineDb == trueappropriately makes theTodoItemsnavigation property available when the offline database feature is enabled, consistent with the PR's offline synchronization objectives.Also applies to: 43-45
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Platforms/Android/MainActivity.cs (2)
31-35: LGTM!The deep link configuration correctly updates to reference
PageUrls.OfflineTodounder theofflineDbcondition, replacing the previousOfflineDatabaseDemoroute. This aligns with the broader navigation refactoring in the PR.
82-83: LGTM!Minor formatting improvement for code clarity.
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/NavBar.razor (2)
9-17: LGTM!The conditional rendering correctly provides separate Todo navigation items for offline mode (
OfflineTodowithToDoLogoOutline) and sample mode (TodowithToDoLogoInverse), allowing the template to support both configurations with distinct visual indicators.
31-33: LGTM!The updated condition correctly excludes the About page when either
sampleorofflineDbmodes are active, consistent with the template's feature configuration.src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Controllers/Todo/ITodoItemController.cs (1)
9-18: Verify that the ID type change from Guid to string is handled consistently.The
GetandDeletemethods now acceptstring idinstead ofGuid id. This is a breaking API change required for CommunityToolkit.Datasync compatibility, which uses string-based identifiers.Ensure that:
- All client-side callers have been updated to use string IDs
- Any existing data migration strategy is in place (if applicable)
- The
TodoItemDto.Idproperty has been updated to string type throughout the codebase- Database queries and mappings handle the string ID correctly
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251130225551_Initial.cs (1)
1-80: Schema aligns with CommunityToolkit.Datasync requirements.The migration correctly implements the three tables needed for offline synchronization:
TodoItemswith requiredId(string),UpdatedAt(as long for SQLite millisecond precision), andVersion(byte[])DatasyncDeltaTokensfor tracking sync stateDatasyncOperationsQueuewith index onItemIdandEntityTypefor efficient queue lookupsThe schema matches Datasync specifications. Note:
UpdatedAtis stored asINTEGER(long) rather than a DateTimeOffset, which is the correct approach for SQLite to maintain millisecond accuracy when combined with EF Core value converters.src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Boilerplate.Server.Api.csproj (1)
50-51: Verify transitive dependency versions for known vulnerabilities.The packages
CommunityToolkit.Datasync.ServerandCommunityToolkit.Datasync.Server.EntityFrameworkCorehave no published security advisories. However, ensure that transitive dependencies (such as System.Text.Json and related .NET libraries) are at patched versions by runningdotnet list package --include-transitiveand cross-referencing against GitHub Security Advisories and CVE databases.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/AppOfflineDbContextModelBuilder.cs (1)
9-30: Auto-generated EF Core compiled model looks correct.The model properly registers all three entity types required for the offline sync feature:
TodoItemDto,DatasyncDeltaToken, andDatasyncOperation. The entity count (3) in the constructor matches the number of entities created inInitialize().src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/TodoItemDtoEntityType.cs (1)
1-88: Auto-generated EF Core entity type mapping is correctly structured.The compiled model properly defines:
- String-based
Idas primary key with appropriate save behaviorDeletedflag for soft-delete pattern required by DatasyncUpdatedAtwithDateTimeOffsetToBinaryConverterfor SQLite compatibilityVersionfor optimistic concurrency controlThe structure aligns with the other Datasync entity types (
DatasyncDeltaTokenEntityType,DatasyncOperationEntityType) in the codebase.src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/PageUrls.cs (1)
27-31: Verify conditional references toPageUrls.Todomatch the preprocessor directives.The conditional structure means
PageUrls.Todois only defined whensample == true(andofflineDbis false/unset). Any code referencingPageUrls.Todomust either be similarly guarded with matching preprocessor directives or only exist in contexts whereofflineDbis not enabled. Ensure all references to this constant are compatible with the conditional compilation logic.src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props (1)
85-88: Package additions are correct and consistent.The CommunityToolkit.Datasync packages (Server, Server.EntityFrameworkCore, and Client) are added with version 9.0.5, which is current and available on NuGet. Conditional gating follows the existing pattern in the file.
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Todo/TodoItemDto.cs (2)
21-24: LGTM!The
Versionproperty for concurrency control and the[NotMapped]attribute onIsInEditModeare appropriate additions for the offline sync feature.
7-7: Verify server-sideTodoItementity also usesstringId.The Id type changed from
Guidtostringfor CommunityToolkit.DataSync compatibility. Ensure the server-sideTodoItementity and theTodoMapper(which mapsTodoItemtoTodoItemDto) are updated consistently to use string-based identifiers.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.items.cs (1)
69-88: LGTM!The conditional compilation correctly separates the offline Todo navigation item from the regular Todo item. The authorization check is properly applied to both branches, and the URLs and localization keys are consistent with the corresponding definitions in
PageUrls.csandAppStrings.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/AppOfflineDbContext.cs (2)
24-35: LGTM -UpdatedAtis correctly updated for soft-deleted entities.The
SaveChangesAsyncoverride correctly updatesUpdatedAtforAdded,Modified, andDeletedstates. IncludingDeletedis appropriate for soft-delete scenarios where tracking deletion time is important for sync operations.
39-46: Verify the HTTP handler chain is configured correctly.The
httpMessageHandlersChainFactory.Invoke()should return a properly configuredDelegatingHandlerchain that includes authentication handlers. Ensure that the factory creates handlers suitable for datasync operations.src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.fa.resx (2)
948-948: LGTM!The conditional compilation comment correctly includes
offlineDb == trueto ensure Todo-related strings are available for both sample and offline database scenarios.
275-286: LGTM - Sync message translations are appropriate.The new sync-related resource strings (
SyncPushFailed,SyncPullFailed,SyncPushSuccess) are well-translated. Verify whetherSyncPullSuccessshould be added for consistency with the push operation pair.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/DatasyncOperationEntityType.cs (1)
1-127: LGTM - Auto-generated EF Core compiled model.This is auto-generated code for the
DatasyncOperationentity type from CommunityToolkit.Datasync. The entity mapping, properties, and index configuration are correct for offline sync operations.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs (1)
55-81: Sync logic implementation looks correct.The push-then-pull flow with conditional pull based on
pullRecentChangesis appropriate. The exception handling correctly usesNonInterruptingwhen online (to avoid blocking UI) andNonewhen offline. The success notification threshold (CompletedOperations > 0) prevents noise for no-op syncs.src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Todo/TodoItemTableController.cs (3)
11-23: Controller setup looks correct for Datasync offline sync.The dual authorization policies, soft delete enablement, and logger assignment follow the expected pattern for a TableController.
45-50: ReplaceAsync correctly enforces user ownership.Setting
UserIdbefore calling the base ensures the entity is always associated with the current user. Combined withAsQueryableAsyncfiltering, this prevents users from modifying others' items.
29-50: Consider defensive null-checking for HttpContext access in repository methods.The repository uses
httpContextAccessor.HttpContext!without explicit null validation inAsQueryableAsync,CreateAsync, andReplaceAsyncmethods. While this pattern is generally safe when the repository is used exclusively within HTTP request scope (e.g., by controllers), explicitly checking for null and throwing a descriptive exception would improve error clarity if the repository is accidentally used in non-HTTP contexts (e.g., background jobs, scheduled tasks). Consider adding a guard clause or helper method to validate the context is available.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor (1)
10-129: Well-structured offline Todo UI implementation.Good patterns observed:
- Debounced input (300ms) prevents excessive updates
- Virtualized list for performance with large datasets
- Pull-to-refresh for mobile UX
- Inline editing with clear Cancel/Save flow
- Delete confirmation dialog prevents accidental deletions
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251130225551_Initial.Designer.cs (1)
1-112: Auto-generated migration designer file.This file is auto-generated by EF Core and correctly defines the schema for offline sync support:
TodoItemstable for local Todo storageDatasyncDeltaTokensfor tracking sync stateDatasyncOperationsQueuewith appropriate index for pending operationsNo manual modifications should be made to this file.
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Models/Todo/TodoItem.cs (2)
25-31: Model properties and relationships look correct.The
[Required]attribute onTitlecombined with nullable reference type (string?) is valid - the attribute enforces database constraints while the nullability allows EF tracking states.
9-23: Class name mismatch:BaseEntityTableDatadoes not exist in CommunityToolkit.Datasync.Server.The CommunityToolkit.Datasync.Server package does not expose a
BaseEntityTableDatatype. The actual available base classes areEntityTableData,SqliteEntityTableData,CosmosEntityTableData, orRepositoryControlledEntityTableData—each specific to their respective backends. These classes implementITableData, which providesId,UpdatedAt,Version, andDeletedproperties.Verify which datasync entity class is the correct parent for
TodoItemin this template and ensure the inheritance is updated accordingly.Likely an incorrect or invalid review comment.
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/DatasyncDeltaTokenEntityType.cs (1)
1-59: Auto-generated EF Core compiled model looks correct.This is standard auto-generated code for EF Core runtime model mapping. The entity type configuration for
DatasyncDeltaTokenwithId(string key) andValue(long with sentinel 0L) follows expected patterns for the CommunityToolkit.Datasync library.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor.cs (3)
1-44: Well-structured offline-first component setup.Good use of
IDbContextFactory<AppOfflineDbContext>for creating short-lived DbContext instances, and proper initialization with default filter/sort values. The keyboard shortcut registration inOnAfterFirstRenderAsyncis appropriate.
72-97: Filtering and visibility logic is correct.The
FilterViewTodoItemsmethod properly handles sorting with ascending/descending options, andTodoItemIsVisiblecorrectly combines search and filter conditions.
145-149: VerifyVersionproperty initialization for newTodoItemDto.The
TodoItemDtocreated at lines 145-149 is initialized with onlyIdandTitleset. IfVersion(byte[]) is marked as required in the database schema or model configuration, ensure it is either assigned a default value, has a property initializer, or is handled automatically by the Datasync library/EF Core during sync operations. Review theTodoItemDtoclass definition andAppOfflineDbContextconfiguration to confirm proper initialization.src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/AppOfflineDbContextModelSnapshot.cs (2)
19-44: TodoItemDto entity configuration looks correct.The schema properly includes all fields required for Datasync synchronization:
Id(string),Deleted(soft-delete flag),UpdatedAt(sync timestamp), andVersion(concurrency token). TheTitlebeing required aligns with business requirements.
46-106: Datasync infrastructure entities are well-configured.The
DatasyncDeltaTokenandDatasyncOperationentities follow CommunityToolkit.Datasync conventions. The composite index on(ItemId, EntityType)inDatasyncOperationsQueueis appropriate for efficient sync operation lookups.
src/Templates/Boilerplate/Bit.Boilerplate/.docs/01- Entity Framework Core.md
Outdated
Show resolved
Hide resolved
...te/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor
Show resolved
Hide resolved
...lates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs
Show resolved
Hide resolved
...lates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request transforms the offline database demo from a simple profile editing form into a fully-featured offline Todo management system with bidirectional sync capabilities. The implementation leverages CommunityToolkit.Datasync for client-server synchronization and replaces the previous demo with a production-ready offline-first Todo application supporting add, edit, delete, search, sort, and filter operations.
Key Changes:
- Introduces bidirectional sync functionality between client offline database and server using CommunityToolkit.Datasync
- Replaces the simple offline database demo (profile editing) with a comprehensive offline Todo feature
- Implements breaking changes to TodoItemDto (ID type changed from Guid to string, UpdatedAt made nullable)
Reviewed changes
Copilot reviewed 48 out of 50 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/Urls.cs |
Updates demo URL from /offline-database-demo to /offline-todo |
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.resx |
Replaces offline database demo strings with offline Todo and sync-related messages |
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Resources/AppStrings.fa.resx |
Adds Farsi translations for new offline Todo and sync messages |
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/PageUrls.cs |
Reorganizes page URLs, moving OfflineTodo constant to conditional block |
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Todo/TodoItemDto.cs |
Changes ID type to string, adds Deleted property, makes UpdatedAt nullable, adds Version byte array |
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Controllers/Todo/ITodoItemController.cs |
Updates method signatures to accept string IDs instead of Guid |
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs |
Registers CommunityToolkit.Datasync services and repositories |
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Models/Todo/TodoItem.cs |
Makes TodoItem inherit from BaseEntityTableData for datasync support |
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/AppDbContext.cs |
Refactors concurrency handling, renames SetConcurrencyStamp to OnSavingChanges, updates UpdatedAt automatically |
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Todo/TodoItemTableController.cs |
New controller providing datasync TableController with user-scoped data access |
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Todo/TodoItemController.cs |
Updates to use string IDs for Todo items |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs |
New service managing push/pull synchronization with server |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/IClientCoreServiceCollectionExtensions.cs |
Registers SyncService and updates DbContext registration |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/AppOfflineDbContext.cs |
Replaces UserDto DbSet with TodoItemDto, configures datasync with server endpoint |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/* |
New migrations for TodoItems and datasync tables, removes old User migrations |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/CompiledModel/* |
Updated EF Core compiled models for new schema |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.* |
New comprehensive offline Todo page with full CRUD, search, filter, and sort capabilities |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineDatabaseDemoPage.* |
Removed old profile editing demo |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/TodoPage.razor |
Updates nullable handling for UpdatedAt property |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/NavBar.razor |
Updates navigation to use OfflineTodo URL with different icon |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/MainLayout.razor.items.cs |
Reorganizes nav panel items for offline Todo |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/service-worker.published.js |
Updates demo URL reference in comments |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Web/wwwroot/manifest.json |
Updates PWA manifest shortcut URL |
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Maui/Platforms/Android/MainActivity.cs |
Updates deep link configuration for offline Todo |
src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props |
Adds CommunityToolkit.Datasync package versions |
src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json |
Updates template exclusion conditions for offline database feature |
src/Templates/Boilerplate/Bit.Boilerplate/.github/prompts/getting-started.prompt.md |
Removed entire getting started prompt file |
src/Templates/Boilerplate/Bit.Boilerplate/.github/copilot-instructions.md |
Removes reference to getting-started prompt, adds RTL language instruction |
Files not reviewed (2)
- src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251128225322_Initial.Designer.cs: Language not supported
- src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Data/Migrations/20251130225551_Initial.Designer.cs: Language not supported
...Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/AppDbContext.cs
Show resolved
Hide resolved
...Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor.cs
Show resolved
Hide resolved
...lates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/SyncService.cs
Show resolved
Hide resolved
...it.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Todo/TodoItemTableController.cs
Outdated
Show resolved
Hide resolved
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Todo/TodoItemDto.cs
Outdated
Show resolved
Hide resolved
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Todo/TodoItemDto.cs
Outdated
Show resolved
Hide resolved
...Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/OfflineTodoPage.razor.cs
Show resolved
Hide resolved
This reverts commit b3300f3.
closes #11779
Summary by CodeRabbit
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.