feat(calendar): cascade-delete a board's events when the board is deleted#1003
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eted Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ails Set countLoaded=true in the error callback of getBoardEventCount so that a failed HTTP request does not permanently disable the Delete button. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the BackendConfiguration calendar board deletion flow so that deleting a calendar board also soft-deletes all event series placed on that board (via the existing per-series delete path), and adds a read-only API + UI wiring to show an event-count warning in the board delete confirmation dialog.
Changes:
- Backend:
DeleteBoardnow enumerates distinct event series IDs on the board and callsDeleteEntireSeriesfor each before deleting the board; newGET .../boards/{id}/event-countendpoint added. - Frontend: calendar service adds
getBoardEventCount; board-delete modal fetches the count and updates the dialog text; en/da translation keys added. - Tests/Docs: new integration tests for cascade + count; spec/plan documentation added.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Services/BackendConfigurationCalendarService/IBackendConfigurationCalendarService.cs | Adds service contract for board event-count lookup. |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Services/BackendConfigurationCalendarService/BackendConfigurationCalendarService.cs | Implements cascade delete in DeleteBoard and adds GetBoardEventCount. |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn/Controllers/CalendarController.cs | Exposes new GET boards/{id}/event-count endpoint. |
| eFormAPI/Plugins/BackendConfiguration.Pn/BackendConfiguration.Pn.Integration.Test/CalendarBoardDeleteCascadeTests.cs | Adds integration coverage for count + cascade delete + abort-on-failure behavior. |
| eform-client/src/app/plugins/modules/backend-configuration-pn/services/backend-configuration-pn-calendar.service.ts | Adds frontend API method to retrieve board event count. |
| eform-client/src/app/plugins/modules/backend-configuration-pn/modules/calendar/modals/board-delete-modal/board-delete-modal.component.ts | Fetches event count on modal open for warning text. |
| eform-client/src/app/plugins/modules/backend-configuration-pn/modules/calendar/modals/board-delete-modal/board-delete-modal.component.html | Updates confirmation copy to permanent deletion with count. |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/enUS.ts | Adds translation entry for new warning string. |
| eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/da.ts | Adds Danish translation entry for new warning string. |
| docs/superpowers/specs/2026-06-11-board-delete-cascade-events-design.md | Adds design spec for cascade-delete and count warning. |
| docs/superpowers/plans/2026-06-11-board-delete-cascade-events.md | Adds implementation plan for backend/frontend/tests. |
Comment on lines
+3243
to
+3263
| public async Task<OperationDataResult<int>> GetBoardEventCount(int id) | ||
| { | ||
| try | ||
| { | ||
| var count = await backendConfigurationPnDbContext.CalendarConfigurations | ||
| .Where(x => x.WorkflowState != Constants.WorkflowStates.Removed) | ||
| .Where(x => x.BoardId == id) | ||
| .Select(x => x.AreaRulePlanningId) | ||
| .Distinct() | ||
| .CountAsync(); | ||
|
|
||
| return new OperationDataResult<int>(true, count); | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| SentrySdk.CaptureException(e); | ||
| logger.LogError(e, "BackendConfigurationCalendarService.GetBoardEventCount: {Message}", e.Message); | ||
| return new OperationDataResult<int>(false, | ||
| $"{localizationService.GetString("ErrorWhileReadingCalendarBoard")}: {e.Message}"); | ||
| } | ||
| } |
Comment on lines
+15
to
+37
| export class BoardDeleteModalComponent implements OnInit { | ||
| eventCount = 0; | ||
| countLoaded = false; | ||
|
|
||
| constructor( | ||
| private dialogRef: MatDialogRef<BoardDeleteModalComponent>, | ||
| @Inject(MAT_DIALOG_DATA) public data: BoardDeleteModalData, | ||
| private calendarService: BackendConfigurationPnCalendarService, | ||
| ) {} | ||
|
|
||
| ngOnInit() { | ||
| this.calendarService.getBoardEventCount(this.data.board.id).subscribe({ | ||
| next: res => { | ||
| if (res && res.success) { | ||
| this.eventCount = res.model; | ||
| } | ||
| this.countLoaded = true; | ||
| }, | ||
| error: () => { | ||
| this.countLoaded = true; | ||
| }, | ||
| }); | ||
| } |
| <p>{{ 'Are you sure you want to delete the board' | translate }} <strong>{{ data.board.name }}</strong>?</p> | ||
| <p>{{ 'All tasks associated with this board will lose their board association' | translate }}.</p> | ||
| <p> | ||
| {{ 'This will permanently delete the board and its {{count}} events. This cannot be undone.' | translate:{count: eventCount} }} |
| <div mat-dialog-actions class="d-flex flex-row justify-content-end"> | ||
| <button class="btn-cancel" (click)="onCancel()">{{ 'Cancel' | translate }}</button> | ||
| <button class="btn-delete" (click)="onConfirm()">{{ 'Delete' | translate }}</button> | ||
| <button class="btn-delete" [disabled]="!countLoaded" (click)="onConfirm()">{{ 'Delete' | translate }}</button> |
Comment on lines
+23
to
+24
| [TestFixture] | ||
| public class CalendarBoardDeleteCascadeTests : TestBaseSetup |
Comment on lines
+5
to
+7
| using BackendConfiguration.Pn.Services.BackendConfigurationCalendarService; | ||
| using BackendConfiguration.Pn.Services.BackendConfigurationLocalizationService; | ||
| using BackendConfiguration.Pn.Services.BackendConfigurationTaskWizardService; |
…ascade-events # Conflicts: # eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/da.ts # eform-client/src/app/plugins/modules/backend-configuration-pn/i18n/enUS.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Deleting a calendar board now cascade-deletes every event placed on that board, and the delete-confirmation dialog warns accurately (permanent deletion) with the event count. Previously
DeleteBoardonly soft-deleted the board, orphaning its events under a non-existent board.Changes
BackendConfigurationCalendarService.DeleteBoard): enumerates the board's events viaCalendarConfiguration.BoardIdand reuses the existingDeleteEntireSeries(arpId)per event (identical to a manual single-event delete), deleting the board last and aborting on the first event-delete failure so a partial failure leaves the board intact/recoverable. All soft-deletes (WorkflowState='Removed').GET api/backend-configuration-pn/calendar/boards/{id}/event-countreturning the distinct event count for the dialog.getBoardEventCountservice method; the board-delete modal fetches the count and shows a permanent-deletion warning ("This will permanently delete the board and its N events. This cannot be undone."); Delete stays usable even if the count fetch errors; en/da translations added.Tests
Notes
CalendarConfiguration.BoardIdandCalendarBoard(out of scope; cascade is explicit).docs/superpowers/.🤖 Generated with Claude Code