Add BitFullCalendar extras component (#12449)#12450
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds the FullCalendar extras component, shared state and helpers, calendar views, timeline layouts, styling, and demo/navigation entries. ChangesBitFullCalendar feature
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
🟡 Minor comments (11)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor-5-5 (1)
5-5:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPolish the page description text for user-facing docs.
Current wording is awkward and inconsistent in casing (
"fullcalendar component of the bit BlazorUI components"). Consider a clearer description, e.g. “FullCalendar component for Bit BlazorUI.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor` at line 5, The Description attribute text in the BitFullCalendarDemo.razor component has awkward wording and inconsistent casing. Update the Description property to use proper casing for "FullCalendar" (currently lowercase) and simplify the text to remove redundancy. Instead of "fullcalendar component of the bit BlazorUI components", use clearer phrasing such as "FullCalendar component for Bit BlazorUI" to improve readability and consistency for user-facing documentation.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs-213-218 (1)
213-218:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse active culture for time labels instead of
InvariantCulture.At Line 216 and Line 253, forcing invariant formatting breaks localization consistency for time strings in non-English cultures.
Suggested fix
- public static string FormatTime(DateTime date, bool use24Hour) + public static string FormatTime(DateTime date, bool use24Hour, CultureInfo? culture = null) { + culture ??= CultureInfo.CurrentUICulture; return use24Hour - ? date.ToString("HH:mm", CultureInfo.InvariantCulture) - : date.ToString("h:mm tt", CultureInfo.InvariantCulture); + ? date.ToString("HH:mm", culture) + : date.ToString("h:mm tt", culture); } @@ - public static string FormatHourLabel(int hour, bool use24Hour) + public static string FormatHourLabel(int hour, bool use24Hour, CultureInfo? culture = null) { var dt = DateTime.Today.AddHours(hour); + culture ??= CultureInfo.CurrentUICulture; return use24Hour - ? dt.ToString("HH:00", CultureInfo.InvariantCulture) - : dt.ToString("h tt", CultureInfo.InvariantCulture); + ? dt.ToString("HH:00", culture) + : dt.ToString("h tt", culture); }Also applies to: 248-254
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs` around lines 213 - 218, The FormatTime method is using CultureInfo.InvariantCulture for both the 24-hour and 12-hour time format calls, which prevents localization for non-English cultures. Replace CultureInfo.InvariantCulture with CultureInfo.CurrentCulture in both date.ToString() calls within the FormatTime method to respect the user's active culture settings. Apply the same fix to the similar time formatting code mentioned in the "Also applies to" section around lines 248-254.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs-25-27 (1)
25-27:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winTreat midnight
EndDateas exclusive for day-span classification.At Line 25,
IsSingleDayuses directDateequality, so an event like2026-06-20 22:00 -> 2026-06-21 00:00is flagged as multi-day even though it ends at the day boundary.Suggested fix
public class BitFullCalendarEvent { @@ - public bool IsSingleDay => StartDate.Date == EndDate.Date; + private DateTime EndDateForDaySpan => + EndDate.TimeOfDay == TimeSpan.Zero && EndDate > StartDate + ? EndDate.AddTicks(-1) + : EndDate; + + public bool IsSingleDay => StartDate.Date == EndDateForDaySpan.Date; public bool IsMultiDay => !IsSingleDay; public TimeSpan Duration => EndDate - StartDate;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 25 - 27, The IsSingleDay property at line 25 of BitFullCalendarEvent class does not treat midnight EndDate as exclusive, causing events ending at 00:00 of the next day to be incorrectly classified as multi-day. Fix this by adjusting the Date comparison in the IsSingleDay property to subtract one tick or unit of time from EndDate before comparing dates, ensuring that an EndDate at midnight is treated as the end of the previous day rather than the start of the next day.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cs-49-49 (1)
49-49:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winMake
Sourcerequired to prevent silent origin misclassification.If omitted,
Sourcedefaults toDialog(enum zero), which can report incorrect origin metadata in emitted change payloads. Mark itrequiredto force explicit assignment.Proposed fix
- public BitFullCalendarChangeSource Source { get; init; } + public required BitFullCalendarChangeSource Source { get; init; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cs` at line 49, Add the `required` keyword to the Source property in the BitFullCalendarChangeEventArgs class to force callers to explicitly assign a BitFullCalendarChangeSource value, preventing silent defaults to Dialog (the zero enum value) which can cause incorrect origin metadata in change payloads.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor-20-23 (1)
20-23:⚠️ Potential issue | 🟡 MinorSet add-event button type explicitly to avoid accidental form submission.
Without
type="button", this button defaults totype="submit"per HTML specification. If the FullCalendar component is used inside a form context, the button will unintentionally trigger form submission instead of only calling theOnAddEventClickhandler. Adding the explicit type prevents this risk.🛠️ Suggested fix
- <button class="bit-bfc-btn bit-bfc-btn-primary bit-bfc-btn-sm" `@onclick`="OnAddEventClick"> + <button type="button" class="bit-bfc-btn bit-bfc-btn-primary bit-bfc-btn-sm" `@onclick`="OnAddEventClick">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor` around lines 20 - 23, The button element with the OnAddEventClick handler in BitFcCalendarHeader.razor lacks an explicit type attribute, causing it to default to type="submit" per HTML specification. This can trigger unintended form submission if the FullCalendar component is placed within a form context. Add type="button" explicitly to the button element that contains the OnAddEventClick event handler to ensure it only calls the click handler and does not submit any parent form.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor-6-6 (1)
6-6:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse calendar culture for the dialog date header.
This currently formats with default culture instead of
State.Culture, causing localization inconsistencies.Suggested fix
- <h3>`@Texts.EventListTitlePrefix` `@Date.ToString`("dddd, MMM d, yyyy")</h3> + <h3>`@Texts.EventListTitlePrefix` `@Date.ToString`("dddd, MMM d, yyyy", State.Culture)</h3>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor` at line 6, In the BitFcEventListDialog.razor component's h3 element, the date formatting using Date.ToString("dddd, MMM d, yyyy") does not respect the calendar's culture setting. Modify the Date.ToString call to include State.Culture as a culture parameter so that the date is formatted according to the calendar's culture instead of the default culture. This will ensure the date header displays in the correct localized format.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cs-19-23 (1)
19-23:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAwait
OnClose.InvokeAsync()in the edit-close flow.The callback task is currently not awaited.
Suggested fix
- private void OnEditClose() + private async Task OnEditClose() { _showEdit = false; - OnClose.InvokeAsync(); + await OnClose.InvokeAsync(); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cs` around lines 19 - 23, The OnEditClose() method invokes the OnClose callback asynchronously but does not await the result, which can cause the callback to not complete properly. Change the OnEditClose() method signature from void to async Task, and add the await keyword before the OnClose.InvokeAsync() call to ensure the asynchronous operation completes before the method returns.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs-36-49 (1)
36-49:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winKeep
SelectedDateconsistent across both add-event paths.
State.SetSelectedDate(day)is only applied whenOnAddClickis delegated, not when using the built-in add dialog.Suggested fix
private async Task OnHourClickAsync(DateTime day, int hour) { + State.SetSelectedDate(day); + if (OnAddClick.HasDelegate) { - State.SetSelectedDate(day); var draft = BitFullCalendarHelpers.CreateDraftEventForTimeSlot(day, hour); await OnAddClick.InvokeAsync(draft); return; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs` around lines 36 - 49, The OnHourClickAsync method only calls State.SetSelectedDate(day) when OnAddClick has a delegate, but not when using the built-in add dialog (when _addDate, _addHour, and _showAddDialog are set). Move the State.SetSelectedDate(day) call outside of the if block so it executes regardless of which path is taken, ensuring the SelectedDate remains consistent across both the delegated callback path and the built-in dialog path.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor-8-10 (1)
8-10:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse calendar month count instead of hardcoded 12.
Line 8 should use the active calendar’s month count (
GetMonthsInYear) to avoid incorrect year rendering in calendars that don’t match a fixed 12-month assumption.Proposed fix
- var months = Enumerable.Range(1, 12) + var monthsInYear = cal.GetMonthsInYear(culturalYear); + var months = Enumerable.Range(1, monthsInYear) .Select(m => cal.ToDateTime(culturalYear, m, 1, 0, 0, 0, 0)) .ToArray();🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor` around lines 8 - 10, Replace the hardcoded value 12 in the Enumerable.Range call within the months variable assignment with a dynamic call to the calendar's month count method. Instead of Range(1, 12), use Range(1, cal.GetMonthsInYear(culturalYear)) or the appropriate equivalent method on the cal object to retrieve the actual number of months in the given year, ensuring the code correctly handles calendars with varying month counts.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor-79-80 (1)
79-80:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winDrop preview can stick after drag cancellation.
Preview class application should be tied to active drag state; otherwise stale highlights can remain after drag ends outside a drop target.
Suggested fix
- var isPreview = _dragResourceId == rowKey && _dragDay == day.Date; + var isPreview = State.IsDragging && _dragResourceId == rowKey && _dragDay == day.Date; ... - var isPreview = _dragResourceId == rowKey && _dragDay == day.Date; + var isPreview = State.IsDragging && _dragResourceId == rowKey && _dragDay == day.Date;Also applies to: 106-107
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor` around lines 79 - 80, The isPreview condition on lines 79-80 (and also on lines 106-107) only checks if the current cell matches the drag source cell, but does not verify if an active drag operation is in progress. When a drag is cancelled, these variables retain their values, causing stale preview highlights to remain. Add a check for an active drag state (such as a boolean flag tracking whether a drag is currently in progress) to the isPreview condition so that the preview class is only applied when there is both an active drag operation and the cell matches the drag source.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor-60-61 (1)
60-61:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winDrop preview can remain visible after drag cancel/end.
Preview styling is computed without checking active drag state, so a canceled drag can leave stale highlighted cells.
Suggested fix
- var isPreviewHour = _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 0; - var isPreviewHalf = _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 30; + var isPreviewHour = State.IsDragging && _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 0; + var isPreviewHalf = State.IsDragging && _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 30; ... - var isPreviewHour = _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 0; - var isPreviewHalf = _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 30; + var isPreviewHour = State.IsDragging && _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 0; + var isPreviewHalf = State.IsDragging && _dragResourceId == rowKey && _dragHour == hour && _dragMinute == 30;Also applies to: 95-96
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor` around lines 60 - 61, The preview styling for drag operations in BitFcTimelineDayView.razor is computed without verifying that an active drag is in progress, allowing stale preview highlighting to persist after a drag is canceled. Add a check to verify that a drag operation is currently active before setting isPreviewHour and isPreviewHalf variables around lines 60-61. Additionally, apply the same fix to the similar preview checks mentioned at lines 95-96. The condition should verify that _dragResourceId is not null or empty and that an active drag state exists before allowing the preview styles to be applied.
🧹 Nitpick comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs (1)
90-101: 🏗️ Heavy liftUse deterministic lexical fallback for unknown color IDs.
Line 101 uses a hash-based fallback, which does not implement “unknown ids by name” and can reorder groups between process runs. Prefer a stable secondary textual key at sort callsites (e.g.,
ThenBy(colorId, OrdinalIgnoreCase)).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs` around lines 90 - 101, The GetSortOrder method in BitFullCalendarColorScheme currently uses StringComparer.OrdinalIgnoreCase.GetHashCode() for unknown color IDs, which is non-deterministic across process runs and doesn't implement text-based sorting as documented. Replace the hash-based fallback on line 101 with a deterministic approach that sorts unknown IDs lexically by their string value instead of relying on hash codes, such as computing a value based on the ordinal character values of the trimmed string or implementing a stable text-based comparison alternative.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor (1)
11-16: ⚡ Quick winPre-index week events to avoid repeated linear scans in render.
At Line 14,
FirstOrDefaultover_weekEventsruns inside nested day/row loops, which makes rerenders grow quadratically with event volume. Precompute a(day,row) -> eventlookup inOnParametersSetand render with O(1) lookups.♻️ Proposed optimization
--- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cs @@ - private Dictionary<string, int> _eventRows = new(); + private Dictionary<string, int> _eventRows = new(); + private Dictionary<(DateTime Day, int Row), BitFullCalendarEvent> _weekEventsByDayRow = new(); @@ - _eventRows = new Dictionary<string, int>(); + _eventRows = new Dictionary<string, int>(); + _weekEventsByDayRow = new(); @@ - foreach (var d in evDays) - rowUsageByDay[d.Date].Add(row); + foreach (var d in evDays) + { + var day = d.Date; + rowUsageByDay[day].Add(row); + _weekEventsByDayRow[(day, row)] = ev; + } break; } } }--- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor @@ - var ev = _weekEvents.FirstOrDefault(e => - _eventRows.GetValueOrDefault(e.Id) == r && - e.StartDate.Date <= d.Date && e.EndDate.Date >= d.Date); + _weekEventsByDayRow.TryGetValue((d.Date, r), out var ev);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor` around lines 11 - 16, The FirstOrDefault call over _weekEvents is executed inside nested loops for each day and row, causing quadratic time complexity during rerenders. Create a precomputed lookup dictionary in the OnParametersSet lifecycle method that maps (date, row) tuples to events based on the same filtering criteria (checking _eventRows values and date ranges with StartDate.Date and EndDate.Date comparisons). Then replace the FirstOrDefault logic in the render loop with a simple O(1) dictionary lookup using the current day and row as the key.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs`:
- Around line 8-21: The RemoveAfterDelay method mutates _toasts without
dispatcher protection on line 19, creating a race condition with the Razor
template's foreach loop. Additionally, delayed removal tasks are never canceled
when the component is disposed. To fix this, wrap the _toasts.RemoveAll() call
inside RemoveAfterDelay with InvokeAsync() to ensure it runs on the renderer
dispatcher. Next, create a collection to track CancellationTokenSource objects
for each delayed removal task, modify RemoveAfterDelay to accept a
CancellationToken and check it after the Task.Delay, and implement
IAsyncDisposable on the component class to cancel all pending removal tasks when
the component is disposed.
---
Major comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cs`:
- Around line 156-159: The ResolveCulture() method in BitFullCalendar.razor.cs
attempts to instantiate CultureInfo with a user-provided name without handling
potential exceptions. Wrap the CultureInfo(name) constructor call in a try-catch
block that catches CultureNotFoundException and falls back to the default
culture (Culture ?? CultureInfo.CurrentUICulture) when an invalid culture name
is provided. This prevents the component initialization from failing due to
invalid CultureName parameter values.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Line 3: Remove the `.scss` file extension from the import statement in the
BitFullCalendar.scss file. The import path for the functions partial currently
includes `functions.scss` but should be changed to `functions` (without the
extension) to comply with the scss/load-partial-extension linting rule. Update
the import statement to remove the `.scss` extension while keeping the relative
path and quotes intact.
- Line 197: The keyframe names bfcFadeIn and bfcSlideUp are using camelCase
naming, which violates the stylelint keyframes-name-pattern rule that requires
kebab-case. Rename bfcFadeIn to bfc-fade-in and bfcSlideUp to bfc-slide-up in
both their keyframe definitions (where they are declared with `@keyframes`) and in
all animation property references throughout the BitFullCalendar.scss file.
Ensure all 8 occurrences are updated consistently to use the kebab-case format.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 113-134: In the endResize function, the OnResizeEnd call must
always execute even if the OnResizeMove invocation fails. Wrap the await
dotNetRef.invokeMethodAsync call for OnResizeMove in a try-finally block, and
move the await dotNetRef.invokeMethodAsync call for OnResizeEnd into the finally
block to guarantee it always executes regardless of whether the OnResizeMove
call succeeds or throws an error. Apply the same fix to the corresponding
endResize function in the other section mentioned at lines 183-204.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor`:
- Around line 16-17: Labels in the BitFcAddEditEventDialog component are not
programmatically associated with their corresponding input controls, which
breaks accessibility for screen readers. Add a unique id attribute to each input
element (the text inputs near the TitleLabel, and other form fields at lines
25-26, 30-31, 39-40, 49-50, and 76-79), then add a for attribute to each label
element that matches the id of its paired input. For example, add
id="_titleInput" to the input with `@bind`="_title" and add for="_titleInput" to
the label for TitleLabel.
- Around line 68-70: The attendee remove button at line 68 is an icon-only
button without an accessible label, which makes it unclear to assistive
technologies. Add an aria-label attribute to the button element that calls
RemoveAttendee(attendee) to provide a descriptive accessible name such as
"Remove attendee" or "Remove [attendee name]" so screen readers can properly
announce the button's purpose to users.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs`:
- Around line 71-74: The OnFocusOut method closes the picker unconditionally
whenever any internal element loses focus, causing the picker to close when
focus moves between internal controls like the trigger button and time/day
controls. Modify the OnFocusOut method to check whether focus is moving to
another element within the component container before closing the picker. You
should verify if the newly focused element (accessible through FocusEventArgs or
related properties) is still a child of the component, and only set _isOpen to
false when focus actually leaves the entire component bounds.
- Around line 54-57: In the SelectDate method, the new DateTime being
constructed uses date.Kind as the DateTimeKind parameter, which can
inadvertently downgrade a previously set Utc or Local kind to Unspecified. To
preserve the bound DateTimeKind, replace date.Kind with Value.Kind when
constructing the selected DateTime object, ensuring the original kind property
is maintained throughout the selection process.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor`:
- Around line 4-11: The icon-only navigation buttons using
State.NavigatePrevious and State.NavigateNext rely only on the title attribute
for accessibility, which may not be consistently announced by assistive
technologies. Add aria-label attributes to both buttons with descriptive text
matching the button's purpose (e.g., "Previous" and "Next"), and also add
type="button" to both button elements to ensure they are semantically correct
and properly recognized by assistive technologies.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor`:
- Around line 8-19: The entire mode tabs container in BitFcModeTabs.razor is
hidden when State.Resources.Count is zero, which traps users in Timeline mode if
resources become empty since they have no UI way to switch back to Event mode.
Remove the outer conditional check on State.Resources.Count so that the mode
tabs remain visible even when resources are empty. Keep the tabs accessible at
all times by rendering the entire div with the foreach loop over _modes and the
State.SetMode(mode) calls regardless of whether State.Resources has items.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Around line 12-47: The checkbox inputs in the three dropdown items (for badge
variant toggle, time format toggle, and event layout toggle) and the number
input for day start hour lack proper accessible associations with their labels.
Add unique `id` attributes to each input element (the three checkboxes and the
number input), then update the `label` elements wrapping the checkboxes to
include `for` attributes referencing their corresponding input ids, and for the
number input that doesn't have a wrapping label, add an `aria-labelledby`
attribute that references the id of the span containing DayStartsAtLabel text to
establish the semantic relationship for screen readers.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`:
- Around line 20-28: The constructor in BitFullCalendarColorScheme keeps a live
reference to the caller-provided options list on line 21 by directly assigning
it to the Options property, while the _byId dictionary is built only once during
construction. If the source list is mutated after construction, Options and the
_byId lookup dictionary can become inconsistent. To fix this, create a defensive
copy/snapshot of the options list (using ToList() or similar) before assigning
it to Options, ensuring that both Options and _byId always represent the same
immutable state regardless of external mutations to the original list.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cs`:
- Line 19: The date.ToString("yyyy-MM-dd") call on the date variable is
culture-sensitive and may produce non-ASCII digits in certain locales, which
will break JavaScript date matching and parsing. Modify the ToString call to
explicitly use CultureInfo.InvariantCulture as the second parameter to ensure
the date is always formatted with ASCII digits in the yyyy-MM-dd format,
regardless of the system locale.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs`:
- Around line 68-82: The CloneEvent method in BitFullCalendarChangeNotifier
performs a shallow copy of the Data property by directly assigning the reference
instead of creating a deep clone, which violates the deep-snapshot contract.
Modify the Data assignment in the CloneEvent method to deep clone the
source.Data object rather than copying the reference, using an appropriate deep
cloning mechanism such as JSON serialization and deserialization to ensure
mutable objects are not shared between the original and cloned event payloads.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 178-186: The EventsMatch method is using reference equality checks
only, which means when parent components modify existing event instances without
changing the reference, SyncEvents skips the update thinking nothing changed.
Update the EventsMatch method to perform deep content-based comparison of the
event properties instead of just ReferenceEquals checks, so that mutations to
existing items are properly detected. Apply the same fix to the SyncResources
method and its corresponding ResourcesMatch comparison method to ensure
consistent behavior across both event and resource synchronization.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs`:
- Around line 3-90: The BitFcCalendarDayView component displays current events
based on DateTime.Now but never triggers periodic re-renders, causing the
"Happening now" status to become stale during long sessions. Add a timer
mechanism in the component lifecycle (such as in OnInitializedAsync or
OnAfterRenderAsync) that periodically calls StateHasChanged() at regular
intervals (e.g., every minute) to refresh the component and keep the current
event status accurate. Ensure the timer is properly disposed in the component's
cleanup to prevent memory leaks, similar to how the scroll signature is managed
in the existing lifecycle methods.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs`:
- Around line 13-17: In the timer callback initialization for _timer, both
UpdatePosition() and StateHasChanged() must be wrapped inside a single
InvokeAsync call to ensure they execute on the Blazor renderer thread. Currently
UpdatePosition() is called directly on the timer thread before being marshaled,
which can cause race conditions since _positionPx is modified. Move the
UpdatePosition() call inside the InvokeAsync delegate so that both methods
execute atomically on the renderer thread, preventing state modification outside
the renderer's synchronization context.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor`:
- Around line 43-47: The week time slot divs with class bit-bfc-hour-row are
currently only clickable, which excludes keyboard users. Add a keyboard event
handler by binding `@onkeydown` to a new method (OnHourSlotKeyDownAsync) that
accepts KeyboardEventArgs along with the day and hour parameters, and invoke the
existing OnHourClickAsync method when the Enter or Space keys are pressed. Apply
this keyboard handler binding to both affected div elements in the week view
grid (the ones currently showing `@onclick`="() => OnHourClickAsync(d, hour)").
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor`:
- Around line 28-35: The BitFcEventBlock event container div is not
keyboard-accessible, preventing keyboard users from activating event details.
Add the tabindex="0" attribute to the div element to make it focusable, then add
the `@onkeydown`="OnKeyDown" event binding to the same div. Implement the
OnKeyDown method that takes KeyboardEventArgs as a parameter and calls the
existing OnClick method when the user presses Enter or Space keys.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor`:
- Around line 15-21: The icon-only buttons for PrevMonth and NextMonth
navigation lack accessible labels for screen readers, making them inaccessible.
Add aria-label attributes to both buttons with descriptive text like "Previous
month" and "Next month" respectively. Additionally, the day selection elements
(the clickable span elements referenced at lines 43-45) need keyboard support -
convert them to button elements or add keyboard event handlers (onkeydown) to
make them accessible via keyboard navigation, ensuring they can be focused and
activated with Enter/Space keys like standard controls.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cs`:
- Around line 9-15: The `_displayMonth` field is initialized only once in
`OnInitialized()` and can become out of sync with `State.SelectedDate` when the
selected date changes externally. Override the `OnParametersSet()` lifecycle
method in the BitFcMiniCalendar component to synchronize `_displayMonth`
whenever parameters change, using the same logic that calculates `_displayMonth`
from `State.SelectedDate` as in `OnInitialized()`. This ensures `_displayMonth`
stays synchronized with external changes to the selected date.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor`:
- Around line 8-12: The clickable div elements in the BitFcDayCell component
(around line 8 with the OnCellClick handler and the additional clickable element
around line 44) do not support keyboard navigation and activation, making them
inaccessible to keyboard users. Convert these interactive divs to proper
keyboard-accessible controls by adding a tabindex attribute to make them
focusable, an ARIA role to identify them as interactive elements, and keyboard
event handlers (`@onkeydown` or `@onkeyup`) that trigger the same OnCellClick action
when Enter or Space keys are pressed, matching the click behavior.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor`:
- Around line 19-25: The BitFcMonthEventBadge component's event badge div is not
keyboard-accessible. Add tabindex="0" to the div element to make it focusable,
and add an `@onkeydown` event handler that detects Enter or Space key presses and
invokes OnSelected.InvokeAsync(Event) when those keys are pressed, matching the
behavior of the existing click handler for keyboard users.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cs`:
- Line 18: The constant _scrollContainerId in the BitFcTimelineDayView component
uses a fixed DOM id that can collide when multiple calendar instances render on
the same page. Change _scrollContainerId from a constant to an instance field
that generates a unique identifier per component instance (such as using a GUID
or unique suffix), ensuring each calendar instance has its own unique scroll
container id to prevent the scrollTimelineToTarget method from operating on the
wrong element.
- Around line 72-85: The OnSlotClickAsync method accepts a minute parameter but
discards it in the internal add flow when OnAddClick is not delegated. Store the
minute value by adding a field similar to _addStartHour (for example,
_addStartMinute), then assign the minute parameter to this field when setting
_showAddDialog to true. Next, pass this stored minute value to the
BitFcAddEditEventDialog component by updating its parameters, and ensure the
dialog component supports and respects the minute parameter when initializing
the time selection to preserve half-hour slot precision.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`:
- Around line 71-74: The catch block in BitFcTimelineEventBlock.razor.cs
currently only catches JSException, but common Blazor lifecycle exceptions like
JSDisconnectedException, InvalidOperationException, and
OperationCanceledException can also be thrown during interop calls and will
crash the render if not handled. Expand the catch clause to handle all these
exception types alongside JSException so they are properly swallowed and the
render retry logic is executed for all expected failure scenarios.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor`:
- Around line 23-27: The `!hasResources` conditional in
BitFcTimelineLayout.razor prevents the rendering of unassigned event rows
because the else block never executes when hasResources is false. Restructure
the logic to ensure that the unassigned-row rendering (referenced at lines
58-70) is not blocked by the !hasResources check. Either move the unassigned row
rendering outside of or before the hasResources conditional, or add a separate
condition that allows unassigned events to display independently of whether
resources exist.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Line 18: The _scrollContainerId constant in BitFcTimelineMonthView is
hardcoded, causing ID collisions when multiple calendar instances are rendered.
Replace the const declaration with a property or field that generates a unique
identifier per component instance (such as using a Guid or unique prefix based
on component state), ensuring each rendered timeline month view has a distinct
scroll container id that won't conflict with other instances on the same page.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor`:
- Around line 21-26: The code filters out null/empty resource IDs on line 21,
but then uses unguarded dictionary lookups with resource.Id and rowKey as keys
on lines 60, 91, and 126 without verifying they are not null or empty. Add guard
conditions before each dictionary lookup at these locations to check if the
resource ID or rowKey is null or empty, and either skip the operation or provide
a safe fallback to prevent runtime exceptions when rendering rows with invalid
resource identifiers.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cs`:
- Line 18: The constant _scrollContainerId with a hardcoded value
"bit-bfc-tl-week-scroll" will cause id collisions when multiple calendar
instances are rendered on the same page. Replace this constant with a
per-instance field that generates a unique scroll container id for each
BitFcTimelineWeekView component instance, such as using a generated guid or
unique identifier that is assigned when the component initializes.
- Around line 74-87: The OnSlotClickAsync method receives a minute parameter but
only uses it when OnAddClick has a delegate. In the fallback branch where the
built-in add dialog is shown (lines 84-86), the minute value is ignored. Store
the minute parameter in a new field (similar to how _addStartHour stores the
hour) such as _addStartMinute, and ensure this field is set when _showAddDialog
is set to true. Additionally, verify that the BitFcAddEditEventDialog component
uses this _addStartMinute field when initializing the event time, adding support
for StartMinute if it does not currently exist.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 21-22: The div elements with click handlers at lines 21-22 and
40-41 in BitFcCalendarYearView.razor lack keyboard accessibility, preventing
keyboard-only users from navigating. Add keyboard event support to both div
elements by implementing an onkeydown event handler that triggers the same
action (GoToMonth call at line 21 and the day/event navigation at line 40) when
Enter or Space keys are pressed. Additionally, add appropriate ARIA attributes
(role and tabindex) to make these divs focusable and semantically indicate they
are interactive elements to assistive technologies.
- Around line 37-38: The dayEvents filter in BitFcCalendarYearView.razor uses
only StartDate.Date comparison, which excludes multi-day events from
intermediate and end dates. Modify the Where clause to check if cell.Date falls
within a date-range overlap by comparing against both the event's StartDate and
EndDate properties, ensuring a multi-day event is included on every day it
spans, not just its start date.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The stylelint rule scss/load-partial-extension is being violated in
the extra-components.scss file. Remove the explicit .scss file extension from
the `@import` statement for BitFullCalendar - the stylelint rule requires that
SCSS partials be imported without their file extension, so the import should
reference only the directory path and filename without the .scss suffix.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Around line 18-23: The BitLink component in BitFullCalendarDemo.razor has
Target="_blank" set to open an external link in a new tab, but it is missing the
rel attribute required for security. Add rel="noopener noreferrer" to the
BitLink component that points to the NuGet package URL to prevent
reverse-tabnabbing vulnerabilities and properly isolate the opener context when
opening external links in a new tab.
---
Minor comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cs`:
- Around line 19-23: The OnEditClose() method invokes the OnClose callback
asynchronously but does not await the result, which can cause the callback to
not complete properly. Change the OnEditClose() method signature from void to
async Task, and add the await keyword before the OnClose.InvokeAsync() call to
ensure the asynchronous operation completes before the method returns.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor`:
- Line 6: In the BitFcEventListDialog.razor component's h3 element, the date
formatting using Date.ToString("dddd, MMM d, yyyy") does not respect the
calendar's culture setting. Modify the Date.ToString call to include
State.Culture as a culture parameter so that the date is formatted according to
the calendar's culture instead of the default culture. This will ensure the date
header displays in the correct localized format.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor`:
- Around line 20-23: The button element with the OnAddEventClick handler in
BitFcCalendarHeader.razor lacks an explicit type attribute, causing it to
default to type="submit" per HTML specification. This can trigger unintended
form submission if the FullCalendar component is placed within a form context.
Add type="button" explicitly to the button element that contains the
OnAddEventClick event handler to ensure it only calls the click handler and does
not submit any parent form.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cs`:
- Line 49: Add the `required` keyword to the Source property in the
BitFullCalendarChangeEventArgs class to force callers to explicitly assign a
BitFullCalendarChangeSource value, preventing silent defaults to Dialog (the
zero enum value) which can cause incorrect origin metadata in change payloads.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 25-27: The IsSingleDay property at line 25 of BitFullCalendarEvent
class does not treat midnight EndDate as exclusive, causing events ending at
00:00 of the next day to be incorrectly classified as multi-day. Fix this by
adjusting the Date comparison in the IsSingleDay property to subtract one tick
or unit of time from EndDate before comparing dates, ensuring that an EndDate at
midnight is treated as the end of the previous day rather than the start of the
next day.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 213-218: The FormatTime method is using
CultureInfo.InvariantCulture for both the 24-hour and 12-hour time format calls,
which prevents localization for non-English cultures. Replace
CultureInfo.InvariantCulture with CultureInfo.CurrentCulture in both
date.ToString() calls within the FormatTime method to respect the user's active
culture settings. Apply the same fix to the similar time formatting code
mentioned in the "Also applies to" section around lines 248-254.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs`:
- Around line 36-49: The OnHourClickAsync method only calls
State.SetSelectedDate(day) when OnAddClick has a delegate, but not when using
the built-in add dialog (when _addDate, _addHour, and _showAddDialog are set).
Move the State.SetSelectedDate(day) call outside of the if block so it executes
regardless of which path is taken, ensuring the SelectedDate remains consistent
across both the delegated callback path and the built-in dialog path.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 60-61: The preview styling for drag operations in
BitFcTimelineDayView.razor is computed without verifying that an active drag is
in progress, allowing stale preview highlighting to persist after a drag is
canceled. Add a check to verify that a drag operation is currently active before
setting isPreviewHour and isPreviewHalf variables around lines 60-61.
Additionally, apply the same fix to the similar preview checks mentioned at
lines 95-96. The condition should verify that _dragResourceId is not null or
empty and that an active drag state exists before allowing the preview styles to
be applied.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor`:
- Around line 79-80: The isPreview condition on lines 79-80 (and also on lines
106-107) only checks if the current cell matches the drag source cell, but does
not verify if an active drag operation is in progress. When a drag is cancelled,
these variables retain their values, causing stale preview highlights to remain.
Add a check for an active drag state (such as a boolean flag tracking whether a
drag is currently in progress) to the isPreview condition so that the preview
class is only applied when there is both an active drag operation and the cell
matches the drag source.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 8-10: Replace the hardcoded value 12 in the Enumerable.Range call
within the months variable assignment with a dynamic call to the calendar's
month count method. Instead of Range(1, 12), use Range(1,
cal.GetMonthsInYear(culturalYear)) or the appropriate equivalent method on the
cal object to retrieve the actual number of months in the given year, ensuring
the code correctly handles calendars with varying month counts.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Line 5: The Description attribute text in the BitFullCalendarDemo.razor
component has awkward wording and inconsistent casing. Update the Description
property to use proper casing for "FullCalendar" (currently lowercase) and
simplify the text to remove redundancy. Instead of "fullcalendar component of
the bit BlazorUI components", use clearer phrasing such as "FullCalendar
component for Bit BlazorUI" to improve readability and consistency for
user-facing documentation.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`:
- Around line 90-101: The GetSortOrder method in BitFullCalendarColorScheme
currently uses StringComparer.OrdinalIgnoreCase.GetHashCode() for unknown color
IDs, which is non-deterministic across process runs and doesn't implement
text-based sorting as documented. Replace the hash-based fallback on line 101
with a deterministic approach that sorts unknown IDs lexically by their string
value instead of relying on hash codes, such as computing a value based on the
ordinal character values of the trimmed string or implementing a stable
text-based comparison alternative.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor`:
- Around line 11-16: The FirstOrDefault call over _weekEvents is executed inside
nested loops for each day and row, causing quadratic time complexity during
rerenders. Create a precomputed lookup dictionary in the OnParametersSet
lifecycle method that maps (date, row) tuples to events based on the same
filtering criteria (checking _eventRows values and date ranges with
StartDate.Date and EndDate.Date comparisons). Then replace the FirstOrDefault
logic in the render loop with a simple O(1) dictionary lookup using the current
day and row as the key.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: e0daf90b-d30d-468a-b05d-3f9abc65f4a8
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 20
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🟡 Minor comments (6)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cs-16-17 (1)
16-17:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winValidate
StartOfDayHouragainst the documented 0–16 range.Line 17 accepts any integer even though the public contract documents 0–16, and the value is applied directly in
BitFullCalendar.razor.cs(Lines 199-210). Add clamping or validation to prevent out-of-range runtime behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cs` around lines 16 - 17, The StartOfDayHour property in BitFullCalendarOptions class lacks validation for the documented 0-16 range constraint, allowing any integer value to be set. This causes runtime issues when the unconstrained value is applied in BitFullCalendar.razor.cs. Add validation logic to the StartOfDayHour property setter to enforce the 0-16 range by either clamping the value using Math.Clamp or throwing an ArgumentException if an out-of-range value is provided, ensuring the property contract matches its documentation.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs-83-87 (1)
83-87:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse current UI culture when
cultureis omitted inStartOfWeek.Line 85 falls back to
DayOfWeek.Sundayinstead ofCultureInfo.CurrentUICulture, which makes this helper inconsistent with other culture-aware methods and can produce incorrect week boundaries for callers that passnull.Suggested fix
public static DateTime StartOfWeek(DateTime date, CultureInfo? culture = null) { - var startDay = culture?.DateTimeFormat.FirstDayOfWeek ?? DayOfWeek.Sunday; + culture ??= CultureInfo.CurrentUICulture; + var startDay = culture.DateTimeFormat.FirstDayOfWeek; return StartOfWeek(date, startDay); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs` around lines 83 - 87, The StartOfWeek method currently falls back to DayOfWeek.Sunday when the culture parameter is null, instead of using the current UI culture. Modify the startDay assignment in the StartOfWeek method to use CultureInfo.CurrentUICulture.DateTimeFormat.FirstDayOfWeek as the fallback instead of DayOfWeek.Sunday. This will make the method consistent with other culture-aware methods and properly respect regional week start conventions when no culture is explicitly provided.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor-4-7 (1)
4-7:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winPrevent browser default behavior on drop.
dropshould also prevent default to avoid accidental browser navigation/content handling on external drops.Suggested fix
<div class="bit-bfc-droppable @(_isOver ? "drag-over" : "") `@Class`" `@ondragover`="OnDragOver" `@ondragover`:preventDefault="true" `@ondragleave`="OnDragLeave" - `@ondrop`="OnDrop"> + `@ondrop`="OnDrop" + `@ondrop`:preventDefault="true">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor` around lines 4 - 7, The `@ondrop` event binding in the BitFcDroppableArea component is missing the preventDefault directive that is already applied to `@ondragover`. Add the :preventDefault="true" modifier to the `@ondrop` binding (similar to how it is applied to `@ondragover`) to ensure the browser's default behavior is prevented when items are dropped on the droppable area, avoiding accidental navigation or unwanted content handling from external drops.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor-13-14 (1)
13-14:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSet explicit button type to prevent accidental form submission.
These mode-tab buttons should be
type="button"; otherwise default submit behavior can fire when the calendar is placed inside a form.Suggested patch
- <button class="bit-bfc-mode-tab @(State.Mode == mode ? "active" : "")" + <button type="button" class="bit-bfc-mode-tab @(State.Mode == mode ? "active" : "")" `@onclick`="() => State.SetMode(mode)">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor` around lines 13 - 14, Add an explicit type="button" attribute to the button element with class "bit-bfc-mode-tab" to prevent it from defaulting to type submit and causing accidental form submissions when the calendar component is placed within a form. This ensures the button only triggers the onclick handler without submitting any parent form.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs-12-23 (1)
12-23:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAlign the first timer tick to the next minute boundary.
Line 22 schedules the first refresh exactly 60 seconds after init, which can keep the “current time” marker one minute behind clock boundaries. Aligning initial due-time to the next minute makes updates accurate on
HH:mmtransitions.Suggested fix
protected override void OnInitialized() { UpdatePosition(); + var now = DateTime.Now; + var due = TimeSpan.FromMinutes(1) + - TimeSpan.FromSeconds(now.Second) + - TimeSpan.FromMilliseconds(now.Millisecond); + if (due <= TimeSpan.Zero) due = TimeSpan.FromMinutes(1); + _timer = new Timer(_ => { // Run both the state mutation and the re-render on the renderer's dispatcher so // _positionPx is never modified outside the synchronization context. InvokeAsync(() => { UpdatePosition(); StateHasChanged(); }); - }, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); + }, null, due, TimeSpan.FromMinutes(1)); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs` around lines 12 - 23, The Timer in the BitFcCalendarTimeline component is configured with an initial due time of one minute, which causes the first refresh to occur one minute after initialization rather than at the next minute boundary. This misalignment can leave the "current time" marker behind by up to 60 seconds. Calculate the time remaining until the next minute boundary by finding the current time's seconds and milliseconds, then subtracting from one minute, and use this calculated TimeSpan as the dueTime parameter in the Timer constructor instead of TimeSpan.FromMinutes(1), keeping TimeSpan.FromMinutes(1) as the period for subsequent ticks. This ensures UpdatePosition is called at clock minute transitions rather than arbitrary intervals.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs-115-121 (1)
115-121:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAvoid repeated scroll interop when selected month is not the current month.
When no “today” target exists, this path retries JS interop every render. Add a month guard and cache the signature to prevent unnecessary calls.
Proposed change
protected override async Task OnAfterRenderAsync(bool firstRender) { var sig = $"{State.SelectedDate:yyyy-MM}|{DateTime.Today:yyyy-MM-dd}"; if (sig == _scrollSignature) return; + var cal = State.Culture.Calendar; + var today = DateTime.Today; + var selectedYear = cal.GetYear(State.SelectedDate); + var selectedMonth = cal.GetMonth(State.SelectedDate); + var todayYear = cal.GetYear(today); + var todayMonth = cal.GetMonth(today); + if (selectedYear != todayYear || selectedMonth != todayMonth) + { + _scrollSignature = sig; + return; + } + if (await BitFcTimelineScrollInterop.TryScrollToTargetAsync(JS, _scrollContainerId)) _scrollSignature = sig; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs` around lines 115 - 121, The OnAfterRenderAsync method calls BitFcTimelineScrollInterop.TryScrollToTargetAsync on every render even when the selected month is not the current month, resulting in unnecessary JavaScript interop calls since there is no "today" target to scroll to in those cases. Add a guard condition before calling BitFcTimelineScrollInterop.TryScrollToTargetAsync that checks whether State.SelectedDate (year and month) matches DateTime.Today (year and month), so the interop only executes when the selected month is the current month. Keep the existing _scrollSignature caching logic to prevent duplicate calls within the same month.
🧹 Nitpick comments (4)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cs (1)
3-10: ⚡ Quick winAdd XML documentation for consistency.
BitFullCalendarView lacks documentation while BitFullCalendarEventLayout and BitFullCalendarMode have comprehensive XML doc comments. Adding documentation would improve consistency across the public enum API and help developers understand which views are supported in different modes.
📝 Suggested documentation
+/// <summary> +/// Calendar view types available in Event mode. +/// Note: Timeline mode supports only Day, Week, and Month views. +/// </summary> public enum BitFullCalendarView { + /// <summary>Single day view with hourly time grid.</summary> Day, + /// <summary>Seven-day week view with hourly time grid.</summary> Week, + /// <summary>Month grid view showing all days and weeks of the month.</summary> Month, + /// <summary>Full year view with all months.</summary> Year, + /// <summary>Chronological agenda/list view groupable by date or color.</summary> Agenda }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cs` around lines 3 - 10, Add XML documentation comments to the BitFullCalendarView enum and all its members (Day, Week, Month, Year, Agenda) to match the documentation style and completeness of BitFullCalendarEventLayout and BitFullCalendarMode. Include a summary comment for the enum itself explaining its purpose as the supported calendar view types, and add brief documentation for each enum member describing what each view represents or when it should be used.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor (1)
43-45: ⚡ Quick winUse a semantic button for day selection.
The current clickable
<span>is not keyboard-friendly. Converting it to a<button>improves accessibility with minimal change.Proposed change
- <span class="bit-bfc-mini-calendar-day `@cls`" `@onclick`="() => SelectDate(cell.Date)"> - `@cell.Day` - </span> + <button type="button" + class="bit-bfc-mini-calendar-day `@cls`" + `@onclick`="() => SelectDate(cell.Date)" + aria-pressed="@(isSelected.ToString().ToLowerInvariant())"> + `@cell.Day` + </button>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor` around lines 43 - 45, Replace the non-semantic `<span>` element used for day selection in the BitFcMiniCalendar component with a `<button>` element to improve accessibility and keyboard navigation. The span element with the class "bit-bfc-mini-calendar-day" and the `@onclick` handler for SelectDate should be converted to a button while preserving the class binding, the onclick handler that calls SelectDate(cell.Date), and the displayed content `@cell.Day`.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor (1)
40-44: 🏗️ Heavy liftMake resize handles keyboard-accessible.
The resize affordances are pointer-only, so keyboard users cannot perform duration edits from this component. Please add a keyboard path (focusable handle + key bindings) with accessible semantics.
Also applies to: 68-72
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor` around lines 40 - 44, The resize handles in BitFcEventBlock are only accessible via pointer events, preventing keyboard users from resizing events. Make the resize handles keyboard-accessible by adding tabindex="0" to make them focusable, adding keyboard event handlers (like `@onkeydown`) alongside the existing `@onpointerdown` handlers to respond to arrow keys or Enter, and including appropriate ARIA attributes such as role="button" and aria-label to describe the handle's purpose. Apply these changes to both the top resize handle (with _topHandleId) and the bottom resize handle referenced in the "Also applies to" comment at lines 68-72.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor (1)
80-86: ⚡ Quick winMake timeline slot cells keyboard-operable.
These clickable
<div>slots currently require a pointer. Add focusability + keyboard activation to support keyboard users for slot-based add interactions.Also applies to: 107-113
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor` around lines 80 - 86, The `<div>` element with class "bit-bfc-tl-cell" is only operable via mouse click. To make it keyboard-accessible, add the tabindex="0" attribute to the div to make it focusable, then add an `@onkeydown` event handler that detects Enter or Space key presses and calls the same OnSlotClickAsync(rowKey, day) method that the `@onclick` handler uses. Apply the same changes to all similar timeline slot cell elements throughout the component (also at lines 107-113).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs`:
- Around line 6-7: The BitFcCalendarToast component stores
CancellationTokenSource objects in the _removalTokens list but never removes
them after they are no longer needed, only cleaning them up at component
disposal. To prevent unbounded list growth on long-lived pages, remove each
CancellationTokenSource from the _removalTokens list after its associated toast
timer completes or the toast is manually dismissed. Locate where new
CancellationTokenSource instances are added to _removalTokens around line 16 and
the disposal logic at line 39, then add cleanup logic that removes the token
from the list immediately after the timeout or dismissal occurs rather than
waiting for component disposal.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Line 3: Remove the .scss file extension from the import statement on line 3
where "functions.scss" is being imported, changing it to just "functions" to
comply with the scss/load-partial-extension rule. Additionally, locate the
keyframe definitions around lines 200 and 1106 in the BitFullCalendar.scss file
and rename them to follow the keyframes-name-pattern convention, which typically
requires lowercase names with hyphens rather than camelCase or other formats.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 104-141: The onPointerMove callback and endResize function
currently process events from any pointer instead of just the pointer that
initiated the resize operation. Add a check in the onPointerMove function to
verify that the incoming event's pointerId matches the activePointerId before
updating latestY. Similarly, in the endResize function, verify that the
triggering pointer's pointerId matches activePointerId before executing the
resize end logic. This ensures that multi-pointer input on touch or pen devices
only responds to movement and events from the pointer that started the resize
operation. Apply the same gate logic to the second occurrence of these event
handlers mentioned in the comment (lines 179-215).
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs`:
- Around line 71-74: The OnFocusOut method unconditionally closes the panel by
setting _isOpen to false, which causes it to close prematurely when users
interact with child controls. Instead of always closing, modify the OnFocusOut
method to check whether the focus is moving to a child element within the picker
component or genuinely leaving it entirely. You can inspect the relatedTarget
property from the FocusEventArgs to determine if focus is moving to an internal
child element (in which case keep the picker open) or if it's moving outside the
component (in which case close it). Alternatively, implement a small delay
before closing to allow child click handlers to execute, then check if focus has
returned to the picker before proceeding with the close operation.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor`:
- Around line 3-8: The BitFcDraggableEvent component's interactive div element
is currently not keyboard-accessible. To fix this, add keyboard event handling
to the div by adding an `@onkeydown` event handler that triggers the same OnClick
behavior when the Enter or Space key is pressed, and add a tabindex="0"
attribute to make the div focusable for keyboard users. This ensures that
keyboard users can interact with the draggable event the same way mouse users
can through the click handler.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Around line 54-63: The Agenda Group By options use non-semantic div elements
with `@onclick` handlers which are not keyboard-accessible or focusable. Replace
both div elements (the one with
SetAgendaModeGroupBy(BitFullCalendarAgendaGroupBy.Date) and the one with
SetAgendaModeGroupBy(BitFullCalendarAgendaGroupBy.Color)) with button elements
instead. Keep all the same class bindings, style bindings, and click handlers
intact, but change the element type from div to button to make them properly
focusable and keyboard-operable.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cs`:
- Around line 14-43: The Defaults property in the BitFullCalendarColorOption
class exposes a list of mutable objects that can be modified by consumers,
causing global side effects across all calendar instances. Make the
BitFullCalendarColorOption class immutable by converting it to a record type or
by changing the Id, Title, and Value properties to use init-only accessors
instead of set accessors. This ensures that the default color instances returned
from the Defaults property cannot be mutated after initialization.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`:
- Around line 20-29: The snapshot of options in the BitFullCalendarColorScheme
constructor is shallow, copying only list references not the individual
BitFullCalendarColorOption objects themselves. This means if any
BitFullCalendarColorOption (especially its Id property) is mutated after
construction, the _byId dictionary will become out of sync with the Options
list. To fix this, perform a deep copy of each BitFullCalendarColorOption object
when populating the Options collection, and build the _byId dictionary from this
deep-copied Options collection to ensure the lookup and options list remain
consistent even if the original objects are mutated later.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: The BitFullCalendarEvent model allows invalid event ranges
where EndDate could be less than StartDate, resulting in a negative duration
calculation at line 27 that propagates to the HandleDrop method in
BitFullCalendarState and causes invalid state updates. Add validation in the
BitFullCalendarEvent class (either in property setters for StartDate and EndDate
or in a constructor) to enforce the invariant that EndDate must be greater than
or equal to StartDate, rejecting any attempt to create or update an event with
an inverted date range at the model boundary before the invalid data reaches the
drag/drop logic.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 510-515: The Where clause filtering events in the day range check
is inconsistent with how GroupEventsByDayRange handles exclusive midnight
boundaries. Currently using ev.EndDate.Date treats midnight as inclusive,
causing events ending at 00:00 to appear on the next day. Modify the EndDate
logic in this Where clause (around the line with ev.EndDate.Date) to match the
exclusive-midnight handling already implemented in GroupEventsByDayRange at line
375, ensuring events ending at midnight do not appear as carry-over in
subsequent month cells.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 178-186: The SyncEvents method short-circuits when EventsMatch
returns true on lines 180-181 without calling ApplyFilters on line 184, causing
filtered events to become stale when individual event objects are mutated
in-place (such as Color or attendees changes). Remove the early return condition
or restructure the method to ensure ApplyFilters and NotifyStateChanged are
always executed, even when the event list structure matches. This same issue
also exists in the other similar code block around lines 216-227.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor`:
- Line 47: The search input element in BitFcAgendaEvents.razor lacks an
accessible label for screen readers, and the event rows referenced at lines
62-63 appear to be clickable divs rather than semantic interactive elements. Add
an associated label element (using for attribute) or aria-label to the search
input to describe its purpose, and convert the event row divs to button elements
or add proper ARIA role, tabindex, and keyboard event handlers to make them
accessible to keyboard and screen reader users.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor`:
- Around line 34-38: The div elements used for hourly time slots in
BitFcCalendarDayView.razor (such as the div with class "bit-bfc-hour-row
bit-bfc-droppable" and `@onclick` handler "OnHourClickAsync") lack keyboard
accessibility, preventing keyboard-only users from creating events. Convert
these div elements to semantic button elements or add appropriate ARIA
attributes (role="button", tabindex, and `@onkeydown` handlers) to enable keyboard
interaction. Apply this fix to all similar time-slot divs including those around
the mentioned lines, ensuring both mouse clicks and keyboard events (Enter/Space
keys) trigger the OnHourClickAsync method.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor`:
- Around line 35-37: The current filtering logic in the Where clause for
dayEvents uses date equality checks (e.StartDate.Date == d.Date ||
e.EndDate.Date == d.Date) which fails to correctly identify overlapping events,
particularly for events spanning multiple days or with exclusive end times.
Replace this equality-based filtering with proper interval overlap logic that
checks if the event overlaps with the current day using the condition:
event.StartDate is before the day's end AND event.EndDate is after the day's
start. This ensures all events that have any overlap with the day column are
included in dayEvents for the GroupEvents operation.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor`:
- Around line 19-22: Add a `@key` directive to the BitFcDayCell component in the
foreach loop that iterates over cells to prevent Blazor from reusing component
instances by position when the month data changes. Use a unique identifier from
the cell object (such as the cell's date or a unique ID property) as the key
value to ensure each day cell maintains its own state and prevents stale UI
state like open dialogs from appearing in the wrong date cell.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor`:
- Around line 8-12: The BitFcDayCell component's interactive div element is
currently only accessible via mouse clicks. To make it keyboard-accessible, add
tabindex="0" and role="button" attributes to the div element containing the
bit-bfc-month-cell class, then add an `@onkeydown` event handler that calls a new
OnCellKeyDown method. In the BitFcDayCell.razor.cs code-behind file, implement
the OnCellKeyDown handler that checks if the pressed key is Enter or Space, and
if so, awaits the OnCellClick() method to perform the same action as the click
handler.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor`:
- Around line 108-121: The div elements with classes bit-bfc-tl-cell and
bit-bfc-tl-cell-half are currently non-focusable and only respond to mouse
events (onclick, ondrop, ondragenter), preventing keyboard-only users from
interacting with them. Make these elements keyboard-accessible by either
converting them to button elements with appropriate aria-labels, or keeping them
as divs but adding tabindex="0" to make them focusable and adding keyboard event
handlers (such as `@onkeydown`) that trigger the same OnSlotClickAsync and event
handler methods when Enter or Space keys are pressed.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 31-38: The code is performing an expensive linear search through
all events for every cell in the year view, creating an O(cells × events)
performance bottleneck. Before the foreach loop that iterates over cells,
pre-compute a dictionary or lookup structure that maps dates to their
corresponding events from the allEvents collection. Then inside the foreach loop
in BitFcCalendarYearView.razor, replace the Where query with a simple dictionary
lookup using cell.Date.Date as the key to retrieve the dayEvents, eliminating
the per-cell scanning of all events.
- Around line 40-42: The year-day cell container (the div with class
bit-bfc-year-day) is using a clickable div element which is not
keyboard-accessible by default. To fix this in the BitFcCalendarYearView
component, replace the div with a button element (or add keyboard event handlers
like `@onkeydown` for Enter/Space keys along with tabindex="0" and appropriate
ARIA attributes if a button is not suitable). This will ensure that users can
open the ShowEventsForDay event list using keyboard navigation, making the
component fully accessible.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The import statement for BitFullCalendar includes the `.scss` file
extension, which violates the stylelint scss/load-partial-extension rule. Remove
the `.scss` extension from the import path in the statement `@import
"../Components/FullCalendar/BitFullCalendar.scss";` so that it imports the
partial without the extension, allowing Stylelint to properly validate the
import and preventing pipeline check failures.
---
Minor comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor`:
- Around line 4-7: The `@ondrop` event binding in the BitFcDroppableArea component
is missing the preventDefault directive that is already applied to `@ondragover`.
Add the :preventDefault="true" modifier to the `@ondrop` binding (similar to how
it is applied to `@ondragover`) to ensure the browser's default behavior is
prevented when items are dropped on the droppable area, avoiding accidental
navigation or unwanted content handling from external drops.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor`:
- Around line 13-14: Add an explicit type="button" attribute to the button
element with class "bit-bfc-mode-tab" to prevent it from defaulting to type
submit and causing accidental form submissions when the calendar component is
placed within a form. This ensures the button only triggers the onclick handler
without submitting any parent form.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cs`:
- Around line 16-17: The StartOfDayHour property in BitFullCalendarOptions class
lacks validation for the documented 0-16 range constraint, allowing any integer
value to be set. This causes runtime issues when the unconstrained value is
applied in BitFullCalendar.razor.cs. Add validation logic to the StartOfDayHour
property setter to enforce the 0-16 range by either clamping the value using
Math.Clamp or throwing an ArgumentException if an out-of-range value is
provided, ensuring the property contract matches its documentation.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 83-87: The StartOfWeek method currently falls back to
DayOfWeek.Sunday when the culture parameter is null, instead of using the
current UI culture. Modify the startDay assignment in the StartOfWeek method to
use CultureInfo.CurrentUICulture.DateTimeFormat.FirstDayOfWeek as the fallback
instead of DayOfWeek.Sunday. This will make the method consistent with other
culture-aware methods and properly respect regional week start conventions when
no culture is explicitly provided.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs`:
- Around line 12-23: The Timer in the BitFcCalendarTimeline component is
configured with an initial due time of one minute, which causes the first
refresh to occur one minute after initialization rather than at the next minute
boundary. This misalignment can leave the "current time" marker behind by up to
60 seconds. Calculate the time remaining until the next minute boundary by
finding the current time's seconds and milliseconds, then subtracting from one
minute, and use this calculated TimeSpan as the dueTime parameter in the Timer
constructor instead of TimeSpan.FromMinutes(1), keeping TimeSpan.FromMinutes(1)
as the period for subsequent ticks. This ensures UpdatePosition is called at
clock minute transitions rather than arbitrary intervals.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Around line 115-121: The OnAfterRenderAsync method calls
BitFcTimelineScrollInterop.TryScrollToTargetAsync on every render even when the
selected month is not the current month, resulting in unnecessary JavaScript
interop calls since there is no "today" target to scroll to in those cases. Add
a guard condition before calling
BitFcTimelineScrollInterop.TryScrollToTargetAsync that checks whether
State.SelectedDate (year and month) matches DateTime.Today (year and month), so
the interop only executes when the selected month is the current month. Keep the
existing _scrollSignature caching logic to prevent duplicate calls within the
same month.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cs`:
- Around line 3-10: Add XML documentation comments to the BitFullCalendarView
enum and all its members (Day, Week, Month, Year, Agenda) to match the
documentation style and completeness of BitFullCalendarEventLayout and
BitFullCalendarMode. Include a summary comment for the enum itself explaining
its purpose as the supported calendar view types, and add brief documentation
for each enum member describing what each view represents or when it should be
used.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor`:
- Around line 40-44: The resize handles in BitFcEventBlock are only accessible
via pointer events, preventing keyboard users from resizing events. Make the
resize handles keyboard-accessible by adding tabindex="0" to make them
focusable, adding keyboard event handlers (like `@onkeydown`) alongside the
existing `@onpointerdown` handlers to respond to arrow keys or Enter, and
including appropriate ARIA attributes such as role="button" and aria-label to
describe the handle's purpose. Apply these changes to both the top resize handle
(with _topHandleId) and the bottom resize handle referenced in the "Also applies
to" comment at lines 68-72.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor`:
- Around line 43-45: Replace the non-semantic `<span>` element used for day
selection in the BitFcMiniCalendar component with a `<button>` element to
improve accessibility and keyboard navigation. The span element with the class
"bit-bfc-mini-calendar-day" and the `@onclick` handler for SelectDate should be
converted to a button while preserving the class binding, the onclick handler
that calls SelectDate(cell.Date), and the displayed content `@cell.Day`.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor`:
- Around line 80-86: The `<div>` element with class "bit-bfc-tl-cell" is only
operable via mouse click. To make it keyboard-accessible, add the tabindex="0"
attribute to the div to make it focusable, then add an `@onkeydown` event handler
that detects Enter or Space key presses and calls the same
OnSlotClickAsync(rowKey, day) method that the `@onclick` handler uses. Apply the
same changes to all similar timeline slot cell elements throughout the component
(also at lines 107-113).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 41c6cbda-5cbb-4b9d-844e-f448795bf9ba
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 16
🧹 Nitpick comments (3)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cs (1)
15-16: ⚡ Quick winAvoid redundant drag-over state writes.
ondragoverfires continuously; setting_isOver = trueeach time can cause unnecessary re-renders.Suggested fix
- private void OnDragOver() => _isOver = true; - private void OnDragLeave() => _isOver = false; + private void OnDragOver() + { + if (_isOver) return; + _isOver = true; + } + + private void OnDragLeave() + { + if (_isOver is false) return; + _isOver = false; + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cs` around lines 15 - 16, The OnDragOver method continuously sets _isOver to true every time the ondragover event fires, causing unnecessary re-renders even when the value is already true. Add a guard condition in the OnDragOver method to check if _isOver is already true before assigning the value, so that a re-render is only triggered when the state actually transitions from false to true.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs (1)
68-82: ⚡ Quick win
CloneEventdocumentation overstates deep-copy behavior.
Datais copied by reference on Line 81, so this is not a full deep snapshot. Either deep-cloneData(if supported) or adjust the XML docs to avoid a misleading contract.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs` around lines 68 - 82, The CloneEvent method's XML documentation claims to create a deep snapshot, but the Data property on Line 81 is copied by reference rather than being deep-cloned, making the documentation misleading. Either implement deep-cloning logic for the Data property assignment in the CloneEvent method to match the documented behavior, or revise the XML documentation summary to accurately describe that this method creates a shallow copy of the event with reference-type properties like Data and Attendees being copied by reference rather than cloned.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor (1)
4-10: ⚡ Quick winExpose dropdown expanded state for accessibility.
The toggle button currently doesn’t announce menu state/ownership. Adding
aria-expanded/aria-controlsimproves keyboard and screen-reader flow.💡 Suggested fix
- <button class="bit-bfc-btn bit-bfc-btn-icon bit-bfc-btn-sm" `@onclick`="() => _open = !_open" title="`@Texts.SettingsButtonTitle`"> + <button type="button" + class="bit-bfc-btn bit-bfc-btn-icon bit-bfc-btn-sm" + `@onclick`="() => _open = !_open" + title="`@Texts.SettingsButtonTitle`" + aria-haspopup="menu" + aria-expanded="`@_open`" + aria-controls="bit-bfc-settings-menu"> @@ - <div class="bit-bfc-dropdown-menu"> + <div id="bit-bfc-settings-menu" class="bit-bfc-dropdown-menu" role="menu">🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor` around lines 4 - 10, The button element in BitFcSettings.razor that toggles the dropdown menu is missing accessibility attributes. Add the aria-expanded attribute to the button and bind it to the _open variable to expose the expanded state to screen readers, add an id attribute to the div with class bit-bfc-dropdown-menu to uniquely identify it, and add the aria-controls attribute to the button to establish the relationship between the button and the dropdown menu it controls by referencing the dropdown menu's id.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 96-143: The event listeners for pointermove, pointerup, and
pointercancel are being registered after awaiting OnResizeStart, which allows a
fast pointer release to occur before the listeners are attached, causing the
endResize handler to be missed and leaving event listeners active. Move the
three addEventListener calls (for pointermove with onPointerMove, pointerup with
endResize, and pointercancel with endResize) to execute before the await of
OnResizeStart so that any pointer events are properly captured. Apply this same
ordering fix to the initResizeHorizontal function as well.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor`:
- Around line 76-78: The three input fields for attendee information
(_newFirstName, _newLastName, and _newId) lack explicit labels or aria-label
attributes, making them inaccessible to screen readers. Add aria-label
attributes to each of these input elements that describe the field's purpose
using the corresponding localized text from the Texts resource
(FirstNamePlaceholder, LastNamePlaceholder, and IdOptionalPlaceholder). This
ensures screen reader users can understand what information each field expects
without relying solely on visual placeholders.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor`:
- Around line 14-18: The aria-label attributes on the navigation buttons (lines
14 and 18) in BitFcDateTimePicker.razor are hard-coded with English text,
preventing localization based on the selected culture. Add two new string
parameters named PreviousMonthAriaLabel and NextMonthAriaLabel to the
component's code-behind (BitFcDateTimePicker.razor.cs) with appropriate default
English values, then bind these parameters to the respective aria-label
attributes in the Razor markup by replacing the hard-coded strings with property
bindings.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor`:
- Around line 12-23: The event row in BitFcEventListDialog.razor is currently
only mouse-clickable and inaccessible to keyboard users. The div with class
"bit-bfc-agenda-item" needs to be made keyboard-operable by adding a tabindex
attribute to make it focusable, and adding a keyboard event handler (such as
`@onkeydown`) that triggers the SelectEvent method when the user presses Enter or
Space keys. This ensures both mouse and keyboard users can select events from
the dialog.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor`:
- Around line 8-20: The guard condition at the start of the BitFcModeTabs
component hides the entire mode tabs container when there are no resources,
which removes the Event mode switching UI entirely. Instead of conditionally
rendering the entire div based on resource count, you should keep the mode tabs
container always visible and conditionally filter or render only the
Timeline-specific mode from the _modes collection when resources are available.
This way the Event mode tab remains accessible for users to switch between modes
even when the resources list is empty.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cs`:
- Around line 11-12: The SetStartOfDayHour method is being called with an
unclamped parsed value, which bypasses min/max validation that only exists on
the input element. After successfully parsing the value into the variable val
using int.TryParse, clamp val to the appropriate valid range (e.g., 0-23 for
hours) before passing it to State.SetStartOfDayHour to ensure the state
invariant is enforced at the handler level regardless of input element
constraints.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor`:
- Around line 9-10: The button element in BitFcViewTabs.razor does not have an
explicit type attribute, which causes it to default to type="submit" when inside
a form, potentially triggering unwanted form submissions. Add the type="button"
attribute to the button element that has the class "bit-bfc-view-tab" and the
onclick handler that calls State.SetView(view) to ensure it functions as a
regular button rather than a submit button.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 201-210: The GetEventsForYear method in BitFullCalendarHelpers
treats EndDate.Date as inclusive in its overlap comparison, but this causes
inconsistency with the exclusive-end convention used elsewhere where midnight is
treated as the boundary. Fix the comparison logic in the where clause for
GetEventsForYear to treat EndDate as exclusive by changing the condition from
ev.EndDate.Date >= yearStart to ev.EndDate > yearStart. Apply this same
exclusive-end rule consistently across all other related date-overlap helper
methods mentioned in the comment (at lines 468-471, 578-588, 591-597, 599-609)
to ensure events ending at midnight do not incorrectly appear in the next
period.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor`:
- Around line 43-47: The clickable div element in the BitFcCalendarWeekView
component that handles the `@onclick`="() => OnHourClickAsync(d, hour)" event is
not keyboard accessible. To fix this, add a role="button" attribute to indicate
this element is interactive, add tabindex="0" to make it focusable for keyboard
navigation, and add an `@onkeydown` event handler that triggers OnHourClickAsync
when the Enter or Space keys are pressed to allow keyboard-only users to create
events from the week grid view.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor`:
- Around line 43-45: Replace the span element with role="button" in the
BitFcMiniCalendar component with a native button element for proper keyboard
semantics. Change the span that contains the SelectDate click handler and
OnDayKeyDown keyboard handler to a button element. Remove the role="button",
tabindex="0" attributes and the `@onkeydown` handler since native buttons
automatically handle keyboard interactions like Space and Enter. Keep the class
attribute with bit-bfc-mini-calendar-day and the `@onclick` handler bound to
SelectDate(cell.Date).
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor`:
- Around line 47-49: The div element with class "bit-bfc-month-more" in
BitFcDayCell.razor is not keyboard-accessible because it only responds to click
events. Add an `@onkeydown` event handler to this div that calls a new
OnMoreKeyDown method, which should check if the pressed key is Enter, Space, or
Spacebar and set _showEventList to true when triggered. Additionally, add
tabindex="0" and role="button" attributes to the div to make it focusable and
semantically correct for keyboard users.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor`:
- Around line 47-50: The time display in the MonthView badge incorrectly shows
Event.StartDate for all positions, including when Position is "last". For
multi-day events, the last segment should display Event.EndDate instead of
Event.StartDate to correctly represent the trailing day's time. Modify the
condition that checks showTime to conditionally use either Event.EndDate when
Position equals "last" or Event.StartDate otherwise, passing the appropriate
date value to the BitFullCalendarHelpers.FormatTime method.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 16-19: The code filters out resources with empty IDs on line 17
when grouping events using `Where(id => !string.IsNullOrEmpty(id))`, but the
same filtering is not applied when rendering rows and drop targets around line
55 where raw `resource.Id` values are used directly. This inconsistency causes
resources with empty IDs to render but fail to retain dropped or created events
properly since the BitFullCalendarEvent.Resource contract treats empty IDs as
unassigned. Apply the same empty ID filtering logic when iterating through
resources for row and drop target rendering to ensure consistency between the
grouping logic and the rendering logic.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`:
- Around line 78-83: In the `OnResizeStart` method in
BitFcTimelineEventBlock.razor.cs, instead of storing a direct reference to the
Event object in `_resizeBaseEvent`, capture an immutable copy or deep clone of
the Event object to preserve its pre-resize state. This ensures that when
`State.UpdateEvent(updated)` is called later and the original Event object is
mutated, the `_resizeBaseEvent` will still contain the original unmodified state
needed for building the accurate `OldEvent` property. Apply the same fix to the
corresponding resize end handler method that also uses `_resizeBaseEvent` to
construct `OldEvent`.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Around line 119-124: The year and month comparison in the conditional check
within the method is using Gregorian calendar properties directly
(State.SelectedDate.Year and State.SelectedDate.Month), but the rendered
calendar may use a different calendar system based on the active culture.
Replace the direct Year and Month property comparisons with culture-aware date
comparison that respects the calendar system being used for rendering, ensuring
that the scroll-to-today functionality works correctly for non-Gregorian
calendar cultures.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 44-46: The clickable div element with `@onclick` handler for
GoToMonth month navigation is not keyboard-accessible. Replace the div element
with a button element to make it keyboard-operable by default, which will allow
users to navigate using Tab and Enter keys. The button should maintain the same
click handler `@onclick`="() => GoToMonth(monthDate)" and display the monthName
content.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cs`:
- Around line 15-16: The OnDragOver method continuously sets _isOver to true
every time the ondragover event fires, causing unnecessary re-renders even when
the value is already true. Add a guard condition in the OnDragOver method to
check if _isOver is already true before assigning the value, so that a re-render
is only triggered when the state actually transitions from false to true.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Around line 4-10: The button element in BitFcSettings.razor that toggles the
dropdown menu is missing accessibility attributes. Add the aria-expanded
attribute to the button and bind it to the _open variable to expose the expanded
state to screen readers, add an id attribute to the div with class
bit-bfc-dropdown-menu to uniquely identify it, and add the aria-controls
attribute to the button to establish the relationship between the button and the
dropdown menu it controls by referencing the dropdown menu's id.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cs`:
- Around line 68-82: The CloneEvent method's XML documentation claims to create
a deep snapshot, but the Data property on Line 81 is copied by reference rather
than being deep-cloned, making the documentation misleading. Either implement
deep-cloning logic for the Data property assignment in the CloneEvent method to
match the documented behavior, or revise the XML documentation summary to
accurately describe that this method creates a shallow copy of the event with
reference-type properties like Data and Attendees being copied by reference
rather than cloned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 336fa9f8-c43a-4be3-81b7-7b5b95625510
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 10
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cs (1)
11-12:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winClamp parsed start-hour before updating state.
Line 11–12 still forwards raw parsed values; enforce the 0–16 bound in the handler so state cannot drift out of range.
Suggested fix
- if (int.TryParse(e.Value?.ToString(), out int val)) - State.SetStartOfDayHour(val); + if (int.TryParse(e.Value?.ToString(), out int val)) + State.SetStartOfDayHour(Math.Clamp(val, 0, 16));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cs` around lines 11 - 12, The handler for the start-hour input does not validate that the parsed value falls within the valid 0-16 range before forwarding it to State.SetStartOfDayHour. After successfully parsing the value with int.TryParse, clamp the parsed integer val to ensure it stays within bounds (minimum 0, maximum 16) before passing it to the SetStartOfDayHour method call.
🧹 Nitpick comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cs (1)
199-210: 💤 Low valueOptions changes not detected when properties are modified in place.
ReferenceEqualscheck means if the consumer modifies properties on the existingOptionsinstance (e.g.,Options.Use24HourFormat = false) without assigning a new object, those changes won't be applied. Consider adding a version/hash check or documenting that a newOptionsinstance must be assigned for changes to take effect.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cs` around lines 199 - 210, The ApplyOptions method uses ReferenceEquals to compare Options with _appliedOptions, which only detects changes when a completely new Options object is assigned, not when individual properties are modified on the existing instance. To fix this, implement a version tracking mechanism or hash-based comparison that can detect property changes within the same Options object. You could add a version property to the Options class that increments when properties change, or compute a hash of the Options properties and compare that instead of just the reference. Store the computed hash or version in _appliedOptions alongside or in place of the Options reference, then check if the current hash/version differs from the stored one in the ApplyOptions method.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cs (1)
100-107: Add State.IsDragging guard to OnDrop for consistency.While
HandleResourceDropAsyncproperly guards against null dragged events, theOnDropmethod should match the defensive pattern used in allOnDragEnterimplementations by checkingif (!State.IsDragging) return;early. This prevents unnecessary notifier calls and ensures consistent drag-state gating across event handlers.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cs` around lines 100 - 107, Add a defensive guard clause at the beginning of the OnDrop method to check State.IsDragging, returning early if it is false. This ensures consistency with the defensive pattern used in OnDragEnter implementations and prevents unnecessary notifier calls when dragging is not actually in progress.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs`:
- Around line 21-32: The OnParametersSet method currently only reinitializes
_visibleMonthAnchor when the Value parameter changes, but does not account for
culture or calendar changes. To fix this, track the current culture or calendar
system similar to how _lastSyncedDate is tracked, and modify the OnParametersSet
method to reinitialize _visibleMonthAnchor not only when Value changes but also
when the culture or calendar system changes. This ensures that month anchoring
remains correct when switching between different calendar systems while
maintaining the same date value.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Around line 4-9: The button element in BitFcSettings component uses a
hardcoded ID "bit-bfc-settings-menu" in the aria-controls attribute, and the
menu div also uses the same hardcoded id. When multiple calendar instances exist
on the same page, this creates duplicate IDs which breaks accessibility by
causing assistive technology to point to the wrong menu. Generate a unique
identifier for each BitFcSettings component instance (typically using Guid in
the code-behind section) and replace both the aria-controls attribute on the
button and the id attribute on the menu div to use this generated unique ID
instead of the hardcoded string.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor`:
- Line 3: The button element in BitFcTodayButton.razor with the onclick handler
State.GoToToday and classes bit-bfc-btn bit-bfc-btn-sm is missing an explicit
type attribute. Add type="button" to the button element to ensure it never
accidentally submits a parent form when clicked.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cs`:
- Around line 15-17: The Initials property getter assumes FirstName and LastName
are non-null strings, which can cause null reference exceptions when these
properties are externally assigned null values. Add null checks before accessing
the Length property on FirstName and LastName in the Initials getter. Use the
null-coalescing operator or conditional checks to ensure that null values are
safely handled, treating them as empty strings when determining the initials.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 213-218: The FormatTime method uses CultureInfo.InvariantCulture
for date formatting, which prevents localized time strings (particularly AM/PM
indicators) from respecting the user's UI culture settings. Replace
CultureInfo.InvariantCulture with CultureInfo.CurrentUICulture in both toString
calls within the FormatTime method to ensure time formatting respects the user's
locale. Additionally, apply the same fix to the similar code at lines 248-254
that handles the same formatting issue.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 48-52: The SetCulture method updates the Culture property and
calls UpdateUI() but fails to notify listeners about date-range changes. When
culture changes, the date range representation may change due to locale-specific
formatting, so consumers listening for range changes miss required updates. Add
a call to NotifyDateRangeChanged() after the UpdateUI() call in the SetCulture
method to ensure all listeners are properly notified of the date-range change.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs`:
- Line 3: The BitFcCalendarTimeline class has a Dispose() method defined on line
37 but does not implement the IDisposable interface on the class declaration on
line 3. Update the class declaration to implement IDisposable so that Blazor
will automatically call the Dispose() method when the component is destroyed,
ensuring the timer resource is properly cleaned up and doesn't leak.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cs`:
- Around line 66-76: The catch block in the resize initialization section of
BitFcEventBlock only catches JSException, but other exceptions like
JSDisconnectedException, InvalidOperationException, and
OperationCanceledException can occur during Blazor teardown and disconnect
scenarios. Update the catch block that surrounds the JS.InvokeVoidAsync calls
for "BitBlazorUI.FullCalendar.initResize" (in the OnAfterRenderAsync method) to
catch all these exception types together, aligning the exception handling
pattern with the equivalent implementation in BitFcTimelineEventBlock.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor`:
- Around line 40-47: The div element in the BitFcTimelineEventBlock component is
not keyboard-accessible because it lacks focus capability and keyboard event
handling. Make the event block keyboard-activatable by adding a tabindex
attribute to make the div focusable, adding an onkeydown event binding to the
div element, and implementing the corresponding OnKeyDown method that checks if
the pressed key is Enter, Space, or Spacebar before invoking the same OnClick
handler used for mouse clicks.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor`:
- Around line 80-85: The timeline month slot cells in the BitFcTimelineMonthView
component (the div elements with classes bit-bfc-tl-cell bit-bfc-tl-cell-day at
lines 80-85 and 107-112) currently only respond to mouse interactions through
onclick handlers. To make these cells keyboard-operable, add keyboard event
handlers (`@onkeydown` or similar) to the div elements that trigger the same
OnSlotClickAsync method when the Enter or Space keys are pressed. This will
enable users to create events using keyboard navigation without requiring a
mouse, improving accessibility.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cs`:
- Around line 11-12: The handler for the start-hour input does not validate that
the parsed value falls within the valid 0-16 range before forwarding it to
State.SetStartOfDayHour. After successfully parsing the value with int.TryParse,
clamp the parsed integer val to ensure it stays within bounds (minimum 0,
maximum 16) before passing it to the SetStartOfDayHour method call.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cs`:
- Around line 199-210: The ApplyOptions method uses ReferenceEquals to compare
Options with _appliedOptions, which only detects changes when a completely new
Options object is assigned, not when individual properties are modified on the
existing instance. To fix this, implement a version tracking mechanism or
hash-based comparison that can detect property changes within the same Options
object. You could add a version property to the Options class that increments
when properties change, or compute a hash of the Options properties and compare
that instead of just the reference. Store the computed hash or version in
_appliedOptions alongside or in place of the Options reference, then check if
the current hash/version differs from the stored one in the ApplyOptions method.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cs`:
- Around line 100-107: Add a defensive guard clause at the beginning of the
OnDrop method to check State.IsDragging, returning early if it is false. This
ensures consistency with the defensive pattern used in OnDragEnter
implementations and prevents unnecessary notifier calls when dragging is not
actually in progress.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 5c0cef1e-f38f-4cd6-8f87-040157a9122a
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (6)
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
7-7:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winRemove the
.scssextension to satisfy Stylelint.The static analysis tool flags this import as violating
scss/load-partial-extension. Other imports in this file omit the extension for consistency.Suggested fix
-@import "../Components/FullCalendar/BitFullCalendar.scss"; +@import "../Components/FullCalendar/BitFullCalendar";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss` at line 7, The import statement in the extra-components.scss file includes the .scss file extension on the BitFullCalendar.scss import, which violates the scss/load-partial-extension Stylelint rule. Remove the .scss extension from the import path so it matches the pattern used by other imports in the file, changing the import to reference just the module name without the extension.Source: Linters/SAST tools
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor (1)
108-126:⚠️ Potential issue | 🟠 Major | ⚡ Quick winTimeline week slot cells lack keyboard accessibility.
Unlike
BitFcTimelineMonthView.razorwhich was updated withrole="button",tabindex="0", and@onkeydownhandlers, these week view cells remain mouse-only. Keyboard users cannot create events in this view.Add the same keyboard support pattern used in the month view:
Suggested fix for outer cell
<div class="bit-bfc-tl-cell @(isPreviewHour ? "bit-bfc-tl-drop-preview" : "")" style="left:@(leftPx)px;width:@(hourWidth)px;" + role="button" + tabindex="0" `@ondragenter`="() => OnDragEnter(rowKey, day, hour, 0)" `@ondragover`:preventDefault="true" `@ondrop`="() => OnDrop(rowKey, day, hour, 0)" - `@onclick`="() => OnSlotClickAsync(rowKey, day, hour, 0)"> + `@onclick`="() => OnSlotClickAsync(rowKey, day, hour, 0)" + `@onkeydown`="e => OnSlotKeyDownAsync(e, rowKey, day, hour, 0)">Also applies to lines 151-165 in UnassignedRowContent.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor` around lines 108 - 126, The timeline week view cells in BitFcTimelineWeekView.razor are not keyboard accessible like they are in BitFcTimelineMonthView.razor. Add keyboard support to both the outer cell div with class "bit-bfc-tl-cell" and the inner cell-half div with class "bit-bfc-tl-cell-half" by adding three attributes to each: role="button" to provide semantic meaning, tabindex="0" to make them focusable, and `@onkeydown` event handler that calls the same OnSlotClickAsync method as the `@onclick` handler (with the same rowKey, day, hour, and minute parameters). Apply the same fix to both occurrences in the week view at the specified line ranges and also to the same cells in the UnassignedRowContent section at lines 151-165.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs (1)
3-3:⚠️ Potential issue | 🟠 Major | ⚡ Quick winImplement
IDisposableon the component type.Line 37 defines
Dispose(), but Line 3 does not implementIDisposable; Blazor lifecycle disposal won’t reliably invoke this cleanup, so the timer can outlive the component.Suggested fix
-public partial class BitFcCalendarTimeline +public partial class BitFcCalendarTimeline : IDisposableAlso applies to: 37-37
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs` at line 3, The BitFcCalendarTimeline class has a Dispose() method defined but does not implement the IDisposable interface. This prevents Blazor from reliably calling the cleanup method, allowing the timer to outlive the component. Add the IDisposable interface implementation to the BitFcCalendarTimeline class declaration so that the existing Dispose() method is properly recognized and invoked during component lifecycle cleanup.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss (1)
3-3:⚠️ Potential issue | 🟡 Minor | 💤 Low valueRemove
.scssextension from import path.The stylelint rule
scss/load-partial-extensionflags this. SCSS partials should be imported without the extension.-@import "../../../Bit.BlazorUI/Styles/functions.scss"; +@import "../../../Bit.BlazorUI/Styles/functions";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss` at line 3, The import statement for the functions.scss partial includes the file extension, which violates the scss/load-partial-extension stylelint rule. Remove the .scss extension from the import path in the `@import` statement that references ../../../Bit.BlazorUI/Styles/functions.scss, so the partial is imported without its extension as per SCSS conventions.Source: Linters/SAST tools
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs (1)
8-9:⚠️ Potential issue | 🟠 Major | ⚡ Quick winEnforce
EndDate >= StartDatein the model.Line 27 can return a negative duration today, and that value is consumed downstream when events are moved/resized. Reject inverted ranges at this boundary so invalid events never enter state logic.
Suggested fix
public class BitFullCalendarEvent { + private DateTime _startDate; + private DateTime _endDate; + public string Id { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; - public DateTime StartDate { get; set; } - public DateTime EndDate { get; set; } + public DateTime StartDate + { + get => _startDate; + set + { + _startDate = value; + EnsureValidRange(); + } + } + public DateTime EndDate + { + get => _endDate; + set + { + _endDate = value; + EnsureValidRange(); + } + } @@ public TimeSpan Duration => EndDate - StartDate; @@ public object? Data { get; set; } + + private void EnsureValidRange() + { + if (_startDate != default && _endDate != default && _endDate < _startDate) + throw new ArgumentOutOfRangeException(nameof(EndDate), "EndDate must be greater than or equal to StartDate."); + } }Also applies to: 27-27
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 8 - 9, The BitFullCalendarEvent model's StartDate and EndDate properties do not validate that EndDate is greater than or equal to StartDate, which allows negative durations to be calculated and propagated to downstream logic. Add validation logic to the EndDate property setter to ensure it is never set to a value less than the current StartDate value, and similarly validate the StartDate property setter to ensure it is never set to a value greater than the current EndDate value. This will prevent invalid inverted date ranges from being created at the model boundary and protect the duration calculations and event manipulation logic downstream.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs (1)
181-186:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
SyncEventsstill skips filter recomputation for in-place mutations.Line 182 returns early when references match, so
_filteredEventscan stay stale after mutating event properties (for exampleColororAttendees) on shared instances.Suggested fix
public void SyncEvents(List<BitFullCalendarEvent> events) { if (EventsMatch(events)) - return; + { + ApplyFilters(); + return; + } _allEvents = [.. events]; ApplyFilters(); NotifyStateChanged(); }Also applies to: 217-227
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs` around lines 181 - 186, The SyncEvents method currently returns early when EventsMatch(events) is true, but this optimization causes _filteredEvents to become stale when individual event properties are mutated in-place (such as Color or Attendees changes on shared event instances). Remove the early return condition and the EventsMatch check so that ApplyFilters() and NotifyStateChanged() are always executed, ensuring that any in-place mutations to event properties trigger filter recomputation. Apply the same fix to the similar code block mentioned in the comment (lines 217-227) to ensure consistent behavior across all event synchronization paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor`:
- Line 4: The button element in BitFcSettings.razor that toggles the _open state
is missing an explicit type attribute, which causes it to default to
type="submit" and can unintentionally submit a parent form. Add type="button" to
the button element with the `@onclick`="() => _open = !_open" handler to prevent
form submission behavior and explicitly declare that this is a regular button
control.
- Around line 12-37: The three toggle setting rows use non-semantic `<div>`
elements with `@onclick` handlers instead of proper button controls, making them
inaccessible via keyboard and screen readers. Replace each `<div
class="bit-bfc-dropdown-item">` element (the ones containing SetBadgeVariant,
ToggleTimeFormat, and ToggleEventLayout handlers) with `<button type="button">`
elements, preserving the existing `@onclick` handlers and all internal content
including the span labels and toggle markup. This ensures keyboard navigation
and proper semantic accessibility.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cs`:
- Around line 97-104: The OnDrop method is calling HandleResourceDropAsync
unconditionally, but it should only do so when a drag operation is actually
active. Before calling the Notifier.HandleResourceDropAsync method in OnDrop,
add a guard condition to check if an active drag state exists (such as verifying
that _dragResourceId is not null before the reset). If no drag is active, the
method should return early without processing the drop logic, making it
consistent with the week view implementation.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor`:
- Around line 25-30: The condition checking `!hasResources` at line 25 prevents
the unassigned timeline row from rendering when resources are empty. Modify the
logic to show the empty state message only if both resources are empty AND there
are no unassigned rows to display. When resources are empty but
`HasUnassignedRow` is true or `UnassignedRowContent` exists, render the
unassigned timeline row instead of the no-resources message. Apply the same fix
to the related section at lines 60-72 to ensure consistent behavior throughout
the BitFcTimelineLayout component.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Around line 111-119: The OnDrop method in BitFcTimelineMonthView.razor.cs is
missing a drag-state precondition check at the start of the method. Add a guard
clause at the beginning of the OnDrop method that checks if drag mode is active
(validate that _dragResourceId and _dragDay are not null) and returns early if
drag is not active, matching the behavior implemented in the timeline week view.
This check should occur before clearing the drag state variables and calling
HandleResourceDropAsync.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Line 5: The Description attribute in the BitFullCalendarDemo.razor file
contains inconsistent casing that makes it appear unprofessional and awkward for
users. Update the Description property value to properly capitalize component
names: change "fullcalendar" to "FullCalendar" and "bit BlazorUI" to "Bit
BlazorUI". Consider also improving the overall phrasing to be more polished and
user-facing, such as emphasizing that this is a powerful calendar component
within the Bit BlazorUI library rather than just stating it is a component of
it.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Line 3: The import statement for the functions.scss partial includes the file
extension, which violates the scss/load-partial-extension stylelint rule. Remove
the .scss extension from the import path in the `@import` statement that
references ../../../Bit.BlazorUI/Styles/functions.scss, so the partial is
imported without its extension as per SCSS conventions.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: The BitFullCalendarEvent model's StartDate and EndDate
properties do not validate that EndDate is greater than or equal to StartDate,
which allows negative durations to be calculated and propagated to downstream
logic. Add validation logic to the EndDate property setter to ensure it is never
set to a value less than the current StartDate value, and similarly validate the
StartDate property setter to ensure it is never set to a value greater than the
current EndDate value. This will prevent invalid inverted date ranges from being
created at the model boundary and protect the duration calculations and event
manipulation logic downstream.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 181-186: The SyncEvents method currently returns early when
EventsMatch(events) is true, but this optimization causes _filteredEvents to
become stale when individual event properties are mutated in-place (such as
Color or Attendees changes on shared event instances). Remove the early return
condition and the EventsMatch check so that ApplyFilters() and
NotifyStateChanged() are always executed, ensuring that any in-place mutations
to event properties trigger filter recomputation. Apply the same fix to the
similar code block mentioned in the comment (lines 217-227) to ensure consistent
behavior across all event synchronization paths.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cs`:
- Line 3: The BitFcCalendarTimeline class has a Dispose() method defined but
does not implement the IDisposable interface. This prevents Blazor from reliably
calling the cleanup method, allowing the timer to outlive the component. Add the
IDisposable interface implementation to the BitFcCalendarTimeline class
declaration so that the existing Dispose() method is properly recognized and
invoked during component lifecycle cleanup.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor`:
- Around line 108-126: The timeline week view cells in
BitFcTimelineWeekView.razor are not keyboard accessible like they are in
BitFcTimelineMonthView.razor. Add keyboard support to both the outer cell div
with class "bit-bfc-tl-cell" and the inner cell-half div with class
"bit-bfc-tl-cell-half" by adding three attributes to each: role="button" to
provide semantic meaning, tabindex="0" to make them focusable, and `@onkeydown`
event handler that calls the same OnSlotClickAsync method as the `@onclick`
handler (with the same rowKey, day, hour, and minute parameters). Apply the same
fix to both occurrences in the week view at the specified line ranges and also
to the same cells in the UnassignedRowContent section at lines 151-165.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The import statement in the extra-components.scss file includes the
.scss file extension on the BitFullCalendar.scss import, which violates the
scss/load-partial-extension Stylelint rule. Remove the .scss extension from the
import path so it matches the pattern used by other imports in the file,
changing the import to reference just the module name without the extension.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: e07c6d12-2eca-4898-a0d1-6974feaee4e1
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarOptions.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (3)
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
7-7: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winRemove the
.scssextension from this import.Line 7 still violates
scss/load-partial-extension, which can block stylelint checks.Suggested fix
-@import "../Components/FullCalendar/BitFullCalendar.scss"; +@import "../Components/FullCalendar/BitFullCalendar";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss` at line 7, The import statement for BitFullCalendar violates the scss/load-partial-extension stylelint rule because it explicitly includes the .scss file extension. Remove the .scss extension from the import path in the `@import` statement so that it reads "../Components/FullCalendar/BitFullCalendar" instead of "../Components/FullCalendar/BitFullCalendar.scss". This will allow stylelint to pass the check while maintaining the correct import functionality.Source: Linters/SAST tools
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor (1)
16-19: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winNormalize blank resource IDs before using them as row interaction keys.
Line 17 excludes empty resource IDs from grouping, but Line 55 still uses raw
resource.Idfor slot/drop actions (Lines 67-70). This can route interactions through keys that are not part of the grouped resource contract.Suggested minimal normalization
- var resourceIds = resources.Select(r => r.Id).Where(id => !string.IsNullOrEmpty(id)).ToList(); + var resourceIds = resources.Select(r => r.Id).Where(id => !string.IsNullOrWhiteSpace(id)).ToList(); @@ - @{ var rowKey = resource.Id; var rowLabel = resource.Title; } + @{ var rowKey = string.IsNullOrWhiteSpace(resource.Id) ? _unassignedKey : resource.Id; var rowLabel = resource.Title; }Also applies to: 55-70
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor` around lines 16 - 19, The code on line 17 filters out empty or null resource IDs when building the resourceIds list for grouping, but the drop and slot action handlers around lines 55-70 use raw resource.Id values directly as interaction keys, which could include empty IDs. Apply the same normalization pattern used in line 17 (the Where clause that filters out empty IDs) to the resource IDs used as keys in the slot and drop action handlers so that only valid, non-empty resource IDs are used for row interactions and they match the grouped resource contract.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs (1)
28-30: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDetect calendar-system changes, not just culture name.
Line 28 compares only
Culture.Name. If callers reuse the same culture name with a different calendar configuration,_visibleMonthAnchorwon’t re-anchor correctly.💡 Minimal patch
- private CultureInfo? _lastSyncedCulture; + private string? _lastCultureKey; @@ - var cultureChanged = !string.Equals(_lastSyncedCulture?.Name, Culture.Name, StringComparison.Ordinal); + var cultureKey = $"{Culture.Name}|{Culture.DateTimeFormat.Calendar.GetType().FullName}"; + var cultureChanged = !string.Equals(_lastCultureKey, cultureKey, StringComparison.Ordinal); @@ - _lastSyncedCulture = Culture; + _lastCultureKey = cultureKey;As per coding guidelines, cross-file and configuration/state checks should validate actual values, and the active calendar type is part of this component’s date contract.
Also applies to: 38-39
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs` around lines 28 - 30, The cultureChanged variable in the BitFcDateTimePicker component currently only compares the Culture.Name property, but this misses cases where the same culture is reused with a different calendar system. Modify the cultureChanged assignment to also check if the calendar system has changed by comparing the Calendar property of _lastSyncedCulture and Culture (in addition to comparing their Name properties). This same pattern check also appears elsewhere in the file (around lines 38-39) and should be updated consistently to detect both culture name and calendar-system changes.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cs`:
- Around line 15-17: The InitialExtraction method in BitFullCalendarAttendee is
not trimming whitespace from FirstName and LastName before extracting initials,
which causes leading spaces in names to produce blank initials. Apply the Trim()
method to FirstName and LastName before checking their length and extracting the
first character to ensure whitespace-prefixed names generate correct initials.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Line 14: The SelectedColors property in BitFullCalendarState class is exposed
as a public mutable List that allows external callers to directly modify it,
bypassing the UpdateUI() notification mechanism and causing state
desynchronization. Change the SelectedColors property to expose only a read-only
collection (such as IReadOnlyList or ReadOnlyCollection) while keeping the
internal list private, ensuring all modifications to the selected colors go
through controlled methods that properly trigger UpdateUI() and maintain state
consistency.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor`:
- Line 45: The hardcoded id "bit-bfc-agenda-scroll" on the div element in the
BitFcAgendaEvents component will be duplicated across multiple calendar
instances on the same page, causing DOM id conflicts and incorrect scrolling
behavior. Generate or use a unique instance identifier (such as a GUID or
component parameter) and incorporate it into the id attribute so each calendar
instance has a distinct id. This will ensure id-based scrolling targets the
correct agenda container.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs`:
- Around line 107-119: The BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync
method is called with a hardcoded element ID string
"bit-bfc-day-timegrid-scroll", which causes issues when multiple calendar
instances render simultaneously as they reference the same target element. To
fix this, create a private unique identifier field per component instance
(following the GUID-backed pattern used in timeline views), replace the
hardcoded string "bit-bfc-day-timegrid-scroll" in the TryScrollToStartOfDayAsync
call with this unique field, and update the corresponding .razor markup to bind
the scroll container's id attribute to this same unique field value.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cs`:
- Around line 13-14: The _eventRows dictionary in
BitFcWeekViewMultiDayEventsRow.razor.cs currently uses ev.Id as a key, which
relies on a user-supplied ID string that can be duplicate or missing, causing
incorrect row placement for multi-day events. Change the key from the event's
string Id to a unique identifier that represents the event instance itself (such
as the event object reference or a tuple combining the event with date
information). Apply this change consistently across all locations where
_eventRows is populated or accessed, including the references at lines 41-42 and
56-57, to ensure row allocation is based on event instance identity rather than
potentially unreliable ID values.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cs`:
- Around line 28-30: The cultureChanged variable in the BitFcDateTimePicker
component currently only compares the Culture.Name property, but this misses
cases where the same culture is reused with a different calendar system. Modify
the cultureChanged assignment to also check if the calendar system has changed
by comparing the Calendar property of _lastSyncedCulture and Culture (in
addition to comparing their Name properties). This same pattern check also
appears elsewhere in the file (around lines 38-39) and should be updated
consistently to detect both culture name and calendar-system changes.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 16-19: The code on line 17 filters out empty or null resource IDs
when building the resourceIds list for grouping, but the drop and slot action
handlers around lines 55-70 use raw resource.Id values directly as interaction
keys, which could include empty IDs. Apply the same normalization pattern used
in line 17 (the Where clause that filters out empty IDs) to the resource IDs
used as keys in the slot and drop action handlers so that only valid, non-empty
resource IDs are used for row interactions and they match the grouped resource
contract.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The import statement for BitFullCalendar violates the
scss/load-partial-extension stylelint rule because it explicitly includes the
.scss file extension. Remove the .scss extension from the import path in the
`@import` statement so that it reads "../Components/FullCalendar/BitFullCalendar"
instead of "../Components/FullCalendar/BitFullCalendar.scss". This will allow
stylelint to pass the check while maintaining the correct import functionality.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 50cd2d85-9a04-4492-ae4f-bb5588f42b81
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 8
♻️ Duplicate comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor (1)
9-21: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winKeep Event mode tab visible when there are no resources.
Line 9 hides the entire mode-tab container when
State.Resources.Count == 0, which removes Event mode switching entirely. Keep the container rendered and only suppress the Timeline tab when resources are unavailable.Suggested minimal patch
-@if (State.Resources.Count > 0) -{ - <div class="bit-bfc-mode-tabs"> - `@foreach` (var mode in _modes) - { - <button class="bit-bfc-mode-tab @(State.Mode == mode ? "active" : "")" - type="button" - `@onclick`="() => State.SetMode(mode)"> - `@Texts.GetModeLabel`(mode) - </button> - } - </div> -} +<div class="bit-bfc-mode-tabs"> + `@foreach` (var mode in _modes) + { + if (mode is BitFullCalendarMode.Timeline && State.Resources.Count == 0) continue; + + <button class="bit-bfc-mode-tab @(State.Mode == mode ? "active" : "")" + type="button" + `@onclick`="() => State.SetMode(mode)"> + `@Texts.GetModeLabel`(mode) + </button> + } +</div>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor` around lines 9 - 21, The outer conditional in BitFcModeTabs.razor that checks State.Resources.Count > 0 prevents the entire mode-tabs container from rendering when there are no resources, which removes the Event mode option. Remove the outer if condition that wraps the div with class bit-bfc-mode-tabs so the container always renders. Then inside the foreach loop that iterates through _modes, add a conditional check to skip rendering the button only when the current mode is Timeline and State.Resources.Count is zero, allowing Event mode to remain available while suppressing the Timeline tab.
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor (1)
6-10: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd
@keyto stabilize badge identity during list updates.Without a key, Blazor can reuse badge component instances by position when event ordering changes.
♻️ Suggested change
`@foreach` (var ev in _multiDayForDay) { var position = GetPosition(ev); - <BitFcMonthEventBadge Event="ev" CellDate="Date" Position="`@position`" OnSelected="ShowEventDetails" EventTemplate="EventTemplate" /> + <BitFcMonthEventBadge `@key`="ev.Id" Event="ev" CellDate="Date" Position="`@position`" OnSelected="ShowEventDetails" EventTemplate="EventTemplate" /> }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor` around lines 6 - 10, The foreach loop that renders BitFcMonthEventBadge components is missing a `@key` directive, which allows Blazor to reuse component instances by position when the _multiDayForDay list order changes, causing potential state and rendering issues. Add a `@key` directive to the foreach loop iterating over _multiDayForDay, using a unique identifier from the event object (such as the event's Id property) as the key value to ensure each BitFcMonthEventBadge component maintains stable identity across re-renders.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cs`:
- Around line 38-43: The parametersChanged variable in the comparison logic is
missing a check for the Resource parameter. Add Resource to the reinitialization
change key by including a comparison between the current Resource and a stored
_lastResource field (similar to how _lastExistingEvent, _lastStartDate,
_lastStartHour, and _lastStartMinute are compared). This will ensure that when
the dialog is reused with the same event and start parameters but a different
resource, it properly reinitializes instead of maintaining stale draft state.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 690-701: The CreateDraftEventForTimeSlot method accepts hour,
startMinute, and durationMinutes parameters without validation, allowing invalid
values to create malformed date ranges. Add explicit input validation at the
start of the CreateDraftEventForTimeSlot method to ensure hour is between 0 and
23, startMinute is between 0 and 59, and durationMinutes is greater than zero.
If any validation fails, throw an appropriate exception with a descriptive
message to catch these errors at the boundary.
- Around line 640-653: The XML documentation for the CeilToMinuteInterval method
claims results will be on the same calendar day, but the implementation at line
652 can return a time on the next calendar day when the interval calculation
crosses midnight (e.g., 23:59 with a 30-minute interval). Either update the XML
documentation lines to accurately reflect that the result may span into the next
day, or modify the implementation logic to clamp the result back to the current
day or throw an exception when the interval exceeds the day boundary. Choose the
approach that best aligns with the intended use cases for this method.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs`:
- Around line 20-28: The await call to
BitFcAgendaScrollInterop.TryScrollToDateAsync in the OnAfterRenderAsync method
lacks exception handling, which can cause render path failures during prerender,
teardown, or disconnect scenarios. Wrap the await statement in a try-catch block
to handle transient JavaScript interop exceptions gracefully, using the same
error handling pattern that is already implemented elsewhere in this feature for
similar interop calls. The catch block should log the exception or handle it
silently to prevent circuit crashes while still allowing the scroll
functionality to attempt execution.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs`:
- Around line 101-104: The BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync
call uses a hard-coded DOM id string "bit-bfc-week-timegrid-scroll" which causes
all instances of BitFcCalendarWeekView to target the same element. Create an
instance-scoped field (for example, _timeGridScrollElementId) to generate a
unique id per component instance, then replace the hard-coded string with this
field in the TryScrollToStartOfDayAsync call. Additionally, in the
BitFcCalendarWeekView.razor template, update the timegrid container element's id
attribute to use the same instance field (id="`@_timeGridScrollElementId`") to
ensure the interop targets the correct element for each instance.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cs`:
- Around line 97-101: The SlotAriaLabel method currently calls
BitFullCalendarHelpers.FormatTime without passing the State.Culture parameter,
which causes the time to be formatted using the default culture instead of the
selected calendar culture. Update the FormatTime call on line 100 to include
State.Culture as an additional parameter so that the ARIA label time formatting
matches the calendar's selected culture.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Around line 136-143: The scroll signature is not being reset when navigating
away from the current month. Currently, when the year or month of the selected
date doesn't match today's year or month, the method returns early without
clearing the _scrollSignature variable. This causes the scroll-to-today logic to
be skipped when navigating back to the same current month later, since the old
signature still matches. To fix this, assign an empty string to _scrollSignature
before the early return statement in the condition that checks if
cal.GetYear(State.SelectedDate) and cal.GetMonth(State.SelectedDate) don't match
the current date's year and month.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cs`:
- Around line 99-103: The SlotAriaLabel method's call to
BitFullCalendarHelpers.FormatTime is not passing the State.Culture parameter,
causing the time formatting to use the default culture instead of the selected
calendar culture. Modify the FormatTime method call to include State.Culture as
a parameter alongside State.Use24HourFormat to ensure the ARIA label respects
the user's selected culture setting.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor`:
- Around line 9-21: The outer conditional in BitFcModeTabs.razor that checks
State.Resources.Count > 0 prevents the entire mode-tabs container from rendering
when there are no resources, which removes the Event mode option. Remove the
outer if condition that wraps the div with class bit-bfc-mode-tabs so the
container always renders. Then inside the foreach loop that iterates through
_modes, add a conditional check to skip rendering the button only when the
current mode is Timeline and State.Resources.Count is zero, allowing Event mode
to remain available while suppressing the Timeline tab.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor`:
- Around line 6-10: The foreach loop that renders BitFcMonthEventBadge
components is missing a `@key` directive, which allows Blazor to reuse component
instances by position when the _multiDayForDay list order changes, causing
potential state and rendering issues. Add a `@key` directive to the foreach loop
iterating over _multiDayForDay, using a unique identifier from the event object
(such as the event's Id property) as the key value to ensure each
BitFcMonthEventBadge component maintains stable identity across re-renders.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 9b59eb62-014d-44f3-bed9-5231c2243e42
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cs`:
- Around line 39-44: The parametersChanged check in BitFcAddEditEventDialog does
not account for changes to the fallback date source. Since line 83-84 uses
StartDate ?? State.SelectedDate to derive the new-event base date, the
reinitialization logic must also track State.SelectedDate in addition to
StartDate. If StartDate is null and State.SelectedDate changes, the dialog will
not reinitialize and will keep stale date values. Add State.SelectedDate to the
parametersChanged comparison by storing the last known value (such as
_lastSelectedDate) and comparing it against the current State.SelectedDate,
similar to how StartDate, StartHour, StartMinute, and Resource are already being
tracked in the parametersChanged condition.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Line 16: The Attendees property in BitFullCalendarEvent initializes to an
empty list but allows null to be assigned through its public setter, causing
NullReferenceException in downstream code that iterates over Attendees. Guard
the property setter to prevent null assignment by implementing a setter that
either rejects null values or coalesces null assignments to an empty list,
ensuring Attendees is never null at the model boundary.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor`:
- Around line 29-30: The `@onkeydown` event handler in BitFcMonthEventBadge.razor
is missing event propagation stopping, which allows keyboard events to bubble up
to the parent BitFcDayCell.razor component and trigger both the badge action and
the cell's add-event action. Add :stopPropagation="true" to the `@onkeydown`
directive (similar to how it's already applied to
`@onclick`:stopPropagation="true" on the same element) to prevent keyboard events
from bubbling to the parent day-cell key handler.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor`:
- Around line 41-43: The issue is that HasUnassignedRow becomes false when there
are no resources and no existing unassigned events, resulting in no slot cells
being rendered. Update the logic that determines HasUnassignedRow to ensure it
returns true when State.Resources is empty, even if there are currently no
unassigned events. This will render an empty unassigned row that allows users to
create the first event. The same fix should also be applied at lines 122-124
where similar logic exists.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor`:
- Around line 48-49: The timeline week view becomes unusable when
State.Resources is empty and there are no unassigned events, because
hasUnassigned evaluates to false and no rows render. Modify the hasUnassigned
variable calculation in BitFcTimelineWeekView to also check if State.Resources
is empty or contains no items. The unassigned lane should be displayed whenever
there are no resources, ensuring there is always at least one row available
where users can add the first event to the timeline.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 96e37496-1ba6-4aaf-bd89-45ba2df89212
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 8
♻️ Duplicate comments (7)
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
7-7: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winRemove the extension from the SCSS import to satisfy stylelint.
Line 7 still violates
scss/load-partial-extension; this can fail lint checks.Suggested fix
-@import "../Components/FullCalendar/BitFullCalendar.scss"; +@import "../Components/FullCalendar/BitFullCalendar";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss` at line 7, The SCSS import statement violates the scss/load-partial-extension stylelint rule because it includes the .scss file extension in the path. Remove the .scss extension from the import statement that references BitFullCalendar so that it imports the partial file without the extension. This will allow the stylelint check to pass.Source: Linters/SAST tools
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs (1)
8-9: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
EndDate >= StartDateinvariant is still not enforced.The model still allows inverted ranges, so
Durationcan be negative and downstream scheduling logic can process invalid event windows.Suggested fix
public class BitFullCalendarEvent { + private DateTime _startDate; + private DateTime _endDate; + @@ - public DateTime StartDate { get; set; } - public DateTime EndDate { get; set; } + public DateTime StartDate + { + get => _startDate; + set + { + _startDate = value; + if (_endDate < _startDate) + throw new ArgumentException("EndDate must be greater than or equal to StartDate."); + } + } + + public DateTime EndDate + { + get => _endDate; + set + { + if (value < _startDate) + throw new ArgumentException("EndDate must be greater than or equal to StartDate."); + _endDate = value; + } + }Also applies to: 34-37
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 8 - 9, The BitFullCalendarEvent model does not enforce the invariant that EndDate must be greater than or equal to StartDate, allowing invalid event windows where Duration becomes negative. Add validation logic to the property setters for StartDate and EndDate (also apply to the corresponding properties mentioned at lines 34-37) to ensure EndDate is never less than StartDate. When either property is set, validate the relationship between both dates and throw an appropriate exception if the invariant would be violated.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs (1)
20-29: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winConstructor snapshot is still shallow, so lookup/order can drift.
Optionscopies references, not option objects. External mutation of an option (notablyId) can desync_byIdfromOptions.Suggested fix
public BitFullCalendarColorScheme(IReadOnlyList<BitFullCalendarColorOption>? options) { var list = options is { Count: > 0 } ? options : BitFullCalendarColorOption.Defaults; - // Snapshot the source so Options and the _byId lookup can't drift apart if the caller mutates the original list. - Options = [.. list]; + // Deep snapshot to prevent external mutations from drifting lookup/order. + Options = list.Select(o => new BitFullCalendarColorOption + { + Id = o.Id, + Title = o.Title, + Value = o.Value + }).ToArray(); _byId = new Dictionary<string, BitFullCalendarColorOption>(StringComparer.OrdinalIgnoreCase); - foreach (var o in list) + foreach (var o in Options) { var id = o.Id?.Trim(); if (!string.IsNullOrEmpty(id) && !_byId.ContainsKey(id)) _byId[id] = o; } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs` around lines 20 - 29, The Options field assignment creates a shallow copy of the list, meaning the array contains references to the original BitFullCalendarColorOption objects. If external code mutates an option's Id property after construction, the _byId dictionary lookup will become desynchronized from Options. To fix this, create a deep copy by cloning each BitFullCalendarColorOption object when populating the Options array instead of copying references directly. Each BitFullCalendarColorOption in the Options snapshot should be an independent copy so that external mutations to the original objects cannot affect the internal state of Options and _byId.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs (1)
24-31: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winDispose path can still race
Task.Delaytoken access.Disposing each
CancellationTokenSourceinDisposeAsynccan happen beforeRemoveAfterDelayreadscts.Token, which can fault the background task withObjectDisposedException. Keep cancellation inDisposeAsync, but letRemoveAfterDelayown disposal.Suggested minimal fix
private async Task RemoveAfterDelay(int id, CancellationTokenSource cts) { @@ finally { - // Drop the token as soon as its timer finishes (or is cancelled) so _removalTokens - // doesn't grow unbounded on long-lived pages that show many toasts. - bool removed; lock (_removalTokensLock) { - removed = _removalTokens.Remove(cts); + _removalTokens.Remove(cts); } - if (removed) - cts.Dispose(); + cts.Dispose(); } } @@ foreach (var cts in tokens) { - try - { - cts.Cancel(); - cts.Dispose(); - } - catch (ObjectDisposedException) - { - // Already disposed by RemoveAfterDelay's cleanup; nothing to do. - } + cts.Cancel(); }Also applies to: 44-55, 69-79
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs` around lines 24 - 31, The RemoveAfterDelay method has a race condition where DisposeAsync can dispose the CancellationTokenSource before RemoveAfterDelay accesses the cts.Token property, causing an ObjectDisposedException. To fix this, modify RemoveAfterDelay to take ownership of disposing the CancellationTokenSource after it completes its operation. In DisposeAsync, keep the cancellation logic (call cts.Cancel()) to signal cancellation but remove the direct disposal of the CancellationTokenSource instances. Instead, let each RemoveAfterDelay invocation dispose its own cts in a finally block after the Task.Delay completes, ensuring the token is never accessed after disposal.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss (1)
3-3: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winFix the SCSS import to satisfy
scss/load-partial-extension.Line 3 still imports with
.scss, which keeps the prior lint blocker unresolved.Suggested fix
-@import "../../../Bit.BlazorUI/Styles/functions.scss"; +@import "../../../Bit.BlazorUI/Styles/functions";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss` at line 3, The SCSS import statement in the BitFullCalendar.scss file is including the `.scss` file extension in the import path, which violates the scss/load-partial-extension linter rule. Remove the `.scss` extension from the import path for the functions.scss file on line 3, as SCSS partials can be imported without their file extension. This will resolve the lint rule violation while maintaining the same functionality.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts (1)
123-127: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winCapture early pointer-up coordinates before deferring resize end.
Line 126 and Line 230 defer
endResizebefore copying pointer position. If release happens beforeOnResizeStartcompletes (and no move event fires), final delta can be stale/zero.💡 Minimal patch
const endResize = async (ev?: PointerEvent) => { if (ev && activePointerId != null && ev.pointerId !== activePointerId) return; + if (ev) latestY = ev.clientY; // A pointer release before resize-start completes is deferred and replayed afterwards. if (!startSucceeded) { pendingEnd = true; return; } if (ended) return; @@ const endResize = async (ev?: PointerEvent) => { if (ev && activePointerId != null && ev.pointerId !== activePointerId) return; + if (ev) latestX = ev.clientX; // A pointer release before resize-start completes is deferred and replayed afterwards. if (!startSucceeded) { pendingEnd = true; return; } if (ended) return;Also applies to: 227-231
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts` around lines 123 - 127, The endResize function defers execution when startSucceeded is false by setting pendingEnd to true and returning early, but the pointer event coordinates (such as clientX and clientY from the ev parameter) are not captured at that moment of deferral. This means when endResize is replayed later after OnResizeStart completes, if no move event fires in between, the pointer coordinates will be stale or zero, resulting in incorrect final delta calculations. Capture and store the pointer event coordinates from the ev parameter before returning on the deferred condition (when !startSucceeded is true), then use these stored coordinates when the deferred endResize is replayed. Apply the same fix to the corresponding deferred handler around line 230 which handles the same scenario (lines 227-231).src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cs (1)
84-84: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winCapture
OldEventsnapshot before callingState.UpdateEvent.Line 84 stores a live reference (
_resizeBaseEvent = Event), and Line 196 clones after Line 191 updates state. IfState.UpdateEventmutates the existing instance,OldEventcan be emitted with updated values instead of the pre-resize state.Suggested fix
[JSInvokable] public void OnResizeStart(string direction) { _isResizing = true; _resizeDirection = direction; - _resizeBaseEvent = Event; + _resizeBaseEvent = BitFullCalendarChangeNotifier.CloneEvent(Event); @@ if (s != _resizeBaseEvent.StartDate || e != _resizeBaseEvent.EndDate) { var b = _resizeBaseEvent; + var oldSnapshot = BitFullCalendarChangeNotifier.CloneEvent(b); var updated = new BitFullCalendarEvent { @@ await Notifier.NotifyAsync(new BitFullCalendarChangeEventArgs { Event = BitFullCalendarChangeNotifier.CloneEvent(updated), - OldEvent = BitFullCalendarChangeNotifier.CloneEvent(b), + OldEvent = oldSnapshot, Kind = BitFullCalendarChangeKind.Edit, Source = BitFullCalendarChangeSource.Resize }); }Also applies to: 191-197
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cs` at line 84, The assignment at line 84 stores a live reference to the Event instead of a snapshot, which means if State.UpdateEvent mutates the event instance at line 191, the _resizeBaseEvent reference will also be mutated. This causes OldEvent to be emitted with updated values instead of the pre-resize state. Create a deep clone or snapshot of the Event when assigning to _resizeBaseEvent at line 84 to ensure OldEvent captures the original pre-resize state before State.UpdateEvent is called on lines 191-197.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor`:
- Line 12: The focusable div element with class "bit-bfc-agenda-item" and
tabindex="0" has a `@onkeydown` handler binding that calls OnEventKeyDown, but the
default Space key scroll behavior is not being prevented, causing unwanted
page/dialog scrolling. Modify the `@onkeydown` directive on this div element to
include preventDefault behavior to stop the default scroll action from occurring
when Space or Enter keys are pressed on the focusable element.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor`:
- Line 10: The `@onkeydown` directive in the BitFcDraggableEvent component needs
to prevent the default browser behavior for Space and Enter key presses to avoid
unwanted page scrolling. Add preventDefault handling to the `@onkeydown` event
binding by either using `@onkeydown`:preventDefault="true" on the directive, or
modify the OnKeyDown event handler method to call preventDefault when Space or
Enter keys are detected. This ensures keyboard activation behaves predictably
without triggering default scroll behavior.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs`:
- Around line 111-122: The BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync
call in the OnAfterRenderAsync method can throw transient JavaScript lifecycle
exceptions during prerender or disconnect phases. Wrap this interop call in a
try-catch block to guard against these transient failures, and only update the
_timeGridScrollSignature property when the operation completes successfully
without throwing an exception.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs`:
- Around line 96-107: The call to
BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync in the OnAfterRenderAsync
method can throw exceptions during JavaScript unavailability
(disconnect/teardown scenarios), causing render failures. Wrap the entire
if-statement containing the TryScrollToStartOfDayAsync call in a try-catch block
to gracefully catch and handle these transient exceptions without allowing them
to propagate and fail the render.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 16-19: The hasUnassigned flag only becomes true when unassigned
events already exist, but it should also be true when there are no valid
resources, ensuring an unassigned row is always rendered. Modify the logic that
sets hasUnassigned to check not only for the existence of unassigned events in
the grouped data, but also to return true when the resourceIds list is empty, so
that users can create events even in an empty calendar with no resources.
- Around line 62-84: Remove the nested focusable structure in
BitFcTimelineDayView.razor where the hour slot (outer div with role="button")
contains a half-hour slot (inner div with role="button"). Instead, render both
the 0-minute and 30-minute time slot targets as sibling native button elements
(button type="button") outside of each other, ensuring each button independently
calls the same event handlers OnDragEnter, OnDrop, OnSlotClickAsync, and
OnSlotKeyDownAsync with their respective minute values (0 or 30). Apply this
same restructuring to the other instance mentioned at lines 106-128.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor`:
- Around line 18-19: The resource filtering logic in the
BitFcTimelineLayout.razor file uses string.IsNullOrEmpty to check if a resource
ID is assigned, but this does not handle whitespace-only strings which should
also be treated as unassigned. Replace the string.IsNullOrEmpty call on r.Id
with string.IsNullOrWhiteSpace to properly filter out resources with empty or
whitespace-only IDs in the Where clause that filters State.Resources.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor`:
- Around line 20-21: The hasUnassigned logic in the BitFcTimelineWeekView
component (referenced at lines 48-52) is currently checking against the raw
resource count rather than the valid resource IDs. Since resourceIds is already
filtered to exclude empty IDs using the Select and Where chain, update the
hasUnassigned check to base its condition on the count of valid resourceIds
instead of the total resources count to ensure the unassigned fallback row is
properly shown when there are no valid resources with non-empty IDs.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cs`:
- Around line 24-31: The RemoveAfterDelay method has a race condition where
DisposeAsync can dispose the CancellationTokenSource before RemoveAfterDelay
accesses the cts.Token property, causing an ObjectDisposedException. To fix
this, modify RemoveAfterDelay to take ownership of disposing the
CancellationTokenSource after it completes its operation. In DisposeAsync, keep
the cancellation logic (call cts.Cancel()) to signal cancellation but remove the
direct disposal of the CancellationTokenSource instances. Instead, let each
RemoveAfterDelay invocation dispose its own cts in a finally block after the
Task.Delay completes, ensuring the token is never accessed after disposal.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Line 3: The SCSS import statement in the BitFullCalendar.scss file is
including the `.scss` file extension in the import path, which violates the
scss/load-partial-extension linter rule. Remove the `.scss` extension from the
import path for the functions.scss file on line 3, as SCSS partials can be
imported without their file extension. This will resolve the lint rule violation
while maintaining the same functionality.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 123-127: The endResize function defers execution when
startSucceeded is false by setting pendingEnd to true and returning early, but
the pointer event coordinates (such as clientX and clientY from the ev
parameter) are not captured at that moment of deferral. This means when
endResize is replayed later after OnResizeStart completes, if no move event
fires in between, the pointer coordinates will be stale or zero, resulting in
incorrect final delta calculations. Capture and store the pointer event
coordinates from the ev parameter before returning on the deferred condition
(when !startSucceeded is true), then use these stored coordinates when the
deferred endResize is replayed. Apply the same fix to the corresponding deferred
handler around line 230 which handles the same scenario (lines 227-231).
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cs`:
- Around line 20-29: The Options field assignment creates a shallow copy of the
list, meaning the array contains references to the original
BitFullCalendarColorOption objects. If external code mutates an option's Id
property after construction, the _byId dictionary lookup will become
desynchronized from Options. To fix this, create a deep copy by cloning each
BitFullCalendarColorOption object when populating the Options array instead of
copying references directly. Each BitFullCalendarColorOption in the Options
snapshot should be an independent copy so that external mutations to the
original objects cannot affect the internal state of Options and _byId.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: The BitFullCalendarEvent model does not enforce the invariant
that EndDate must be greater than or equal to StartDate, allowing invalid event
windows where Duration becomes negative. Add validation logic to the property
setters for StartDate and EndDate (also apply to the corresponding properties
mentioned at lines 34-37) to ensure EndDate is never less than StartDate. When
either property is set, validate the relationship between both dates and throw
an appropriate exception if the invariant would be violated.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cs`:
- Line 84: The assignment at line 84 stores a live reference to the Event
instead of a snapshot, which means if State.UpdateEvent mutates the event
instance at line 191, the _resizeBaseEvent reference will also be mutated. This
causes OldEvent to be emitted with updated values instead of the pre-resize
state. Create a deep clone or snapshot of the Event when assigning to
_resizeBaseEvent at line 84 to ensure OldEvent captures the original pre-resize
state before State.UpdateEvent is called on lines 191-197.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: The SCSS import statement violates the scss/load-partial-extension
stylelint rule because it includes the .scss file extension in the path. Remove
the .scss extension from the import statement that references BitFullCalendar so
that it imports the partial file without the extension. This will allow the
stylelint check to pass.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 5eea49d8-8794-422a-a7e2-7b792ef16a23
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (8)
src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss (1)
7-7: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winRemove the
.scssextension from the new import to satisfy stylelint.Line 7 still imports with
.scssextension, which violatesscss/load-partial-extensionand can fail lint checks.Suggested fix
-@import "../Components/FullCalendar/BitFullCalendar.scss"; +@import "../Components/FullCalendar/BitFullCalendar";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss` at line 7, Remove the .scss file extension from the import statement in extra-components.scss. The import statement for BitFullCalendar.scss should omit the .scss extension and reference only the partial file name without its extension, as required by the scss/load-partial-extension stylelint rule.Source: Linters/SAST tools
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cs (1)
15-37: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winStateful keydown prevent-default flag leaks into the next key event.
Line 32 sets
_preventKeyDefaultas component state, so after Enter/Space the next keydown can inherit a staletruevia Line 12 inBitFcEventListDialog.razor, briefly blocking normal keyboard navigation.💡 Suggested patch
--- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor @@ - <div class="bit-bfc-agenda-item" tabindex="0" role="button" `@onclick`="() => SelectEvent(ev)" `@onkeydown`="@(e => OnEventKeyDown(e, ev))" `@onkeydown`:preventDefault="_preventKeyDefault"> + <div class="bit-bfc-agenda-item" tabindex="0" role="button" `@onclick`="() => SelectEvent(ev)" `@onkeydown`="@(e => OnEventKeyDown(e, ev))">--- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cs @@ - // Drives `@onkeydown`:preventDefault so Space/Enter activation doesn't also scroll the dialog, - // while leaving Tab/arrow keys with their native behaviour (no keyboard trap). - private bool _preventKeyDefault; @@ - _preventKeyDefault = e.Key is "Enter" or " " or "Spacebar"; - if (_preventKeyDefault) + if (e.Key is "Enter" or " " or "Spacebar") { await SelectEvent(ev); }In Blazor, for `@onkeydown`:preventDefault bound to a bool field, is the preventDefault decision taken from the last render (so changing that field inside the same keydown handler does not affect the current event)?🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cs` around lines 15 - 37, The OnEventKeyDown method sets _preventKeyDefault to true but never resets it, causing the flag to persist as component state and leak into subsequent keyboard events. When the next keydown occurs (such as an arrow key), it incorrectly inherits the stale true value from the previous Enter/Space keydown. Fix this by resetting _preventKeyDefault to false at the start of the OnEventKeyDown method before evaluating the current key, ensuring each keydown event is evaluated independently without state leakage from previous events.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cs (1)
13-25: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
_preventKeyDefaultcreates one-event-late keyboard suppression here too.Line 22 stores key intent in component state, so the next key event can see stale prevent-default behavior via
BitFcDraggableEvent.razorLine 11.💡 Suggested patch
--- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor @@ - `@onkeydown`="OnKeyDown" - `@onkeydown`:preventDefault="_preventKeyDefault" + `@onkeydown`="OnKeyDown"--- a/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cs +++ b/src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cs @@ - // Drives `@onkeydown`:preventDefault so Space/Enter activation doesn't also scroll the page, - // while leaving Tab/arrow keys with their native behaviour (no keyboard trap). - private bool _preventKeyDefault; @@ - _preventKeyDefault = e.Key is "Enter" or " " or "Spacebar"; - if (_preventKeyDefault) + if (e.Key is "Enter" or " " or "Spacebar") await OnClick.InvokeAsync();In Blazor, when `@onkeydown`:preventDefault is bound to a component field, does toggling that field inside OnKeyDown affect the same keydown event or only future events?🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cs` around lines 13 - 25, The _preventKeyDefault field in the OnKeyDown method is set based on the current key event, but the `@onkeydown`:preventDefault directive in the razor template evaluates before the OnKeyDown handler executes, causing the prevention to apply one event too late. To fix this, remove the reliance on the _preventKeyDefault field for the current event's prevention and instead use JavaScript interop to directly call preventDefault on the keyboard event for the keys "Enter", " " (space), and "Spacebar" immediately within the OnKeyDown handler, ensuring prevention applies to the same event that triggered the handler.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs (1)
8-9: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winStill unresolved: enforce
EndDate >= StartDateat the model boundary.Inverted ranges are still allowed, so
Durationcan become negative and propagate invalid updates during drag/drop flows.Suggested fix
public class BitFullCalendarEvent { + private DateTime _startDate; + private DateTime _endDate; + public string Id { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; - public DateTime StartDate { get; set; } - public DateTime EndDate { get; set; } + public DateTime StartDate + { + get => _startDate; + set + { + _startDate = value; + if (_endDate < _startDate) + throw new ArgumentException("EndDate must be greater than or equal to StartDate."); + } + } + public DateTime EndDate + { + get => _endDate; + set + { + if (value < _startDate) + throw new ArgumentException("EndDate must be greater than or equal to StartDate."); + _endDate = value; + } + }Also applies to: 34-37
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 8 - 9, Add validation to the StartDate and EndDate properties in the BitFullCalendarEvent class to enforce that EndDate is always greater than or equal to StartDate. Implement validation logic in the property setters to prevent invalid date ranges that could result in negative durations and cause issues during drag/drop operations. The same validation should be applied to any other similar date range properties in the model as indicated by the comment about lines 34-37.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cs (1)
80-84: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winGuard
OnResizeStartagainst invalid directions.Line 80 still accepts any
directionand flips_isResizingon, while invalid directions are ignored later inOnResizeMove. Early-returning here avoids getting stuck in resize-suppression paths from unexpected interop payloads.Suggested fix
[JSInvokable] public void OnResizeStart(string direction) { + if (direction is not ("top" or "bottom")) + return; + _isResizing = true; _resizeDirection = direction; _resizeBaseEvent = Event;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cs` around lines 80 - 84, Add validation at the beginning of the OnResizeStart method to guard against invalid direction values before setting _isResizing to true and assigning the _resizeDirection field. Check if the direction parameter is one of the valid resize directions (typically the cardinal and diagonal directions like "n", "s", "e", "w", "ne", "nw", "se", "sw" or however they are defined in your resize logic), and only proceed with the resize initialization (_isResizing = true, _resizeDirection = direction, _resizeBaseEvent = Event) if the direction is valid. If an invalid direction is provided, return early from the method to prevent the component from entering an inconsistent state where resize mode is enabled with an unrecognized direction.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor (1)
20-22: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winUse whitespace-safe resource-ID filtering for week fallback logic.
Week fallback currently treats whitespace IDs as valid resources. Combined with
BitFcTimelineLayoutfiltering, this can suppress the unassigned row while also rendering zero resource rows.Suggested fix
- var resourceIds = resources.Select(r => r.Id).Where(id => !string.IsNullOrEmpty(id)).ToList(); + var resourceIds = resources.Select(r => r.Id).Where(id => !string.IsNullOrWhiteSpace(id)).ToList();Also applies to: 48-52
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor` around lines 20 - 22, The resource ID filtering in BitFcTimelineWeekView.razor is using string.IsNullOrEmpty to validate resource IDs, which treats whitespace-only strings as valid. Replace the string.IsNullOrEmpty(id) check with string.IsNullOrWhiteSpace(id) in the Where clause that filters the resourceIds to properly exclude whitespace-only resource IDs and prevent unassigned rows from being incorrectly suppressed.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor (1)
26-27: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winNormalize resource-ID validity before unassigned-row fallback.
resourceIdstreats whitespace IDs as valid, whileBitFcTimelineLayout.razorfilters those rows out. This can leave month timeline with no rendered rows andHasUnassignedRow == false, so users cannot add the first event.Suggested fix
- var resourceIds = resources.Select(r => r.Id).Where(id => !string.IsNullOrEmpty(id)).ToList(); + var resourceIds = resources.Select(r => r.Id).Where(id => !string.IsNullOrWhiteSpace(id)).ToList(); @@ - var hasUnassigned = hasUnassignedEvents || resources.Count == 0; + var hasUnassigned = hasUnassignedEvents || resourceIds.Count == 0;Also applies to: 41-45
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor` around lines 26 - 27, The resourceIds filtering logic in BitFcTimelineMonthView.razor uses IsNullOrEmpty which treats whitespace-only IDs as valid, but BitFcTimelineLayout.razor filters those rows out using IsNullOrWhiteSpace, creating a mismatch that can result in no rendered rows. Replace the IsNullOrEmpty check with IsNullOrWhiteSpace in the Where clause that filters the resources.Select statement to ensure consistent handling of whitespace IDs across both components. This same fix should be applied to the similar filtering logic mentioned at lines 41-45.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs (1)
136-148: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winMake scroll signature culture-calendar aware, not Gregorian-month based.
The guard is now culture-aware, but
sigstill uses Gregorianyyyy-MM. That can skip scroll-to-today after culture/calendar changes even when the rendered month grid changed.Suggested fix
var cal = State.Culture.Calendar; var today = DateTime.Today; - if (cal.GetYear(State.SelectedDate) != cal.GetYear(today) || - cal.GetMonth(State.SelectedDate) != cal.GetMonth(today)) + var selectedYear = cal.GetYear(State.SelectedDate); + var selectedMonth = cal.GetMonth(State.SelectedDate); + var todayYear = cal.GetYear(today); + var todayMonth = cal.GetMonth(today); + if (selectedYear != todayYear || selectedMonth != todayMonth) { // Reset the signature so that navigating back to the current month later re-triggers // the scroll-to-today interop instead of being skipped by a stale matching signature. _scrollSignature = ""; return; } - var sig = $"{State.SelectedDate:yyyy-MM}|{today:yyyy-MM-dd}"; + var sig = $"{State.Culture.Name}|{selectedYear:D4}-{selectedMonth:D2}|{today:yyyy-MM-dd}";🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs` around lines 136 - 148, The scroll signature generation using the hardcoded Gregorian format string (yyyy-MM) is inconsistent with the culture-aware guard condition above that uses cal.GetYear() and cal.GetMonth(). Replace the sig variable construction to use the same culture-aware calendar methods instead of Gregorian date formatting. Build the signature string by calling cal.GetYear() and cal.GetMonth() on both State.SelectedDate and today, along with the day components, so that the signature properly reflects month changes when the calendar system changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 88-91: The pointerdown event handlers at lines 88 and 198 only
gate on e.button, which allows multiple touch pointers to start concurrent
resize operations on the same element. Implement pointer tracking by adding a
property to store the active pointer ID. In the pointerdown event handler, check
if a pointer is already active before allowing a new resize to start, store the
pointer ID from e.pointerId when starting a resize, and only process subsequent
pointermove and pointerup events if they match the stored active pointer ID.
Clear the active pointer ID when the resize operation completes.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cs`:
- Around line 26-27: The TryScrollToDateAsync call result should be captured and
checked before updating _lastAgendaScrollNonce. Currently the nonce is advanced
unconditionally regardless of whether
BitFcAgendaScrollInterop.TryScrollToDateAsync returns success or failure, which
prevents retry attempts after transient failures. Store the result of the
TryScrollToDateAsync call in a variable and only update _lastAgendaScrollNonce
when that result indicates success.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cs`:
- Around line 15-37: The OnEventKeyDown method sets _preventKeyDefault to true
but never resets it, causing the flag to persist as component state and leak
into subsequent keyboard events. When the next keydown occurs (such as an arrow
key), it incorrectly inherits the stale true value from the previous Enter/Space
keydown. Fix this by resetting _preventKeyDefault to false at the start of the
OnEventKeyDown method before evaluating the current key, ensuring each keydown
event is evaluated independently without state leakage from previous events.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cs`:
- Around line 13-25: The _preventKeyDefault field in the OnKeyDown method is set
based on the current key event, but the `@onkeydown`:preventDefault directive in
the razor template evaluates before the OnKeyDown handler executes, causing the
prevention to apply one event too late. To fix this, remove the reliance on the
_preventKeyDefault field for the current event's prevention and instead use
JavaScript interop to directly call preventDefault on the keyboard event for the
keys "Enter", " " (space), and "Spacebar" immediately within the OnKeyDown
handler, ensuring prevention applies to the same event that triggered the
handler.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: Add validation to the StartDate and EndDate properties in the
BitFullCalendarEvent class to enforce that EndDate is always greater than or
equal to StartDate. Implement validation logic in the property setters to
prevent invalid date ranges that could result in negative durations and cause
issues during drag/drop operations. The same validation should be applied to any
other similar date range properties in the model as indicated by the comment
about lines 34-37.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cs`:
- Around line 80-84: Add validation at the beginning of the OnResizeStart method
to guard against invalid direction values before setting _isResizing to true and
assigning the _resizeDirection field. Check if the direction parameter is one of
the valid resize directions (typically the cardinal and diagonal directions like
"n", "s", "e", "w", "ne", "nw", "se", "sw" or however they are defined in your
resize logic), and only proceed with the resize initialization (_isResizing =
true, _resizeDirection = direction, _resizeBaseEvent = Event) if the direction
is valid. If an invalid direction is provided, return early from the method to
prevent the component from entering an inconsistent state where resize mode is
enabled with an unrecognized direction.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor`:
- Around line 26-27: The resourceIds filtering logic in
BitFcTimelineMonthView.razor uses IsNullOrEmpty which treats whitespace-only IDs
as valid, but BitFcTimelineLayout.razor filters those rows out using
IsNullOrWhiteSpace, creating a mismatch that can result in no rendered rows.
Replace the IsNullOrEmpty check with IsNullOrWhiteSpace in the Where clause that
filters the resources.Select statement to ensure consistent handling of
whitespace IDs across both components. This same fix should be applied to the
similar filtering logic mentioned at lines 41-45.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Around line 136-148: The scroll signature generation using the hardcoded
Gregorian format string (yyyy-MM) is inconsistent with the culture-aware guard
condition above that uses cal.GetYear() and cal.GetMonth(). Replace the sig
variable construction to use the same culture-aware calendar methods instead of
Gregorian date formatting. Build the signature string by calling cal.GetYear()
and cal.GetMonth() on both State.SelectedDate and today, along with the day
components, so that the signature properly reflects month changes when the
calendar system changes.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor`:
- Around line 20-22: The resource ID filtering in BitFcTimelineWeekView.razor is
using string.IsNullOrEmpty to validate resource IDs, which treats
whitespace-only strings as valid. Replace the string.IsNullOrEmpty(id) check
with string.IsNullOrWhiteSpace(id) in the Where clause that filters the
resourceIds to properly exclude whitespace-only resource IDs and prevent
unassigned rows from being incorrectly suppressed.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scss`:
- Line 7: Remove the .scss file extension from the import statement in
extra-components.scss. The import statement for BitFullCalendar.scss should omit
the .scss extension and reference only the partial file name without its
extension, as required by the scss/load-partial-extension stylelint rule.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 9b6cc7df-aa38-4778-8a93-93f9b070a659
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 18
♻️ Duplicate comments (4)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs (1)
96-106: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winGuard the week-view scroll interop against transient JS lifecycle failures.
This render-path interop call can still throw during disconnect/teardown and fail the component render. Catch the transient JS lifecycle exceptions and only persist
_timeGridScrollSignaturewhen the scroll succeeds.Suggested patch
protected override async Task OnAfterRenderAsync(bool firstRender) { var sig = BuildTimeGridScrollSignature(); if (sig == _timeGridScrollSignature) return; - if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( - JS, - _timeGridScrollElementId, - State.StartOfDayHour)) - _timeGridScrollSignature = sig; + try + { + if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( + JS, + _timeGridScrollElementId, + State.StartOfDayHour)) + _timeGridScrollSignature = sig; + } + catch (Exception ex) when (ex is JSException or JSDisconnectedException or InvalidOperationException or OperationCanceledException) + { + // Retry on a later render once JS is available again. + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs` around lines 96 - 106, The week-view scroll interop in BitFcCalendarWeekView.OnAfterRenderAsync is still vulnerable to transient JS lifecycle failures during disconnect or teardown. Update the OnAfterRenderAsync flow to wrap the BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync call in exception handling for transient JS/interoperability lifecycle errors, and only assign _timeGridScrollSignature after the scroll completes successfully so failed attempts can be retried on the next render.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs (1)
111-121: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winGuard the day-view scroll interop against transient JS lifecycle failures.
TryScrollToStartOfDayAsyncis still unhandled in the render path. During prerender/disconnect, that exception can fail the whole render, so_timeGridScrollSignatureshould only be updated after a successful call.Suggested patch
protected override async Task OnAfterRenderAsync(bool firstRender) { var sig = BuildTimeGridScrollSignature(); if (sig == _timeGridScrollSignature) return; - if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( - JS, - _scrollContainerId, - State.StartOfDayHour)) - _timeGridScrollSignature = sig; + try + { + if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( + JS, + _scrollContainerId, + State.StartOfDayHour)) + _timeGridScrollSignature = sig; + } + catch (Exception ex) when (ex is JSException or JSDisconnectedException or InvalidOperationException or OperationCanceledException) + { + // Retry on a later render once JS is available again. + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs` around lines 111 - 121, The day-view render path in BitFcCalendarDayView.OnAfterRenderAsync still depends on BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync without guarding transient JS lifecycle failures. Update the scroll call to safely handle prerender/disconnect exceptions so the render does not fail, and keep _timeGridScrollSignature unchanged unless the interop call completes successfully. Use the existing OnAfterRenderAsync flow, BuildTimeGridScrollSignature, and _timeGridScrollSignature to locate and adjust the logic.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor (1)
66-70: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winPrefer a real button for clickable year-day cells.
Line 66 still uses a focusable
divwithrole="button". That keeps the cell tabbable, but it still won't fully match native button keyboard behavior—most notably, Space can scroll the page instead of acting like a button press. Rendering thehasEventsbranch as a<button type="button">avoids that mismatch.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor` around lines 66 - 70, Replace the clickable year-day cell in BitFcCalendarYearView.razor with a real button when hasEvents is true instead of a focusable div with role="button". Update the branching around the cell rendering so the interactive path uses a <button type="button"> and keeps the existing click and keyboard handlers (ShowEventsForDay and OnDayKeyDown) on that element, while the non-interactive path remains non-button markup. Ensure the current month and hasEvents styling/classes are preserved on the new button.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor (1)
62-65: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winUse a real button for agenda rows.
Line 62 still emulates a button with a
div. Enter works, but Space will still scroll the page because this element does not get native button keyboard semantics. A semantic<button type="button">removes the extra key handling and fixes that behavior cleanly.Minimal patch
- <div class="bit-bfc-agenda-item" data-agenda-date="`@ev.StartDate.ToString`("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture)" - role="button" tabindex="0" - `@onclick`="() => ShowDetails(ev)" - `@onkeydown`="e => OnItemKeyDown(e, ev)"> + <button type="button" + class="bit-bfc-agenda-item" + data-agenda-date="`@ev.StartDate.ToString`("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture)" + `@onclick`="() => ShowDetails(ev)"> @@ - </div> + </button>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor` around lines 62 - 65, The agenda row in BitFcAgendaEvents still uses a div as a button, so replace the clickable agenda item container in the event rendering logic with a semantic button element in BitFcAgendaEvents.razor and keep the existing ShowDetails(ev) action wired through the button’s click handling. Remove the custom keyboard handling tied to the div, since a real button in this component will provide native Enter/Space behavior and accessible semantics automatically; use the existing identifiers ShowDetails and OnItemKeyDown to locate and simplify the interaction code.
🧹 Nitpick comments (1)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor (1)
12-31: 🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy liftPrecompute overlap metadata outside the render tree.
This block rescans every other lane for every rendered event, so dense day/week views pay the full conflict-detection cost on each rerender. Consider computing
depth/rankonce when the groups are built and rendering only the prepared layout here.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor` around lines 12 - 31, The overlap detection in BitFcRenderGroupedEvents.razor is being recomputed during rendering for every event, which is too expensive for dense day/week views. Move the conflict/position calculation out of the render path by precomputing the needed layout metadata (such as depth/rank or lane conflict counts) when GroupedEvents are built, and have the render block consume that prepared data instead of rescanning every group in the loop.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 112-126: The RAF resize callbacks in BitFullCalendar drop the
promise returned by flushMove()/dotNetRef.invokeMethodAsync("OnResizeMove",
...), so any rejection becomes unhandled. Update both resize paths (the
onPointerMove/requestAnimationFrame flow and the other OnResizeMove RAF
callback) to attach a .catch handler or otherwise explicitly handle/report
failures, while keeping the existing flushMove and invokeMethodAsync behavior
intact.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor`:
- Around line 16-17: The FullCalendar add/edit dialog is using hard-coded ids
for labeled inputs, which can collide when multiple instances are open and break
label-to-control association. Update BitFcAddEditEventDialog.razor to generate
per-instance unique ids in the component (for example with private readonly
fields like _titleInputId, _colorSelectId, and _descriptionInputId), then use
those fields consistently in the matching label for attributes and input/select
ids across the dialog.
- Around line 4-10: The BitFcAddEditEventDialog modal container is missing
dialog semantics, so update the root dialog element in
BitFcAddEditEventDialog.razor to expose proper accessibility context. Add
role="dialog", aria-modal="true", and wire an accessible title reference from
the heading, using a stable title id such as the _dialogTitleId field suggested
for this component. Make sure the dialog title element in the same component
uses that id so assistive tech can announce the dialog correctly when it opens.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor`:
- Around line 40-53: The hour and minute controls in BitFcDateTimePicker are
currently unlabeled, so add explicit accessible names to both select elements in
the time section. Update the BitFcDateTimePicker.razor markup around the _hour
and _minute selects to use visible labels or aria-label attributes so assistive
technologies can distinguish the hour field from the minute field.
- Around line 30-37: The day buttons in BitFcDateTimePicker.razor only expose
the numeric label, so update the day cell rendering to include an accessible
full-date label. Add an aria-label for each button using a helper like
GetDayAriaLabel(CalendarDay day) that formats the localized full date from
day.Date and appends selected state when day.IsSelected is true, while keeping
the existing GetDayCellClass and SelectDate flow unchanged.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor`:
- Around line 4-7: The dialog container in BitFcEventDetailsDialog lacks
accessible modal semantics, so update the main wrapper rendered by the dialog to
behave like a true dialog. Add role="dialog" and aria-modal="true" to the outer
bit-bfc-dialog element, and connect aria-labelledby to the heading rendered in
the header so assistive tech can announce the title; use the existing h3 and
OnClose markup in BitFcEventDetailsDialog as the reference points.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor`:
- Around line 4-8: Add dialog semantics to the BitFcEventListDialog container by
marking the root element as a modal dialog with role="dialog" and
aria-modal="true", and connect the heading in the dialog header to the dialog
via an accessible label relationship. Update the BitFcEventListDialog.razor
markup around the bit-bfc-dialog and bit-bfc-dialog-header structure so screen
readers identify the event list surface as a modal and announce the title
correctly.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cs`:
- Around line 15-17: The key suppression logic in BitFcEventListDialog is using
a component-level `@onkeydown:preventDefault` flag, but `_preventKeyDefault` is
updated inside `OnEventKeyDown`, so it affects the next render instead of the
current Space/Enter press. Move the per-key prevention out of the current
handler in `BitFcEventListDialog.razor`/`BitFcEventListDialog.razor.cs` by using
a native button for activation or handling the key filtering in JS, and keep
`OnEventKeyDown` focused on dispatching actions without toggling a shared
prevent-default state.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor`:
- Around line 10-11: The keyboard preventDefault flag is being applied with a
stale value, so the current Space/Enter press can still scroll while a later
keydown gets prevented instead. Update the event handling in
BitFcDraggableEvent.razor so OnKeyDown sets the prevent-default behavior for the
same keydown that triggered it, and ensure _preventKeyDefault is derived in a
way that reflects the current event rather than the previous render.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cs`:
- Around line 18-20: The header-created draft is using the current system hour
instead of the calendar’s configured default, which makes the same selected date
open inconsistently. Update the draft creation in BitFcCalendarHeader to use
Settings.StartOfDayHour when calling
BitFullCalendarHelpers.CreateDraftEventForTimeSlot, so the default hour matches
the calendar baseline and stays stable.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor`:
- Around line 4-11: The chevron icons in BitFcDateNavigator are hard-coded for
LTR, so they should be flipped when the calendar is rendered in RTL mode. Update
the markup in BitFcDateNavigator.razor to use State.IsRtl to conditionally
mirror the SVG direction for the Previous and Next buttons, keeping the existing
State.NavigatePrevious and State.NavigateNext handlers unchanged. Use the
existing State.IsRtl and BitFullCalendarHelpers/Texts context to locate the nav
button markup and apply the visual direction swap without affecting behavior.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor`:
- Around line 39-45: The mini calendar styling logic in BitFcMiniCalendar.razor
makes “today” and “selected” mutually exclusive, so the active date loses the
selected state when it is also DateTime.Today. Update the class selection logic
around the cell rendering so the SelectedDate case still applies even when
isToday is true, and keep the current-month/today/selected handling in the
BitFcMiniCalendar day button markup consistent with the intended priority.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cs`:
- Around line 17-25: Resync the mini-calendar month when culture changes, not
just when State.SelectedDate changes. Update BitFcMiniCalendar.OnParametersSet
to also track State.Culture (or an equivalent culture key) alongside
_lastSyncedSelectedDate so _displayMonth is recomputed via StartOfDisplayMonth
whenever BitFullCalendarState.SetCulture triggers a rerender. Keep the existing
SelectedDate behavior intact, but ensure culture switches force the month/header
to be normalized for the new calendar.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cs`:
- Around line 32-35: Skip events that normalize to no visible week days in
BitFcWeekViewMultiDayEventsRow.razor.cs: after computing evDays from the
adjusted EndDate/StartDate range, do not let empty evDays proceed into the row
assignment logic because All(...) on an empty set can still allocate a phantom
row. Update the row-building flow in the component so the existing loop that
assigns _eventRows only runs when evDays.Count > 0, and guard the later loop
that reads from _eventRows so it only processes events that were actually
assigned a row.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cs`:
- Around line 31-35: Update the BitFcMonthEventBadge.OnKeyDown handler to ignore
repeated keydown events by checking e.Repeat before invoking OnSelected. Keep
the existing Enter/Space/Spacebar key check, but only call
OnSelected.InvokeAsync(Event) when the pressed key matches and !e.Repeat is true
so holding the key does not trigger multiple selections.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor`:
- Around line 25-45: The month fallback logic in BitFcTimelineMonthView should
be based on the validated resource ID set, not the raw resources collection
count. Update the hasUnassigned calculation to use resourceIds (the filtered
valid IDs) so that blank-ID resources still trigger the unassigned row when
there are no persistable resources. Keep the existing perResource and
_unassignedKey flow, but ensure the fallback row is shown whenever resourceIds
is empty.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cs`:
- Around line 84-97: The month slot defaults in OnSlotClickAsync currently use
DateTime.Now.Hour, which ties new events to the server/process clock instead of
the calendar context. Update the default hour selection in
BitFcTimelineMonthView.razor.cs to use a deterministic calendar-friendly value,
and apply it consistently both when creating the draft via
BitFullCalendarHelpers.CreateDraftEventForTimeSlot and when setting
_addStartHour for the add dialog path.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs`:
- Around line 534-633: The Persian localization in persianTexts is still missing
the aria labels for month navigation and attendee removal, so those strings fall
back to English. Add Persian translations for PreviousMonthAriaLabel,
NextMonthAriaLabel, and RemoveAttendeeAriaLabel in the BitFullCalendarTexts
initialization, and make the same updates in the copied sample/localization
block referenced by persianTexts so both demo paths stay consistent.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor`:
- Around line 62-65: The agenda row in BitFcAgendaEvents still uses a div as a
button, so replace the clickable agenda item container in the event rendering
logic with a semantic button element in BitFcAgendaEvents.razor and keep the
existing ShowDetails(ev) action wired through the button’s click handling.
Remove the custom keyboard handling tied to the div, since a real button in this
component will provide native Enter/Space behavior and accessible semantics
automatically; use the existing identifiers ShowDetails and OnItemKeyDown to
locate and simplify the interaction code.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cs`:
- Around line 111-121: The day-view render path in
BitFcCalendarDayView.OnAfterRenderAsync still depends on
BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync without guarding transient
JS lifecycle failures. Update the scroll call to safely handle
prerender/disconnect exceptions so the render does not fail, and keep
_timeGridScrollSignature unchanged unless the interop call completes
successfully. Use the existing OnAfterRenderAsync flow,
BuildTimeGridScrollSignature, and _timeGridScrollSignature to locate and adjust
the logic.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs`:
- Around line 96-106: The week-view scroll interop in
BitFcCalendarWeekView.OnAfterRenderAsync is still vulnerable to transient JS
lifecycle failures during disconnect or teardown. Update the OnAfterRenderAsync
flow to wrap the BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync call in
exception handling for transient JS/interoperability lifecycle errors, and only
assign _timeGridScrollSignature after the scroll completes successfully so
failed attempts can be retried on the next render.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 66-70: Replace the clickable year-day cell in
BitFcCalendarYearView.razor with a real button when hasEvents is true instead of
a focusable div with role="button". Update the branching around the cell
rendering so the interactive path uses a <button type="button"> and keeps the
existing click and keyboard handlers (ShowEventsForDay and OnDayKeyDown) on that
element, while the non-interactive path remains non-button markup. Ensure the
current month and hasEvents styling/classes are preserved on the new button.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor`:
- Around line 12-31: The overlap detection in BitFcRenderGroupedEvents.razor is
being recomputed during rendering for every event, which is too expensive for
dense day/week views. Move the conflict/position calculation out of the render
path by precomputing the needed layout metadata (such as depth/rank or lane
conflict counts) when GroupedEvents are built, and have the render block consume
that prepared data instead of rescanning every group in the loop.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: feaedd78-6a12-41aa-9d52-6c474dc63a2e
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (2)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor (1)
3-5: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winPolish the page metadata description.
The
<PageOutlet>description still reads awkwardly compared with the richerDemoPagecopy, and this is the user-facing meta description for the page.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor` around lines 3 - 5, The PageOutlet metadata description for the FullCalendar demo page reads awkwardly and should be polished to match the clearer DemoPage-style copy. Update the Description text in BitFullCalendarDemo.razor so it is more natural and user-facing, while keeping the existing PageOutlet, Url, and Title usage intact.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs (1)
96-107: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winWrap the scroll interop in transient-exception handling.
OnAfterRenderAsyncstill callsBitFcTimeGridScrollInterop.TryScrollToStartOfDayAsyncwithout guarding against JS lifecycle exceptions (disconnect/teardown). A throw here fails the render path.Suggested patch
- if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( - JS, - _timeGridScrollElementId, - State.StartOfDayHour)) - _timeGridScrollSignature = sig; + try + { + if (await BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync( + JS, + _timeGridScrollElementId, + State.StartOfDayHour)) + _timeGridScrollSignature = sig; + } + catch (Exception ex) when (ex is JSException or JSDisconnectedException or InvalidOperationException or OperationCanceledException) + { + // Transient renderer/JS lifecycle condition; retry on a later render. + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs` around lines 96 - 107, Wrap the scroll call in BitFcCalendarWeekView.OnAfterRenderAsync with transient JS lifecycle exception handling so disconnect/teardown errors do not fail rendering. Keep the existing signature check and call to BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync, but catch the expected JS interop lifecycle exceptions around that await and skip updating _timeGridScrollSignature when the scroll attempt fails transiently.
🧹 Nitpick comments (5)
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs (1)
534-636: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftAvoid maintaining the Persian text table twice.
The live
persianTextsobject andexample8RazorCodeduplicate the same large key set. Any future text addition has to be updated in both places, so the live demo and copied sample are likely to drift again. Consider generating the sample from a single source or extracting the shared initialization behind one helper.Also applies to: 807-914
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs` around lines 534 - 636, The Persian FullCalendar text mappings are duplicated between persianTexts and example8RazorCode, which will cause them to drift. Refactor the shared initialization into one reusable source, such as a helper or factory used by both the live demo and the sample, and update the BitFullCalendarDemo component so the text set is defined once and referenced from both places.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor (1)
14-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider adding
@keyto the week multi-day badge.The day-view counterpart keys each
BitFcMonthEventBadgewith@key="ev.Id". Here the badge is rendered without a key inside a positional@for/@foreach, so Blazor may reuse instances by position when the week's event layout shifts. Keying byev.Idkeeps this consistent with the day-view row and avoids potential instance reuse.Suggested change
- <BitFcMonthEventBadge Event="ev" CellDate="d" Position="`@position`" OnSelected="ShowEventDetails" EventTemplate="EventTemplate" /> + <BitFcMonthEventBadge `@key`="ev.Id" Event="ev" CellDate="d" Position="`@position`" OnSelected="ShowEventDetails" EventTemplate="EventTemplate" />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor` around lines 14 - 23, The week multi-day badge rendering in BitFcWeekViewMultiDayEventsRow.razor is missing a stable Blazor key, unlike the day-view badge. Update the BitFcMonthEventBadge inside the event row loop to use a unique `@key` based on ev.Id so instances are tracked by event identity instead of position. Keep the change aligned with the existing row logic around _cellLookup, evEndInclusive, and position so the week view behaves consistently when layout shifts.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cs (1)
16-22: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueOut-of-range handling differs from
BitFullCalendarState.
StartOfDayHourhere silently clamps to0–16(Line 20), whereasBitFullCalendarState.SetStartOfDayHoursilently rejects out-of-range values (Lines 135-136). A consumer passing e.g.20gets16via settings but no change via the setter, which is surprising. Consider clamping in both paths for consistent semantics.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cs` around lines 16 - 22, Make out-of-range handling for StartOfDayHour consistent between BitFullCalendarSettings and BitFullCalendarState. Update BitFullCalendarState.SetStartOfDayHour to clamp values to the same 0–16 range used by the StartOfDayHour property instead of ignoring invalid input, so both the settings model and the state setter behave the same way.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs (1)
235-239: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor: view clamp here is a no-op.
When falling back from
TimelinetoEvent, Line 238 callsClampViewForMode(View, Mode)withMode == Event, which returnsViewunchanged (Line 101-102). The assignment has no effect and can be dropped for clarity. Functionally harmless.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs` around lines 235 - 239, The fallback in BitFullCalendarState currently does an unnecessary view clamp when switching from BitFullCalendarMode.Timeline to BitFullCalendarMode.Event, because ClampViewForMode(View, Mode) is a no-op for Event. Update the Timeline fallback branch in BitFullCalendarState to only set Mode = BitFullCalendarMode.Event and remove the redundant View reassignment, keeping the logic clear and consistent with ClampViewForMode.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor (1)
5-23: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueOptional: reuse a cached timeline list instead of recomputing per render.
State.Events.ToList()on Line 7 allocates a new list on every render of the body, whereas the non-timeline branch consumes precomputed_singleDayEvents/_multiDayEvents. You could compute the timeline list once inComputeEvents()for consistency. Low impact since timeline render frequency is bounded.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor` around lines 5 - 23, The timeline branch in BitFcCalendarBody is allocating State.Events.ToList() on every render instead of reusing precomputed data like the _singleDayEvents and _multiDayEvents paths. Move the timeline list creation into ComputeEvents() in BitFcCalendarBody.razor and store it in a cached field, then have the timeline view switch use that cached list so the render path avoids repeated allocations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scss`:
- Around line 1631-1640: The user-select dropdown is still hard-coded to align
with right: 0, so it doesn’t mirror in RTL like the settings menu. Update the
`.bit-bfc-user-select-menu` styles in `BitFullCalendar.scss` to include the same
RTL override pattern used by the settings dropdown, using the existing
FullCalendar RTL selector/block so the menu opens toward the correct side in
both directions.
- Around line 734-737: The day sidebar separator in BitFullCalendar.scss uses a
physical left border, which is wrong when `[dir="rtl"] .bit-bfc-day-layout`
flips the sidebar position. Update the `.bit-bfc-day-sidebar` styling to use a
logical border so the separator stays between the sidebar and the main grid in
both LTR and RTL layouts, and verify any RTL-specific overrides in the
FullCalendar styles still align with the sidebar placement.
- Around line 1333-1335: The selected-day style in BitFullCalendar.scss uses a
hard-coded white foreground instead of the calendar’s primary-text token, which
makes it inconsistent with the other primary states. Update the
.bit-bfc-dtp-day-selected rule to use --bit-bfc-primary-text for the text color
while keeping --bit-bfc-primary as the background, matching the existing primary
styling conventions in the FullCalendar SCSS.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cs`:
- Around line 20-24: The edit-close flow in BitFcEventDetailsDialog is closing
the parent details dialog too early, since OnEditClose currently hides the edit
dialog and also invokes OnClose. Update OnEditClose so it only dismisses the
edit overlay locally, and introduce or wire a separate success path from
BitFcAddEditEventDialog for save/confirm actions that should close the details
dialog. Keep the parent OnClose callback reserved for the actual details-dialog
dismissal behavior.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor`:
- Around line 30-39: Separate the synthetic unassigned row state from the actual
grouped unassigned lanes in BitFcTimelineDayView.razor: hasUnassigned should
only describe whether the UI needs an unassigned row, but the height calculation
in BitFcTimelineLayout and the related lane rendering logic must not index
grouped[_unassignedKey] unless that key actually exists. Update the unassigned
row height/LaneCountFor path to safely handle the empty-calendar case
(resourceIds.Count == 0) by using a fallback count when _unassignedKey is
absent.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Around line 113-149: The BitFullCalendar demo currently allows unsupported
combinations by binding bindingView and bindingMode independently, so users can
select BitFullCalendarView.Year or BitFullCalendarView.Agenda and then switch to
BitFullCalendarMode.Timeline even though the timeline implementation only
supports day/week/month. Update the BitFullCalendarDemo.razor logic around the
BitChoiceGroup controls and the HandleModeChange/HandleViewChange flow so
Timeline only exposes supported views, or automatically coerce bindingView back
to a valid BitFullCalendarView when bindingMode becomes Timeline.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cs`:
- Around line 96-107: Wrap the scroll call in
BitFcCalendarWeekView.OnAfterRenderAsync with transient JS lifecycle exception
handling so disconnect/teardown errors do not fail rendering. Keep the existing
signature check and call to
BitFcTimeGridScrollInterop.TryScrollToStartOfDayAsync, but catch the expected JS
interop lifecycle exceptions around that await and skip updating
_timeGridScrollSignature when the scroll attempt fails transiently.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor`:
- Around line 3-5: The PageOutlet metadata description for the FullCalendar demo
page reads awkwardly and should be polished to match the clearer DemoPage-style
copy. Update the Description text in BitFullCalendarDemo.razor so it is more
natural and user-facing, while keeping the existing PageOutlet, Url, and Title
usage intact.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor`:
- Around line 5-23: The timeline branch in BitFcCalendarBody is allocating
State.Events.ToList() on every render instead of reusing precomputed data like
the _singleDayEvents and _multiDayEvents paths. Move the timeline list creation
into ComputeEvents() in BitFcCalendarBody.razor and store it in a cached field,
then have the timeline view switch use that cached list so the render path
avoids repeated allocations.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cs`:
- Around line 16-22: Make out-of-range handling for StartOfDayHour consistent
between BitFullCalendarSettings and BitFullCalendarState. Update
BitFullCalendarState.SetStartOfDayHour to clamp values to the same 0–16 range
used by the StartOfDayHour property instead of ignoring invalid input, so both
the settings model and the state setter behave the same way.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 235-239: The fallback in BitFullCalendarState currently does an
unnecessary view clamp when switching from BitFullCalendarMode.Timeline to
BitFullCalendarMode.Event, because ClampViewForMode(View, Mode) is a no-op for
Event. Update the Timeline fallback branch in BitFullCalendarState to only set
Mode = BitFullCalendarMode.Event and remove the redundant View reassignment,
keeping the logic clear and consistent with ClampViewForMode.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor`:
- Around line 14-23: The week multi-day badge rendering in
BitFcWeekViewMultiDayEventsRow.razor is missing a stable Blazor key, unlike the
day-view badge. Update the BitFcMonthEventBadge inside the event row loop to use
a unique `@key` based on ev.Id so instances are tracked by event identity instead
of position. Keep the change aligned with the existing row logic around
_cellLookup, evEndInclusive, and position so the week view behaves consistently
when layout shifts.
In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cs`:
- Around line 534-636: The Persian FullCalendar text mappings are duplicated
between persianTexts and example8RazorCode, which will cause them to drift.
Refactor the shared initialization into one reusable source, such as a helper or
factory used by both the live demo and the sample, and update the
BitFullCalendarDemo component so the text set is defined once and referenced
from both places.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d72986f1-34ac-46e4-b0b0-62765d446458
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
|
@coderabbitai re-review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 11
♻️ Duplicate comments (5)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cs (1)
10-10: 🎯 Functional Correctness | 🟠 MajorTrack the calendar implementation in the sync key, not just
CultureInfo.Name.This still misses culture changes that keep the same name but swap
State.Culture.Calendar, so the mini-calendar can keep the old month normalization even thoughStartOfDisplayMonth()now resolves through a different calendar.Suggested fix
- private string? _lastSyncedCultureName; + private string? _lastSyncedCultureKey; @@ - _lastSyncedCultureName = State.Culture.Name; + _lastSyncedCultureKey = $"{State.Culture.Name}|{State.Culture.Calendar.GetType().FullName}"; @@ - || !string.Equals(_lastSyncedCultureName, State.Culture.Name, StringComparison.Ordinal)) + || !string.Equals(_lastSyncedCultureKey, $"{State.Culture.Name}|{State.Culture.Calendar.GetType().FullName}", StringComparison.Ordinal)) { _lastSyncedSelectedDate = State.SelectedDate; - _lastSyncedCultureName = State.Culture.Name; + _lastSyncedCultureKey = $"{State.Culture.Name}|{State.Culture.Calendar.GetType().FullName}"; _displayMonth = StartOfDisplayMonth(State.SelectedDate); }Also applies to: 25-30
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cs` at line 10, The mini-calendar sync key only tracks CultureInfo.Name, so it can miss changes where the culture name stays the same but State.Culture.Calendar changes and month normalization becomes stale. Update the sync tracking in BitFcMiniCalendar to include the calendar implementation alongside the culture name, and use that expanded key wherever _lastSyncedCultureName is compared or assigned so the sync logic reruns when the calendar type changes.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor (1)
17-24: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winInclude dates in the badge’s accessible name.
The new
aria-labelstill omits the event dates, so multi-day/overnight badges can be announced as an ambiguous time range only. Include the start/end dates in the label as well.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor` around lines 17 - 24, The accessible name built in BitFcMonthEventBadge.razor via badgeAriaLabel only includes the event title and times, so update that label to also include the start and end dates for Event.StartDate and Event.EndDate, using the existing BitFullCalendarHelpers formatting patterns and State.Culture/State.Use24HourFormat. Keep the aria-label on the badge element in sync so multi-day and overnight events are announced with both dates and times.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cs (1)
3-3: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winImplement
IDisposableon the component class.Line 3 defines a component with a
Dispose()method (Line 29) but noIDisposableimplementation, so Blazor won’t invoke that cleanup automatically andState.OnStateChangedcan remain subscribed.Suggested fix
-public partial class BitFcCalendarHeader +public partial class BitFcCalendarHeader : IDisposable#!/bin/bash # Verify class declaration and disposal pattern in this file. cat -n src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cs | sed -n '1,40p' rg -n "class BitFcCalendarHeader|OnStateChanged \+=|Dispose\(" src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.csAlso applies to: 27-29
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cs` at line 3, The component class BitFcCalendarHeader currently defines a Dispose() cleanup method but does not implement IDisposable, so Blazor will not automatically call it; update the class declaration to implement IDisposable and keep the existing Dispose logic so the State.OnStateChanged subscription is always removed. Verify the disposal pattern around BitFcCalendarHeader and its Dispose method remains intact, and ensure any related subscription setup in the component is matched by the IDisposable cleanup path.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs (1)
8-9: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winReject inverted event ranges at the model boundary.
StartDateandEndDatestill allowEndDate < StartDate. That makesDurationnegative on Line 36, andsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs:443-454reuses that duration when rebuilding dropped events, so one invalid model instance can propagate broken dates. Validate the invariant in the setters (or a shared validator) instead of relying on downstream code.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs` around lines 8 - 9, BitFullCalendarEvent currently allows an invalid range where EndDate is earlier than StartDate, which can produce a negative Duration and later break event rebuilding in BitFullCalendarState. Add validation at the model boundary by enforcing the StartDate/EndDate invariant in the BitFullCalendarEvent property setters or a shared validator, and reject or normalize any inverted range before the object can be used downstream.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cs (1)
3-35: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winImplement
IDisposableon the component type.
Dispose()unsubscribesState.OnStateChanged, but Blazor won't call it unless the component implementsIDisposable. That leaves the subscription alive after teardown and can keep invokingRefreshon a disposed component.Suggested fix
-public partial class BitFcCalendarBody +public partial class BitFcCalendarBody : IDisposable🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cs` around lines 3 - 35, BitFcCalendarBody currently unsubscribes in Dispose() but never declares IDisposable, so Blazor won’t invoke teardown cleanup. Update the BitFcCalendarBody component type to implement IDisposable, keeping the existing Dispose() method so State.OnStateChanged is unsubscribed when the component is disposed. Ensure the change is applied on the BitFcCalendarBody partial class alongside OnInitialized, Refresh, and ComputeEvents.
🧹 Nitpick comments (2)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs (1)
470-473: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract the exclusive-end normalization into one helper.
The midnight-exclusive adjustment is now copy-pasted in three overlap helpers. Centralizing it will keep future date-overlap fixes from drifting again.
♻️ Proposed refactor
+ private static DateTime InclusiveEndDate(BitFullCalendarEvent ev) + => (ev.EndDate > ev.StartDate ? ev.EndDate.AddTicks(-1) : ev.EndDate).Date; + ... - var evEnd = (ev.EndDate > ev.StartDate ? ev.EndDate.AddTicks(-1) : ev.EndDate).Date; + var evEnd = InclusiveEndDate(ev); ... - var e = (ev.EndDate > ev.StartDate ? ev.EndDate.AddTicks(-1) : ev.EndDate).Date; + var e = InclusiveEndDate(ev); ... - var e = (ev.EndDate > ev.StartDate ? ev.EndDate.AddTicks(-1) : ev.EndDate).Date; + var e = InclusiveEndDate(ev);Also applies to: 516-520, 588-590
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs` around lines 470 - 473, The midnight-exclusive end-date normalization is duplicated across the overlap helpers, so extract that logic into a single shared helper in BitFullCalendarHelpers and use it wherever ev.EndDate is adjusted. Update the overlap checks that currently inline the AddTicks(-1) and Date handling so they all call the same helper, keeping IsSingleDay, GroupEventsByDayRange, and the other overlap methods consistent.src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs (1)
33-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winEncapsulate drag state mutations.
DraggedEventis publicly settable, so any caller can bypassStartDrag/EndDragand skipNotifyStateChanged(). Making the setter private keeps drag state transitions consistent.Suggested patch
- public BitFullCalendarEvent? DraggedEvent { get; set; } + public BitFullCalendarEvent? DraggedEvent { get; private set; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs` at line 33, The drag state in BitFullCalendarState is too exposed because DraggedEvent can be set directly, bypassing StartDrag and EndDrag and skipping NotifyStateChanged. Make the DraggedEvent setter private so only the state transition methods control it, and keep all drag mutations routed through StartDrag/EndDrag to preserve consistent notifications.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`:
- Around line 307-312: Guard the storage helpers in BitFullCalendar against
DOMException by wrapping getLocalStorage and setLocalStorage in try/catch, since
localStorage.getItem/setItem can throw when storage is blocked or unavailable.
Update getLocalStorage to return null on failure and make setLocalStorage a
no-op on failure so the JS interop path degrades cleanly without breaking
preference initialization.
- Around line 207-213: Serialize resize sessions per event instead of per handle
by moving the active-resize guard in BitFullCalendar.ts from the element-local
pointer flag to a shared per-dotNetRef tracker, since
BitFcTimelineEventBlock.razor.cs wires both handles to the same dotNetRef.
Update the pointerdown/pointermove/pointerup flow in the resize logic so only
one resize can run at a time for a given event across both handles, and ensure
the shared tracking is cleared after resize end/cancel.
- Around line 130-159: The async resize lifecycle in FullCalendar can still
surface unhandled promise rejections because `endResize` is used directly as a
DOM listener and also replayed from the deferred `pointerdown` flow. Update the
listener entry points around `endResize`, the deferred replay path, and the
related resize handlers mentioned in the comment to use non-async wrappers that
call the async work via `void ...catch(...)`, while keeping the existing cleanup
and `OnResizeMove`/`OnResizeEnd` sequencing intact.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cs`:
- Around line 138-185: The Submit flow in BitFcAddEditEventDialog is re-entrant
and can be invoked twice before the dialog closes, causing duplicate add/edit
operations. Add an _isSubmitting guard inside Submit so repeated clicks/Enter
return early while a save is in progress, and make sure the flag is set before
the event/state update work and cleared afterward. Also wire the primary action
in this dialog to respect that flag so the save button is disabled during the
in-flight Submit path.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor`:
- Around line 3-13: The view switcher in BitFcViewTabs should expose the
selected state to assistive technologies. Update the container in the tabs
markup to behave like a tablist, and give each button in the `@foreach` over
_views a tab role plus an aria-selected state based on State.View == view, or
refactor to reuse an existing tabs component with the same semantics. Keep the
existing click behavior via State.SetView(view) and preserve the timeline
filtering logic.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Around line 80-97: SetMode in BitFullCalendarState currently always calls
NotifyDateRangeChanged after updating Mode and possibly clamping View, which can
trigger OnDateChange even when the visible date range did not change. Update the
SetMode flow to compare the previously reported range against the new
Start/End/View state and only invoke NotifyDateRangeChanged when that range
actually differs, keeping the visible-range callback behavior aligned with the
BitFullCalendar.razor.cs contract.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor`:
- Around line 34-42: The hour slot div in BitFcCalendarDayView.razor behaves
like a button, but the current OnHourKeyDownAsync key handler still allows Space
to scroll the page. Update the keyboard handler binding on the pseudo-button
element to use a prevent-default modifier so Space activates the slot without
page scrolling, while keeping the existing OnHourKeyDownAsync behavior intact.
- Around line 8-9: The “Happening now” list in BitFcCalendarDayView only uses
SingleDayEvents, so multi-day events are missed while still active. Update the
currentEvents selection logic in the day view to include any in-progress events
from the multi-day events source as well as single-day events, using the
existing DateTime.Now range check against StartDate and EndDate. Keep the change
localized to the currentEvents computation in BitFcCalendarDayView so the
sidebar shows all currently ongoing events.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor`:
- Around line 8-15: The month day cell in BitFcDayCell is incorrectly exposed as
a full button-like container while it also hosts separate interactive controls
such as BitFcMonthEventBadge and the “more events” trigger, causing nested
interactive semantics. Update the DayCell markup and related click/keyboard
handlers so the outer cell is just a non-button container, and move the
add-event action to a dedicated control or overlay that is separately focusable
and clickable. Make the same accessibility/interaction adjustment in the other
affected sections of BitFcDayCell where the cell wrapper currently behaves like
a button.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`:
- Around line 66-80: The resize initialization in OnAfterRenderAsync can
partially succeed, leaving one handle registered while _resizeInitialized
remains false, which causes duplicate listeners on later renders. Update
BitFcTimelineEventBlock.razor.cs so the start and end handle initialization in
BitBlazorUI.FullCalendar.initResizeHorizontal is tracked separately or marked as
initialized per handle, and only retry the missing side instead of
re-registering both when one call has already succeeded. Keep the existing
exception handling, but ensure partial success does not reattach listeners on an
already-initialized handle.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`:
- Around line 68-77: The year-day button content in BitFcCalendarYearView
currently includes an invalid block-level wrapper inside the button, so update
the button’s children to use valid button content only. In the year-day
rendering block that contains ShowEventsForDay and the bit-bfc-year-day-bullets
markup, replace the inner div with inline-compatible content or a span-based
wrapper so the button remains semantically valid and accessible.
---
Duplicate comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cs`:
- Around line 3-35: BitFcCalendarBody currently unsubscribes in Dispose() but
never declares IDisposable, so Blazor won’t invoke teardown cleanup. Update the
BitFcCalendarBody component type to implement IDisposable, keeping the existing
Dispose() method so State.OnStateChanged is unsubscribed when the component is
disposed. Ensure the change is applied on the BitFcCalendarBody partial class
alongside OnInitialized, Refresh, and ComputeEvents.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cs`:
- Line 3: The component class BitFcCalendarHeader currently defines a Dispose()
cleanup method but does not implement IDisposable, so Blazor will not
automatically call it; update the class declaration to implement IDisposable and
keep the existing Dispose logic so the State.OnStateChanged subscription is
always removed. Verify the disposal pattern around BitFcCalendarHeader and its
Dispose method remains intact, and ensure any related subscription setup in the
component is matched by the IDisposable cleanup path.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cs`:
- Around line 8-9: BitFullCalendarEvent currently allows an invalid range where
EndDate is earlier than StartDate, which can produce a negative Duration and
later break event rebuilding in BitFullCalendarState. Add validation at the
model boundary by enforcing the StartDate/EndDate invariant in the
BitFullCalendarEvent property setters or a shared validator, and reject or
normalize any inverted range before the object can be used downstream.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cs`:
- Line 10: The mini-calendar sync key only tracks CultureInfo.Name, so it can
miss changes where the culture name stays the same but State.Culture.Calendar
changes and month normalization becomes stale. Update the sync tracking in
BitFcMiniCalendar to include the calendar implementation alongside the culture
name, and use that expanded key wherever _lastSyncedCultureName is compared or
assigned so the sync logic reruns when the calendar type changes.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor`:
- Around line 17-24: The accessible name built in BitFcMonthEventBadge.razor via
badgeAriaLabel only includes the event title and times, so update that label to
also include the start and end dates for Event.StartDate and Event.EndDate,
using the existing BitFullCalendarHelpers formatting patterns and
State.Culture/State.Use24HourFormat. Keep the aria-label on the badge element in
sync so multi-day and overnight events are announced with both dates and times.
---
Nitpick comments:
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cs`:
- Around line 470-473: The midnight-exclusive end-date normalization is
duplicated across the overlap helpers, so extract that logic into a single
shared helper in BitFullCalendarHelpers and use it wherever ev.EndDate is
adjusted. Update the overlap checks that currently inline the AddTicks(-1) and
Date handling so they all call the same helper, keeping IsSingleDay,
GroupEventsByDayRange, and the other overlap methods consistent.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cs`:
- Line 33: The drag state in BitFullCalendarState is too exposed because
DraggedEvent can be set directly, bypassing StartDrag and EndDrag and skipping
NotifyStateChanged. Make the DraggedEvent setter private so only the state
transition methods control it, and keep all drag mutations routed through
StartDrag/EndDrag to preserve consistent notifications.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: a35d24ec-b6fc-48c2-b0db-a42976d0be7e
📒 Files selected for processing (100)
src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarBody.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFcCalendarToast.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.scsssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.tssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcDateTimePicker.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventDetailsDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcEventListDialog.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDraggableEvent.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/DragDrop/BitFcDroppableArea.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarAgendaGroupBy.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarBadgeVariant.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarEventLayout.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarMode.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Enums/BitFullCalendarView.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcCalendarHeader.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcDateNavigator.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcFilterEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcModeTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcSettings.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcTodayButton.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarAttendee.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarCell.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorOption.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarColorScheme.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarDateChangeEventArgs.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarEvent.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarResource.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarSettings.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Models/BitFullCalendarTexts.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcAgendaScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimeGridScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFcTimelineScrollInterop.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarChangeNotifier.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarHelpers.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Services/BitFullCalendarState.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/AgendaView/BitFcAgendaEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarTimeline.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcDayViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcMiniCalendar.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcRenderGroupedEvents.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcTimeColumn.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcWeekViewMultiDayEventsRow.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcCalendarMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcEventBullet.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcMonthEventBadge.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineDayView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineLayout.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineMonthView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineWeekView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razorsrc/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor.cssrc/BlazorUI/Bit.BlazorUI.Extras/Styles/extra-components.scsssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Extras/FullCalendar/BitFullCalendarDemo.razor.cssrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Home/ComponentsSection.razorsrc/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Shared/MainLayout.razor.NavItems.cs
| const endResize = async (ev?: PointerEvent) => { | ||
| if (ev && activePointerId != null && ev.pointerId !== activePointerId) return; | ||
| // A pointer release before resize-start completes is deferred and replayed afterwards. | ||
| // Capture the release coordinate now so the replayed delta reflects where the pointer | ||
| // actually was, even when no move event fired between deferral and replay. | ||
| if (!startSucceeded) { if (ev) latestY = ev.clientY; pendingEnd = true; return; } | ||
| if (ended) return; | ||
| ended = true; | ||
| document.removeEventListener("pointermove", onPointerMove); | ||
| document.removeEventListener("pointerup", endResize); | ||
| document.removeEventListener("pointercancel", endResize); | ||
|
|
||
| if (rafId != null) { | ||
| cancelAnimationFrame(rafId); | ||
| rafId = null; | ||
| } | ||
| const deltaMinutes = Math.round((latestY - startY) * minPerPixel); | ||
|
|
||
| try { | ||
| await dotNetRef.invokeMethodAsync("OnResizeMove", direction, deltaMinutes); | ||
| } finally { | ||
| try { | ||
| if (activePointerId != null && typeof el.releasePointerCapture === "function") | ||
| el.releasePointerCapture(activePointerId); | ||
| } catch { } | ||
|
|
||
| activePointerId = null; | ||
| activeResizePointerId = null; | ||
| await dotNetRef.invokeMethodAsync("OnResizeEnd"); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Catch rejected async resize-end calls.
endResize is registered directly as an async DOM listener and is also replayed from the async pointerdown handler. If OnResizeMove or OnResizeEnd rejects here, the browser drops the returned promise and you still get an unhandled rejection even though cleanup already ran. Wrap the listener entry points in non-async callbacks that void ...catch(...), and apply the same catch to the deferred replay path.
Also applies to: 184-185, 244-273, 298-299
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`
around lines 130 - 159, The async resize lifecycle in FullCalendar can still
surface unhandled promise rejections because `endResize` is used directly as a
DOM listener and also replayed from the deferred `pointerdown` flow. Update the
listener entry points around `endResize`, the deferred replay path, and the
related resize handlers mentioned in the comment to use non-async wrappers that
call the async work via `void ...catch(...)`, while keeping the existing cleanup
and `OnResizeMove`/`OnResizeEnd` sequencing intact.
| // Tracks the pointer that owns the in-progress resize so a second concurrent pointer | ||
| // (e.g. a second touch contact) can't start an overlapping resize on the same element. | ||
| let activeResizePointerId: number | null = null; | ||
|
|
||
| el.addEventListener("pointerdown", async (e: PointerEvent) => { | ||
| if (e.button !== 0) return; | ||
| if (activeResizePointerId !== null) return; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Serialize resize sessions per event, not per handle.
This lock is local to one handle element, but src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs:73-74 wires both the start and end handles with the same dotNetRef. Two touch points can still start overlapping resize sessions for one event and interleave OnResizeStart/Move/End. Track the active resize against the shared dotNetRef (for example with a WeakSet) instead of only this element-local flag.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`
around lines 207 - 213, Serialize resize sessions per event instead of per
handle by moving the active-resize guard in BitFullCalendar.ts from the
element-local pointer flag to a shared per-dotNetRef tracker, since
BitFcTimelineEventBlock.razor.cs wires both handles to the same dotNetRef.
Update the pointerdown/pointermove/pointerup flow in the resize logic so only
one resize can run at a time for a given event across both handles, and ensure
the shared tracking is cleared after resize end/cancel.
| public static getLocalStorage(key: string): string | null { | ||
| return localStorage.getItem(key); | ||
| } | ||
|
|
||
| public static setLocalStorage(key: string, value: string) { | ||
| localStorage.setItem(key, value); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Guard storage access against DOMException.
localStorage.getItem/setItem can throw when storage is blocked, unavailable, or quota-exceeded. Right now that would fail the JS interop call and can break preference initialization. Return null / no-op from a try/catch here so the calendar degrades cleanly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/BitFullCalendar.ts`
around lines 307 - 312, Guard the storage helpers in BitFullCalendar against
DOMException by wrapping getLocalStorage and setLocalStorage in try/catch, since
localStorage.getItem/setItem can throw when storage is blocked or unavailable.
Update getLocalStorage to return null on failure and make setLocalStorage a
no-op on failure so the JS interop path degrades cleanly without breaking
preference initialization.
| private async Task Submit() | ||
| { | ||
| _errors.Clear(); | ||
| if (string.IsNullOrWhiteSpace(_title)) | ||
| _errors["title"] = Texts.ValidationTitleRequired; | ||
| if (string.IsNullOrWhiteSpace(_description)) | ||
| _errors["description"] = Texts.ValidationDescriptionRequired; | ||
| if (_endDate <= _startDate) | ||
| _errors["endDate"] = Texts.ValidationEndAfterStart; | ||
|
|
||
| if (_errors.Count > 0) return; | ||
|
|
||
| var oldSnapshot = _isEditing && ExistingEvent is not null | ||
| ? BitFullCalendarChangeNotifier.CloneEvent(ExistingEvent) | ||
| : null; | ||
|
|
||
| var ev = new BitFullCalendarEvent | ||
| { | ||
| Id = _isEditing ? ExistingEvent!.Id : Guid.NewGuid().ToString("N"), | ||
| Title = _title, | ||
| Description = _description, | ||
| StartDate = _startDate, | ||
| EndDate = _endDate, | ||
| Color = _color, | ||
| Resource = _isEditing ? ExistingEvent!.Resource : Resource, | ||
| Data = _isEditing ? ExistingEvent!.Data : null, | ||
| Attendees = [.. _attendees] | ||
| }; | ||
|
|
||
| if (_isEditing) | ||
| State.UpdateEvent(ev); | ||
| else | ||
| State.AddEvent(ev); | ||
|
|
||
| await Notifier.NotifyAsync(new BitFullCalendarChangeEventArgs | ||
| { | ||
| Event = BitFullCalendarChangeNotifier.CloneEvent(ev), | ||
| OldEvent = oldSnapshot, | ||
| Kind = _isEditing ? BitFullCalendarChangeKind.Edit : BitFullCalendarChangeKind.Add, | ||
| Source = BitFullCalendarChangeSource.Dialog | ||
| }); | ||
|
|
||
| // Prefer the dedicated success path when provided (e.g. the details dialog closes itself | ||
| // only on a real save), otherwise fall back to OnClose for standalone add/edit usages. | ||
| if (OnSaved.HasDelegate) | ||
| await OnSaved.InvokeAsync(); | ||
| else | ||
| await OnClose.InvokeAsync(); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Guard Submit against re-entry.
A double-click or repeated Enter can run Submit twice before the dialog closes. In add mode that creates two different ids and calls State.AddEvent(ev) twice, so the same draft is duplicated in calendar state. Add an _isSubmitting guard here and disable the primary action while the first save is in flight.
Suggested fix
+ private bool _isSubmitting;
+
private async Task Submit()
{
+ if (_isSubmitting) return;
+ _isSubmitting = true;
+
+ try
+ {
_errors.Clear();
if (string.IsNullOrWhiteSpace(_title))
_errors["title"] = Texts.ValidationTitleRequired;
if (string.IsNullOrWhiteSpace(_description))
_errors["description"] = Texts.ValidationDescriptionRequired;
if (_endDate <= _startDate)
_errors["endDate"] = Texts.ValidationEndAfterStart;
- if (_errors.Count > 0) return;
+ if (_errors.Count > 0) return;
- var oldSnapshot = _isEditing && ExistingEvent is not null
- ? BitFullCalendarChangeNotifier.CloneEvent(ExistingEvent)
- : null;
+ var oldSnapshot = _isEditing && ExistingEvent is not null
+ ? BitFullCalendarChangeNotifier.CloneEvent(ExistingEvent)
+ : null;
- var ev = new BitFullCalendarEvent
- {
- Id = _isEditing ? ExistingEvent!.Id : Guid.NewGuid().ToString("N"),
- Title = _title,
- Description = _description,
- StartDate = _startDate,
- EndDate = _endDate,
- Color = _color,
- Resource = _isEditing ? ExistingEvent!.Resource : Resource,
- Data = _isEditing ? ExistingEvent!.Data : null,
- Attendees = [.. _attendees]
- };
+ var ev = new BitFullCalendarEvent
+ {
+ Id = _isEditing ? ExistingEvent!.Id : Guid.NewGuid().ToString("N"),
+ Title = _title,
+ Description = _description,
+ StartDate = _startDate,
+ EndDate = _endDate,
+ Color = _color,
+ Resource = _isEditing ? ExistingEvent!.Resource : Resource,
+ Data = _isEditing ? ExistingEvent!.Data : null,
+ Attendees = [.. _attendees]
+ };
- if (_isEditing)
- State.UpdateEvent(ev);
- else
- State.AddEvent(ev);
+ if (_isEditing)
+ State.UpdateEvent(ev);
+ else
+ State.AddEvent(ev);
- await Notifier.NotifyAsync(new BitFullCalendarChangeEventArgs
- {
- Event = BitFullCalendarChangeNotifier.CloneEvent(ev),
- OldEvent = oldSnapshot,
- Kind = _isEditing ? BitFullCalendarChangeKind.Edit : BitFullCalendarChangeKind.Add,
- Source = BitFullCalendarChangeSource.Dialog
- });
+ await Notifier.NotifyAsync(new BitFullCalendarChangeEventArgs
+ {
+ Event = BitFullCalendarChangeNotifier.CloneEvent(ev),
+ OldEvent = oldSnapshot,
+ Kind = _isEditing ? BitFullCalendarChangeKind.Edit : BitFullCalendarChangeKind.Add,
+ Source = BitFullCalendarChangeSource.Dialog
+ });
- if (OnSaved.HasDelegate)
- await OnSaved.InvokeAsync();
- else
- await OnClose.InvokeAsync();
+ if (OnSaved.HasDelegate)
+ await OnSaved.InvokeAsync();
+ else
+ await OnClose.InvokeAsync();
+ }
+ finally
+ {
+ _isSubmitting = false;
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private async Task Submit() | |
| { | |
| _errors.Clear(); | |
| if (string.IsNullOrWhiteSpace(_title)) | |
| _errors["title"] = Texts.ValidationTitleRequired; | |
| if (string.IsNullOrWhiteSpace(_description)) | |
| _errors["description"] = Texts.ValidationDescriptionRequired; | |
| if (_endDate <= _startDate) | |
| _errors["endDate"] = Texts.ValidationEndAfterStart; | |
| if (_errors.Count > 0) return; | |
| var oldSnapshot = _isEditing && ExistingEvent is not null | |
| ? BitFullCalendarChangeNotifier.CloneEvent(ExistingEvent) | |
| : null; | |
| var ev = new BitFullCalendarEvent | |
| { | |
| Id = _isEditing ? ExistingEvent!.Id : Guid.NewGuid().ToString("N"), | |
| Title = _title, | |
| Description = _description, | |
| StartDate = _startDate, | |
| EndDate = _endDate, | |
| Color = _color, | |
| Resource = _isEditing ? ExistingEvent!.Resource : Resource, | |
| Data = _isEditing ? ExistingEvent!.Data : null, | |
| Attendees = [.. _attendees] | |
| }; | |
| if (_isEditing) | |
| State.UpdateEvent(ev); | |
| else | |
| State.AddEvent(ev); | |
| await Notifier.NotifyAsync(new BitFullCalendarChangeEventArgs | |
| { | |
| Event = BitFullCalendarChangeNotifier.CloneEvent(ev), | |
| OldEvent = oldSnapshot, | |
| Kind = _isEditing ? BitFullCalendarChangeKind.Edit : BitFullCalendarChangeKind.Add, | |
| Source = BitFullCalendarChangeSource.Dialog | |
| }); | |
| // Prefer the dedicated success path when provided (e.g. the details dialog closes itself | |
| // only on a real save), otherwise fall back to OnClose for standalone add/edit usages. | |
| if (OnSaved.HasDelegate) | |
| await OnSaved.InvokeAsync(); | |
| else | |
| await OnClose.InvokeAsync(); | |
| private bool _isSubmitting; | |
| private async Task Submit() | |
| { | |
| if (_isSubmitting) return; | |
| _isSubmitting = true; | |
| try | |
| { | |
| _errors.Clear(); | |
| if (string.IsNullOrWhiteSpace(_title)) | |
| _errors["title"] = Texts.ValidationTitleRequired; | |
| if (string.IsNullOrWhiteSpace(_description)) | |
| _errors["description"] = Texts.ValidationDescriptionRequired; | |
| if (_endDate <= _startDate) | |
| _errors["endDate"] = Texts.ValidationEndAfterStart; | |
| if (_errors.Count > 0) return; | |
| - var oldSnapshot = _isEditing && ExistingEvent is not null | |
| - ? BitFullCalendarChangeNotifier.CloneEvent(ExistingEvent) | |
| var oldSnapshot = _isEditing && ExistingEvent is not null | |
| ? BitFullCalendarChangeNotifier.CloneEvent(ExistingEvent) | |
| : null; | |
| - var ev = new BitFullCalendarEvent | |
| - { | |
| - Id = _isEditing ? ExistingEvent!.Id : Guid.NewGuid().ToString("N"), | |
| - Title = _title, | |
| - Description = _description, | |
| - StartDate = _startDate, | |
| - EndDate = _endDate, | |
| - Color = _color, | |
| - Resource = _isEditing ? ExistingEvent!.Resource : Resource, | |
| - Data = _isEditing ? ExistingEvent!.Data : null, | |
| - Attendees = [.. _attendees] | |
| var ev = new BitFullCalendarEvent | |
| { | |
| Id = _isEditing ? ExistingEvent!.Id : Guid.NewGuid().ToString("N"), | |
| Title = _title, | |
| Description = _description, | |
| StartDate = _startDate, | |
| EndDate = _endDate, | |
| Color = _color, | |
| Resource = _isEditing ? ExistingEvent!.Resource : Resource, | |
| Data = _isEditing ? ExistingEvent!.Data : null, | |
| Attendees = [.. _attendees] | |
| }; | |
| - if (_isEditing) | |
| - State.UpdateEvent(ev); | |
| - else | |
| if (_isEditing) | |
| State.UpdateEvent(ev); | |
| else | |
| State.AddEvent(ev); | |
| - await Notifier.NotifyAsync(new BitFullCalendarChangeEventArgs | |
| - { | |
| - Event = BitFullCalendarChangeNotifier.CloneEvent(ev), | |
| - OldEvent = oldSnapshot, | |
| - Kind = _isEditing ? BitFullCalendarChangeKind.Edit : BitFullCalendarChangeKind.Add, | |
| - Source = BitFullCalendarChangeSource.Dialog | |
| await Notifier.NotifyAsync(new BitFullCalendarChangeEventArgs | |
| { | |
| Event = BitFullCalendarChangeNotifier.CloneEvent(ev), | |
| OldEvent = oldSnapshot, | |
| Kind = _isEditing ? BitFullCalendarChangeKind.Edit : BitFullCalendarChangeKind.Add, | |
| Source = BitFullCalendarChangeSource.Dialog | |
| }); | |
| - // Prefer the dedicated success path when provided (e.g. the details dialog closes itself | |
| - // only on a real save), otherwise fall back to OnClose for standalone add/edit usages. | |
| - if (OnSaved.HasDelegate) | |
| - await OnSaved.InvokeAsync(); | |
| - else | |
| // Prefer the dedicated success path when provided (e.g. the details dialog closes itself | |
| // only on a real save), otherwise fall back to OnClose for standalone add/edit usages. | |
| if (OnSaved.HasDelegate) | |
| await OnSaved.InvokeAsync(); | |
| else | |
| await OnClose.InvokeAsync(); | |
| } | |
| finally | |
| { | |
| _isSubmitting = false; | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Dialogs/BitFcAddEditEventDialog.razor.cs`
around lines 138 - 185, The Submit flow in BitFcAddEditEventDialog is re-entrant
and can be invoked twice before the dialog closes, causing duplicate add/edit
operations. Add an _isSubmitting guard inside Submit so repeated clicks/Enter
return early while a save is in progress, and make sure the flag is set before
the event/state update work and cleared afterward. Also wire the primary action
in this dialog to respect that flag so the save button is disabled during the
in-flight Submit path.
| <div class="bit-bfc-view-tabs"> | ||
| @foreach (var view in _views) | ||
| { | ||
| if (State.Mode == BitFullCalendarMode.Timeline && !_timelineViews.Contains(view)) | ||
| continue; | ||
|
|
||
| <button class="bit-bfc-view-tab @(State.View == view ? "active" : "")" | ||
| type="button" | ||
| @onclick="() => State.SetView(view)"> | ||
| @Texts.GetViewLabel(view) | ||
| </button> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Expose the active view to assistive tech.
This switcher is rendered as plain buttons, so the current view is not announced semantically. Add role="tablist" on the container and role="tab" plus aria-selected on each button (or reuse an existing tabs component) so the selected view is conveyed accessibly.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Header/BitFcViewTabs.razor`
around lines 3 - 13, The view switcher in BitFcViewTabs should expose the
selected state to assistive technologies. Update the container in the tabs
markup to behave like a tablist, and give each button in the `@foreach` over
_views a tab role plus an aria-selected state based on State.View == view, or
refactor to reuse an existing tabs component with the same semantics. Keep the
existing click behavior via State.SetView(view) and preserve the timeline
filtering logic.
| var currentEvents = SingleDayEvents.Where(e => | ||
| DateTime.Now >= e.StartDate && DateTime.Now <= e.EndDate).ToList(); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Include multi-day events in the "Happening now" list.
currentEvents only scans SingleDayEvents, so an event that spans across days disappears from this sidebar while it is still in progress.
Suggested patch
- var currentEvents = SingleDayEvents.Where(e =>
+ var currentEvents = MultiDayEvents.Concat(SingleDayEvents).Where(e =>
DateTime.Now >= e.StartDate && DateTime.Now <= e.EndDate).ToList();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| var currentEvents = SingleDayEvents.Where(e => | |
| DateTime.Now >= e.StartDate && DateTime.Now <= e.EndDate).ToList(); | |
| var currentEvents = MultiDayEvents.Concat(SingleDayEvents).Where(e => | |
| DateTime.Now >= e.StartDate && DateTime.Now <= e.EndDate).ToList(); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor`
around lines 8 - 9, The “Happening now” list in BitFcCalendarDayView only uses
SingleDayEvents, so multi-day events are missed while still active. Update the
currentEvents selection logic in the day view to include any in-progress events
from the multi-day events source as well as single-day events, using the
existing DateTime.Now range check against StartDate and EndDate. Keep the change
localized to the currentEvents computation in BitFcCalendarDayView so the
sidebar shows all currently ongoing events.
| <div class="bit-bfc-hour-row bit-bfc-droppable @GetHourDropClass(hour, 0)" | ||
| role="button" | ||
| tabindex="0" | ||
| aria-label="@HourSlotAriaLabel(hour)" | ||
| @ondragenter="() => OnDragEnterHour(hour, 0)" | ||
| @ondragover:preventDefault="true" | ||
| @ondrop="() => OnDropHour(hour, 0)" | ||
| @onclick="() => OnHourClickAsync(hour)" | ||
| @onkeydown="e => OnHourKeyDownAsync(e, hour)"> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Prevent default keyboard scrolling on the pseudo-button slot.
This element emulates a button, but Space can still scroll the page while also triggering OnHourKeyDownAsync. Add a prevent-default modifier on the key handler.
Suggested patch
`@onclick`="() => OnHourClickAsync(hour)"
- `@onkeydown`="e => OnHourKeyDownAsync(e, hour)">
+ `@onkeydown`="e => OnHourKeyDownAsync(e, hour)"
+ `@onkeydown`:preventDefault="true">📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <div class="bit-bfc-hour-row bit-bfc-droppable @GetHourDropClass(hour, 0)" | |
| role="button" | |
| tabindex="0" | |
| aria-label="@HourSlotAriaLabel(hour)" | |
| @ondragenter="() => OnDragEnterHour(hour, 0)" | |
| @ondragover:preventDefault="true" | |
| @ondrop="() => OnDropHour(hour, 0)" | |
| @onclick="() => OnHourClickAsync(hour)" | |
| @onkeydown="e => OnHourKeyDownAsync(e, hour)"> | |
| <div class="bit-bfc-hour-row bit-bfc-droppable `@GetHourDropClass`(hour, 0)" | |
| role="button" | |
| tabindex="0" | |
| aria-label="`@HourSlotAriaLabel`(hour)" | |
| `@ondragenter`="() => OnDragEnterHour(hour, 0)" | |
| `@ondragover`:preventDefault="true" | |
| `@ondrop`="() => OnDropHour(hour, 0)" | |
| `@onclick`="() => OnHourClickAsync(hour)" | |
| `@onkeydown`="e => OnHourKeyDownAsync(e, hour)" | |
| `@onkeydown`:preventDefault="true"> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/DayWeekView/BitFcCalendarDayView.razor`
around lines 34 - 42, The hour slot div in BitFcCalendarDayView.razor behaves
like a button, but the current OnHourKeyDownAsync key handler still allows Space
to scroll the page. Update the keyboard handler binding on the pseudo-button
element to use a prevent-default modifier so Space activates the slot without
page scrolling, while keeping the existing OnHourKeyDownAsync behavior intact.
| <div class="bit-bfc-month-cell @(!Cell.CurrentMonth ? "other-month" : "") bit-bfc-droppable" | ||
| role="button" | ||
| tabindex="0" | ||
| @ondragover="OnDragOver" | ||
| @ondragover:preventDefault="true" | ||
| @ondrop="OnDrop" | ||
| @onclick="() => OnCellClick()" | ||
| @onkeydown="OnCellKeyDown"> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Avoid wrapping the entire day cell in a button role.
The outer cell is keyboard-focusable/clickable, but it also contains separate interactive controls (BitFcMonthEventBadge and the “more events” trigger). That creates nested button semantics and inconsistent assistive-tech behavior. Move the add-event action to its own dedicated control or overlay instead of making the whole container the button.
Also applies to: 31-32, 47-49
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/MonthView/BitFcDayCell.razor`
around lines 8 - 15, The month day cell in BitFcDayCell is incorrectly exposed
as a full button-like container while it also hosts separate interactive
controls such as BitFcMonthEventBadge and the “more events” trigger, causing
nested interactive semantics. Update the DayCell markup and related
click/keyboard handlers so the outer cell is just a non-button container, and
move the add-event action to a dedicated control or overlay that is separately
focusable and clickable. Make the same accessibility/interaction adjustment in
the other affected sections of BitFcDayCell where the cell wrapper currently
behaves like a button.
| protected override async Task OnAfterRenderAsync(bool firstRender) | ||
| { | ||
| if (_resizeInitialized || PixelsPerMinute <= 0) return; | ||
|
|
||
| try | ||
| { | ||
| _dotNetRef ??= DotNetObjectReference.Create(this); | ||
| await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _startHandleId, "start"); | ||
| await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _endHandleId, "end"); | ||
| _resizeInitialized = true; | ||
| } | ||
| catch (Exception ex) when (ex is JSException or JSDisconnectedException or InvalidOperationException or OperationCanceledException) | ||
| { | ||
| // BitFullCalendar JS not yet available, or the circuit/render is mid-teardown; retry on next render. | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Avoid duplicate resize listener registration after partial init failures.
If the first initResizeHorizontal call succeeds and the second throws, _resizeInitialized stays false, so the next render runs both calls again. That can stack duplicate listeners on the already-initialized handle and fire resize callbacks multiple times.
Suggested fix
private DotNetObjectReference<BitFcTimelineEventBlock>? _dotNetRef;
- private bool _resizeInitialized;
+ private bool _startResizeInitialized;
+ private bool _endResizeInitialized;
+ private bool _resizeInitialized;
@@
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (_resizeInitialized || PixelsPerMinute <= 0) return;
try
{
_dotNetRef ??= DotNetObjectReference.Create(this);
- await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _startHandleId, "start");
- await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _endHandleId, "end");
- _resizeInitialized = true;
+ if (!_startResizeInitialized)
+ {
+ await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _startHandleId, "start");
+ _startResizeInitialized = true;
+ }
+
+ if (!_endResizeInitialized)
+ {
+ await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _endHandleId, "end");
+ _endResizeInitialized = true;
+ }
+
+ _resizeInitialized = _startResizeInitialized && _endResizeInitialized;
}
catch (Exception ex) when (ex is JSException or JSDisconnectedException or InvalidOperationException or OperationCanceledException)
{
// BitFullCalendar JS not yet available, or the circuit/render is mid-teardown; retry on next render.
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| protected override async Task OnAfterRenderAsync(bool firstRender) | |
| { | |
| if (_resizeInitialized || PixelsPerMinute <= 0) return; | |
| try | |
| { | |
| _dotNetRef ??= DotNetObjectReference.Create(this); | |
| await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _startHandleId, "start"); | |
| await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _endHandleId, "end"); | |
| _resizeInitialized = true; | |
| } | |
| catch (Exception ex) when (ex is JSException or JSDisconnectedException or InvalidOperationException or OperationCanceledException) | |
| { | |
| // BitFullCalendar JS not yet available, or the circuit/render is mid-teardown; retry on next render. | |
| } | |
| private DotNetObjectReference<BitFcTimelineEventBlock>? _dotNetRef; | |
| private bool _startResizeInitialized; | |
| private bool _endResizeInitialized; | |
| private bool _resizeInitialized; | |
| protected override async Task OnAfterRenderAsync(bool firstRender) | |
| { | |
| if (_resizeInitialized || PixelsPerMinute <= 0) return; | |
| try | |
| { | |
| _dotNetRef ??= DotNetObjectReference.Create(this); | |
| if (!_startResizeInitialized) | |
| { | |
| await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _startHandleId, "start"); | |
| _startResizeInitialized = true; | |
| } | |
| if (!_endResizeInitialized) | |
| { | |
| await JS.InvokeVoidAsync("BitBlazorUI.FullCalendar.initResizeHorizontal", _dotNetRef, _endHandleId, "end"); | |
| _endResizeInitialized = true; | |
| } | |
| _resizeInitialized = _startResizeInitialized && _endResizeInitialized; | |
| } | |
| catch (Exception ex) when (ex is JSException or JSDisconnectedException or InvalidOperationException or OperationCanceledException) | |
| { | |
| // BitFullCalendar JS not yet available, or the circuit/render is mid-teardown; retry on next render. | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/TimelineMode/BitFcTimelineEventBlock.razor.cs`
around lines 66 - 80, The resize initialization in OnAfterRenderAsync can
partially succeed, leaving one handle registered while _resizeInitialized
remains false, which causes duplicate listeners on later renders. Update
BitFcTimelineEventBlock.razor.cs so the start and end handle initialization in
BitBlazorUI.FullCalendar.initResizeHorizontal is tracked separately or marked as
initialized per handle, and only retry the missing side instead of
re-registering both when one call has already succeeded. Keep the existing
exception handling, but ensure partial success does not reattach listeners on an
already-initialized handle.
| <button type="button" class="bit-bfc-year-day has-events" | ||
| style="appearance:none;border:none;background:none;font:inherit;color:inherit;padding:0;text-align:inherit;cursor:pointer;" | ||
| @onclick="() => ShowEventsForDay(cell.Date, dayEvents)"> | ||
| <span class="bit-bfc-year-day-number @(isToday ? "today" : "")">@cell.Day</span> | ||
| <div class="bit-bfc-year-day-bullets"> | ||
| @foreach (var ev in dayEvents.Take(3)) | ||
| { | ||
| <BitFcEventBullet Color="ev.Color" /> | ||
| } | ||
| </div> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Keep the year-day button’s children valid button content.
The new <button> wraps a <div> (bit-bfc-year-day-bullets), which is invalid HTML inside a button. Browsers usually tolerate it, but the DOM/accessibility tree can become inconsistent here.
Minimal fix
<button type="button" class="bit-bfc-year-day has-events"
style="appearance:none;border:none;background:none;font:inherit;color:inherit;padding:0;text-align:inherit;cursor:pointer;"
`@onclick`="() => ShowEventsForDay(cell.Date, dayEvents)">
<span class="bit-bfc-year-day-number @(isToday ? "today" : "")">`@cell.Day`</span>
- <div class="bit-bfc-year-day-bullets">
+ <span class="bit-bfc-year-day-bullets">
`@foreach` (var ev in dayEvents.Take(3))
{
<BitFcEventBullet Color="ev.Color" />
}
- </div>
+ </span>
</button>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button type="button" class="bit-bfc-year-day has-events" | |
| style="appearance:none;border:none;background:none;font:inherit;color:inherit;padding:0;text-align:inherit;cursor:pointer;" | |
| @onclick="() => ShowEventsForDay(cell.Date, dayEvents)"> | |
| <span class="bit-bfc-year-day-number @(isToday ? "today" : "")">@cell.Day</span> | |
| <div class="bit-bfc-year-day-bullets"> | |
| @foreach (var ev in dayEvents.Take(3)) | |
| { | |
| <BitFcEventBullet Color="ev.Color" /> | |
| } | |
| </div> | |
| <button type="button" class="bit-bfc-year-day has-events" | |
| style="appearance:none;border:none;background:none;font:inherit;color:inherit;padding:0;text-align:inherit;cursor:pointer;" | |
| `@onclick`="() => ShowEventsForDay(cell.Date, dayEvents)"> | |
| <span class="bit-bfc-year-day-number @(isToday ? "today" : "")">`@cell.Day`</span> | |
| <span class="bit-bfc-year-day-bullets"> | |
| `@foreach` (var ev in dayEvents.Take(3)) | |
| { | |
| <BitFcEventBullet Color="ev.Color" /> | |
| } | |
| </span> | |
| </button> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@src/BlazorUI/Bit.BlazorUI.Extras/Components/FullCalendar/Views/YearView/BitFcCalendarYearView.razor`
around lines 68 - 77, The year-day button content in BitFcCalendarYearView
currently includes an invalid block-level wrapper inside the button, so update
the button’s children to use valid button content only. In the year-day
rendering block that contains ShowEventsForDay and the bit-bfc-year-day-bullets
markup, replace the inner div with inline-compatible content or a span-based
wrapper so the button remains semantically valid and accessible.
closes #12449
Summary by CodeRabbit
BitFullCalendarcomponent with Month/Week/Day/Year/Agenda views and resource-based Timeline (RTL support, culture-aware labels, sticky layout)./components/fullcalendardemo showcasing templates, localization, and two-way bindings.BitFullCalendar.scsstheming with RTL and theme-aware variables.