Skip to content

Add scheduling algorithm #3062

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 17, 2025
Merged

Add scheduling algorithm #3062

merged 7 commits into from
Jun 17, 2025

Conversation

datnguyen-en
Copy link
Collaborator

@datnguyen-en datnguyen-en commented Jun 9, 2025

Summary by CodeRabbit

  • New Features
    • Introduced scheduling-related interfaces for events, tasks, date ranges, and active hours.
    • Added default configurations for active hours and tasks.
    • Added an AI-powered task scheduling algorithm with support for task splitting, deadlines, and category-based active hours.
    • Added React components for task management, schedule display, algorithm insights, task modal, template scenarios, and a scheduler page integrating these features.
    • Added predefined scheduling templates for quick scenario loading.
  • Tests
    • Added a comprehensive test suite to validate scheduling interfaces and default configurations.
  • Chores
    • Added a new dependency on the dayjs library for date and time handling.
  • Bug Fixes
    • Updated root layout background styling for improved UI consistency.
  • Style
    • Added background styling to the navigation bar component.
  • New Features (Developer Mode)
    • Added a conditional "Scheduler" button visible only in development mode.

Copy link

graphite-app bot commented Jun 9, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

Copy link
Contributor

coderabbitai bot commented Jun 9, 2025

Warning

Rate limit exceeded

@vhpx has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 22 minutes and 44 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 78e9cd2 and 32c065c.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • packages/ai/package.json (1 hunks)
  • packages/types/src/supabase.ts (17 hunks)

Walkthrough

A new scheduling module was introduced, defining interfaces and constants for managing tasks, events, and active hours using dayjs for date handling. Corresponding tests were added to verify these interfaces and constants. The dayjs dependency was added to the package manifest. No changes were made to existing exported entities.

Changes

File(s) Change Summary
packages/ai/package.json Added dayjs as a runtime dependency.
packages/ai/src/scheduling/types.ts Added scheduling-related TypeScript interfaces for DateRange, Event, Task, ActiveHours, Log, ScheduleResult, and TemplateScenario.
packages/ai/src/scheduling/default.ts Added default scheduling constants: defaultActiveHours and defaultTasks.
packages/ai/src/scheduling/templates.ts Added predefined scheduling template scenarios with detailed task lists.
packages/ai/src/scheduling/algorithm.ts Added task scheduling algorithm implementing scheduling logic with task splitting, deadlines, and active hours.
packages/ai/src/scheduling/algorithm.test.ts Added tests for scheduling interfaces, constants, and placeholders for scheduling algorithm tests.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Scheduler
    participant dayjs

    User->>Scheduler: Provide tasks and active hours
    Scheduler->>dayjs: Round and calculate time slots
    Scheduler->>Scheduler: Schedule tasks respecting deadlines and constraints
    Scheduler-->>User: Return scheduled events and logs
Loading

Suggested labels

upskii

Poem

🐇
In the warren of time, new rules take their place,
With dayjs for hours, we schedule and trace.
Tasks and events, all tidy and neat,
Active hours defined, our plans are complete!
Tests hop along, checking each range—
The future of scheduling, ready for change!

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment
  • Commit Unit Tests in branch feat/implement-scheduling-algorithm

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Jun 9, 2025

Codecov Report

Attention: Patch coverage is 0.00877% with 11405 lines in your changes missing coverage. Please review.

Project coverage is 0.82%. Comparing base (c1de4e8) to head (a0490ba).
Report is 192 commits behind head on main.

Files with missing lines Patch % Lines
.../[wsId]/time-tracker/components/timer-controls.tsx 0.00% 1668 Missing ⚠️
...oard)/[wsId]/time-tracker/time-tracker-content.tsx 0.00% 1357 Missing ⚠️
...board)/[wsId]/calendar/components/time-tracker.tsx 0.00% 755 Missing ⚠️
...board)/[wsId]/tasks/boards/[boardId]/task-list.tsx 0.00% 723 Missing ⚠️
...ttings/account/security/linked-identities-card.tsx 0.00% 557 Missing and 1 partial ⚠️
.../[locale]/(root)/scheduler/components/TaskList.tsx 0.00% 473 Missing and 1 partial ⚠️
[...sId]/quiz-sets/[setId]/take/taking-quiz-client.tsx](https://app.codecov.io/gh/tutur3u/platform/pull/3062?src=pr&el=tree&filepath=apps%2Fupskii%2Fsrc%2Fapp%2F%5Blocale%5D%2F%28dashboard%29%2F%5BwsId%5D%2Fquiz-sets%2F%5BsetId%5D%2Ftake%2Ftaking-quiz-client.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=tutur3u#diff-YXBwcy91cHNraWkvc3JjL2FwcC9bbG9jYWxlXS8oZGFzaGJvYXJkKS9bd3NJZF0vcXVpei1zZXRzL1tzZXRJZF0vdGFrZS90YWtpbmctcXVpei1jbGllbnQudHN4) 0.00% 468 Missing and 1 partial ⚠️
.../(root)/scheduler/components/AlgorithmInsights.tsx 0.00% 405 Missing and 1 partial ⚠️
...oard)/[wsId]/quiz-sets/[setId]/statistics/page.tsx 0.00% 393 Missing and 1 partial ⚠️
...[locale]/(root)/scheduler/components/TaskModal.tsx 0.00% 353 Missing and 1 partial ⚠️
... and 97 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3062      +/-   ##
==========================================
- Coverage    0.84%    0.82%   -0.02%     
==========================================
  Files        2469     2509      +40     
  Lines      301703   313716   +12013     
  Branches     2970     3011      +41     
==========================================
+ Hits         2546     2585      +39     
- Misses     297019   308990   +11971     
- Partials     2138     2141       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vhpx vhpx changed the title feat: add dayjs dependency and implement scheduling algorithm with tests Add scheduling algorithm Jun 9, 2025
@vhpx vhpx added enhancement New feature or request calendar labels Jun 9, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
packages/ai/src/scheduling/algorithm.ts (1)

57-57: Consider implementing the schedule function or removing the placeholder.

The commented-out schedule function suggests incomplete implementation. Either implement the function or remove the placeholder to avoid confusion.

Would you like me to help implement a basic scheduling algorithm or should this placeholder be removed for now?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c1de4e8 and eec3d03.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • packages/ai/package.json (1 hunks)
  • packages/ai/src/scheduling/algorithm.test.ts (1 hunks)
  • packages/ai/src/scheduling/algorithm.ts (1 hunks)
🧰 Additional context used
🪛 GitHub Check: CodeFactor
packages/ai/src/scheduling/algorithm.test.ts

[notice] 176-176: packages/ai/src/scheduling/algorithm.test.ts#L176
Unresolved 'todo' comment. (eslint/no-warning-comments)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Deploy-Preview
  • GitHub Check: Deploy-Preview
  • GitHub Check: Deploy-Preview
🔇 Additional comments (3)
packages/ai/package.json (1)

46-46:

✅ Verification successful

Verify the dayjs version for security and currency.

The dayjs version ^1.11.13 should be verified to ensure it's current and free from known vulnerabilities.


🌐 Web query:

What is the latest version of dayjs and are there any known security vulnerabilities in version 1.11.13?

💡 Result:

As of June 9, 2025, the latest stable version of Day.js is 1.11.13, released approximately seven months ago. (npmjs.com)

Regarding security vulnerabilities, there are no direct vulnerabilities reported for Day.js version 1.11.13 in Snyk's vulnerability database. (security.snyk.io) However, it's important to note that Day.js version 1.11.10 depends on Moment.js, which has a known security vulnerability (CVE-2022-31129). (github.com) Since version 1.11.13 is the latest release, it is likely that this dependency has been updated or addressed.

For the most current information on security vulnerabilities and updates, it's recommended to consult the official Day.js GitHub repository or the Snyk vulnerability database.

Citations:


Confirm Day.js version is current and secure

The dayjs dependency at ^1.11.13 is the latest stable release (as of June 2025) and has no reported vulnerabilities. No further changes needed.

packages/ai/src/scheduling/algorithm.test.ts (2)

1-184: Excellent test coverage and structure.

The test suite is comprehensive and well-organized, covering all interfaces and default constants with appropriate assertions. The structure follows good testing practices with clear describe blocks and focused test cases.

🧰 Tools
🪛 GitHub Check: CodeFactor

[notice] 176-176: packages/ai/src/scheduling/algorithm.test.ts#L176
Unresolved 'todo' comment. (eslint/no-warning-comments)


176-183: TODO comments are intentional for future implementation.

The TODO comments in the test file are placeholders for the schedule function implementation, which is currently commented out in the algorithm file. These are intentional and provide a clear roadmap for future development.

🧰 Tools
🪛 GitHub Check: CodeFactor

[notice] 176-176: packages/ai/src/scheduling/algorithm.test.ts#L176
Unresolved 'todo' comment. (eslint/no-warning-comments)

@vhpx vhpx marked this pull request as draft June 9, 2025 04:47
@vhpx vhpx force-pushed the feat/implement-scheduling-algorithm branch from a0490ba to 78e9cd2 Compare June 17, 2025 17:06
@vhpx vhpx marked this pull request as ready for review June 17, 2025 17:06
@vhpx vhpx merged commit 9fdceac into main Jun 17, 2025
14 checks passed
@vhpx vhpx deleted the feat/implement-scheduling-algorithm branch June 17, 2025 17:09
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

♻️ Duplicate comments (1)
apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx (1)

45-56: Same colour helper repeated across three components

Extract to @tuturuuu/ui/theme (or similar) to ensure consistent updates.

🧹 Nitpick comments (9)
apps/calendar/src/app/[locale]/layout.tsx (1)

115-117: Background token diverges from children

The root layout now uses bg-root-background whereas the navbar keeps bg-background. Make sure both tokens exist in the Tailwind theme and intentionally differ; otherwise you might get an unexpected color seam between the header and body.

apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx (2)

30-46: Hash function can be simplified & made deterministic

a & a is a no-op; it just returns a. To clamp to 32-bit you likely wanted a & 0xffffffff. Consider cleaning this up for readability.

-    return a & a;
+    return a & 0xffffffff;

179-182: Sorting mutates dailyEvents, risking unexpected re-renders

dailyEvents.sort(...) mutates the original array held in groupedEvents, which is memoised. On subsequent renders this may violate React’s expectations and break referential equality checks.

-const sortedEvents = dailyEvents.sort((a, b) =>
-  a.range.start.diff(b.range.start)
-);
+const sortedEvents = [...dailyEvents].sort((a, b) =>
+  a.range.start.diff(b.range.start)
+);
apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx (1)

146-148: onOpenChange handler ignores the boolean parameter

<Dialog open={isOpen} onOpenChange={handleClose}> passes newOpen: boolean to handleClose, but the function signature () => void discards it.
If the modal were ever opened by the dialog itself (e.g. via keyboard shortcut), the handler would immediately invoke onClose() and reset the form.
Accept the parameter and early-return when newOpen is true.

apps/calendar/src/app/[locale]/(root)/scheduler/page.tsx (1)

119-130: DRY: consolidate colour helpers

getCategoryColor duplicates identical logic found in other components.
Export once from a shared utils/colors.ts to avoid drift.

apps/calendar/src/app/[locale]/(root)/scheduler/components/TemplateScenarios.tsx (1)

34-44: Icon detection is brittle & case-sensitive

name.includes('Split') misses “Task Splitting Challenge”.
Compare lower-cased strings or use regexes on keyword arrays.

packages/ai/src/scheduling/algorithm.ts (1)

244-290: getNextAvailableTime ignores later ranges

Only the first range of hours is inspected (const firstHour = hours[0]).
For multiple daily ranges (e.g., lunch break gap), early slots may be missed. Iterate all ranges when day === 0.

apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx (2)

82-100: Inefficient per-task sort inside a loop.

events.filter(...).sort(...) is executed for every task, producing O(T × E log E) complexity and repeated array copies.
A quicker alternative:

  1. Build a Map<taskId, Event[]> once.
  2. Keep only the last event per task while populating the map.

This removes the nested filter/sort and scales linearly with events.length.


129-130: Unresolved TODO leaves largestGap always zero.

Either compute the metric or omit it from the UI until implemented to avoid misleading analytics.
I can help sketch the gap-calculation if useful.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eec3d03 and 78e9cd2.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • apps/calendar/src/app/[locale]/(root)/navbar.tsx (1 hunks)
  • apps/calendar/src/app/[locale]/(root)/page.tsx (2 hunks)
  • apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx (1 hunks)
  • apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx (1 hunks)
  • apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx (1 hunks)
  • apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx (1 hunks)
  • apps/calendar/src/app/[locale]/(root)/scheduler/components/TemplateScenarios.tsx (1 hunks)
  • apps/calendar/src/app/[locale]/(root)/scheduler/page.tsx (1 hunks)
  • apps/calendar/src/app/[locale]/layout.tsx (1 hunks)
  • packages/ai/package.json (1 hunks)
  • packages/ai/src/scheduling/algorithm.test.ts (1 hunks)
  • packages/ai/src/scheduling/algorithm.ts (1 hunks)
  • packages/ai/src/scheduling/default.ts (1 hunks)
  • packages/ai/src/scheduling/templates.ts (1 hunks)
  • packages/ai/src/scheduling/types.ts (1 hunks)
  • packages/types/src/supabase.ts (15 hunks)
✅ Files skipped from review due to trivial changes (4)
  • packages/ai/src/scheduling/default.ts
  • packages/ai/src/scheduling/templates.ts
  • packages/ai/src/scheduling/types.ts
  • packages/types/src/supabase.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ai/package.json
🧰 Additional context used
🧬 Code Graph Analysis (5)
apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx (4)
packages/ai/src/scheduling/types.ts (1)
  • Event (8-16)
packages/ui/src/components/ui/card.tsx (5)
  • Card (68-68)
  • CardHeader (72-72)
  • CardTitle (73-73)
  • CardDescription (70-70)
  • CardContent (69-69)
packages/ui/src/components/ui/badge.tsx (1)
  • Badge (49-49)
packages/ui/src/components/ui/tooltip.tsx (3)
  • Tooltip (60-60)
  • TooltipTrigger (60-60)
  • TooltipContent (60-60)
apps/calendar/src/app/[locale]/(root)/scheduler/components/TemplateScenarios.tsx (4)
packages/ai/src/scheduling/types.ts (1)
  • TemplateScenario (45-50)
packages/ui/src/components/ui/card.tsx (5)
  • Card (68-68)
  • CardHeader (72-72)
  • CardTitle (73-73)
  • CardDescription (70-70)
  • CardContent (69-69)
packages/ai/src/scheduling/templates.ts (1)
  • templateScenarios (4-737)
packages/ui/src/components/ui/badge.tsx (1)
  • Badge (49-49)
apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx (5)
packages/ai/src/scheduling/types.ts (2)
  • Task (18-27)
  • Event (8-16)
packages/ui/src/components/ui/card.tsx (5)
  • Card (68-68)
  • CardHeader (72-72)
  • CardTitle (73-73)
  • CardDescription (70-70)
  • CardContent (69-69)
packages/ui/src/components/ui/badge.tsx (1)
  • Badge (49-49)
packages/ui/src/components/ui/tooltip.tsx (3)
  • Tooltip (60-60)
  • TooltipTrigger (60-60)
  • TooltipContent (60-60)
packages/ui/src/components/ui/select.tsx (5)
  • Select (170-170)
  • SelectTrigger (178-178)
  • SelectValue (179-179)
  • SelectContent (171-171)
  • SelectItem (173-173)
packages/ai/src/scheduling/algorithm.ts (2)
packages/ai/src/scheduling/types.ts (6)
  • Task (18-27)
  • ActiveHours (29-33)
  • ScheduleResult (40-43)
  • Event (8-16)
  • Log (35-38)
  • DateRange (3-6)
packages/ai/src/scheduling/default.ts (1)
  • defaultActiveHours (4-23)
packages/ai/src/scheduling/algorithm.test.ts (1)
packages/ai/src/scheduling/default.ts (2)
  • defaultActiveHours (4-23)
  • defaultTasks (25-35)
🪛 GitHub Check: codecov/patch
apps/calendar/src/app/[locale]/(root)/page.tsx

[warning] 3-3: apps/calendar/src/app/[locale]/(root)/page.tsx#L3
Added line #L3 was not covered by tests


[warning] 5-5: apps/calendar/src/app/[locale]/(root)/page.tsx#L5
Added line #L5 was not covered by tests


[warning] 8-8: apps/calendar/src/app/[locale]/(root)/page.tsx#L8
Added line #L8 was not covered by tests


[warning] 17-21: apps/calendar/src/app/[locale]/(root)/page.tsx#L17-L21
Added lines #L17 - L21 were not covered by tests

apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx

[warning] 2-303: apps/calendar/src/app/[locale]/(root)/scheduler/components/ScheduleDisplay.tsx#L2-L303
Added lines #L2 - L303 were not covered by tests

apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx

[warning] 2-354: apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx#L2-L354
Added lines #L2 - L354 were not covered by tests

apps/calendar/src/app/[locale]/(root)/scheduler/components/TemplateScenarios.tsx

[warning] 2-143: apps/calendar/src/app/[locale]/(root)/scheduler/components/TemplateScenarios.tsx#L2-L143
Added lines #L2 - L143 were not covered by tests

apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx

[warning] 2-474: apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx#L2-L474
Added lines #L2 - L474 were not covered by tests

apps/calendar/src/app/[locale]/(root)/scheduler/page.tsx

[warning] 2-343: apps/calendar/src/app/[locale]/(root)/scheduler/page.tsx#L2-L343
Added lines #L2 - L343 were not covered by tests

packages/ai/src/scheduling/algorithm.ts

[warning] 10-11: packages/ai/src/scheduling/algorithm.ts#L10-L11
Added lines #L10 - L11 were not covered by tests


[warning] 13-13: packages/ai/src/scheduling/algorithm.ts#L13
Added line #L13 was not covered by tests


[warning] 16-21: packages/ai/src/scheduling/algorithm.ts#L16-L21
Added lines #L16 - L21 were not covered by tests


[warning] 23-25: packages/ai/src/scheduling/algorithm.ts#L23-L25
Added lines #L23 - L25 were not covered by tests


[warning] 27-32: packages/ai/src/scheduling/algorithm.ts#L27-L32
Added lines #L27 - L32 were not covered by tests


[warning] 34-35: packages/ai/src/scheduling/algorithm.ts#L34-L35
Added lines #L34 - L35 were not covered by tests


[warning] 38-40: packages/ai/src/scheduling/algorithm.ts#L38-L40
Added lines #L38 - L40 were not covered by tests


[warning] 43-45: packages/ai/src/scheduling/algorithm.ts#L43-L45
Added lines #L43 - L45 were not covered by tests


[warning] 47-52: packages/ai/src/scheduling/algorithm.ts#L47-L52
Added lines #L47 - L52 were not covered by tests


[warning] 55-61: packages/ai/src/scheduling/algorithm.ts#L55-L61
Added lines #L55 - L61 were not covered by tests


[warning] 64-69: packages/ai/src/scheduling/algorithm.ts#L64-L69
Added lines #L64 - L69 were not covered by tests


[warning] 71-72: packages/ai/src/scheduling/algorithm.ts#L71-L72
Added lines #L71 - L72 were not covered by tests


[warning] 74-80: packages/ai/src/scheduling/algorithm.ts#L74-L80
Added lines #L74 - L80 were not covered by tests


[warning] 83-88: packages/ai/src/scheduling/algorithm.ts#L83-L88
Added lines #L83 - L88 were not covered by tests


[warning] 90-94: packages/ai/src/scheduling/algorithm.ts#L90-L94
Added lines #L90 - L94 were not covered by tests


[warning] 96-97: packages/ai/src/scheduling/algorithm.ts#L96-L97
Added lines #L96 - L97 were not covered by tests


[warning] 99-103: packages/ai/src/scheduling/algorithm.ts#L99-L103
Added lines #L99 - L103 were not covered by tests


[warning] 105-105: packages/ai/src/scheduling/algorithm.ts#L105
Added line #L105 was not covered by tests

apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx

[warning] 2-406: apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx#L2-L406
Added lines #L2 - L406 were not covered by tests

apps/calendar/src/app/[locale]/(root)/navbar.tsx

[warning] 63-63: apps/calendar/src/app/[locale]/(root)/navbar.tsx#L63
Added line #L63 was not covered by tests

apps/calendar/src/app/[locale]/layout.tsx

[warning] 116-116: apps/calendar/src/app/[locale]/layout.tsx#L116
Added line #L116 was not covered by tests

🪛 GitHub Check: CodeFactor
apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx

[notice] 129-129: apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx#L129
Unresolved 'todo' comment. (eslint/no-warning-comments)

packages/ai/src/scheduling/algorithm.test.ts

[notice] 176-176: packages/ai/src/scheduling/algorithm.test.ts#L176
Unresolved 'todo' comment. (eslint/no-warning-comments)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Deploy-Preview
  • GitHub Check: Verify generated types
  • GitHub Check: Deploy-Preview
  • GitHub Check: Deploy-Preview
🔇 Additional comments (3)
apps/calendar/src/app/[locale]/(root)/navbar.tsx (1)

63-63: Verify that SharedNavbar forwards className

className="bg-background" will have no visual effect unless SharedNavbar explicitly spreads the className prop to its root element. Double-check the underlying component to be certain the new style is actually applied.

packages/ai/src/scheduling/algorithm.test.ts (1)

42-44: Duration unit is unclear

duration: 120 // 2 hours in minutes conflicts with the rest of the codebase where duration seems to be expressed in hours (see defaultTasks, where duration: 1 equals 1 hour). Standardise on a single unit to avoid subtle bugs when the algorithm consumes these objects.

apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx (1)

65-75: Possible unit mismatch between task.duration and scheduledDuration.

totalDuration is aggregated from task.duration (unit unknown) while scheduledDuration is derived via dayjs.diff(..., 'hour', true) (clearly hours). If task.duration is stored in minutes or milliseconds, the metrics (average size, utilization, etc.) become inconsistent.

Verify that both use the same time-unit, or normalise during aggregation:

-const totalDuration = tasks.reduce((sum, task) => sum + task.duration, 0);
+const totalDuration = tasks.reduce(
+  (sum, task) => sum + dayjs.duration(task.duration).asHours(), // example normalisation
+  0,
+);

Comment on lines +17 to +21
{DEV_MODE && (
<Link href="/scheduler">
<Button>Scheduler</Button>
</Link>
)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Locale is dropped from the Scheduler link – navigation will break

Link points to "/scheduler", ignoring the active locale segment (/en, /vi, …). Users will be routed to the default-locale page, losing translation context.

-<Link href="/scheduler">
+<Link href={`/${locale}/scheduler`}>

If you rely on next-intl’s <Link locale={false|...}> API, use that instead.

📝 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.

Suggested change
{DEV_MODE && (
<Link href="/scheduler">
<Button>Scheduler</Button>
</Link>
)}
{DEV_MODE && (
<Link href={`/${locale}/scheduler`}>
<Button>Scheduler</Button>
</Link>
)}
🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 17-21: apps/calendar/src/app/[locale]/(root)/page.tsx#L17-L21
Added lines #L17 - L21 were not covered by tests

🤖 Prompt for AI Agents
In apps/calendar/src/app/[locale]/(root)/page.tsx around lines 17 to 21, the
Link to "/scheduler" does not include the active locale segment, causing
navigation to lose translation context. Update the Link component to preserve
the current locale by using next-intl's locale-aware Link API, such as adding
the locale prop or setting locale={false} to keep the current locale in the URL.

Comment on lines +139 to +144
const updateFormData = (field: string, value: string | number) => {
setFormData((prev) => ({ ...prev, [field]: value }));
if (errors[field]) {
setErrors((prev) => ({ ...prev, [field]: '' }));
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Guard against NaN when numeric inputs are cleared

parseFloat(e.target.value) returns NaN on an empty field, causing NaN <= 0 checks and later arithmetic to behave unexpectedly.
Add an explicit empty-string check before calling parseFloat, or fall back to '' in state and coerce only during validation.

🤖 Prompt for AI Agents
In apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskModal.tsx
around lines 139 to 144, the updateFormData function does not guard against NaN
values when numeric inputs are cleared, causing issues with comparisons and
arithmetic. Modify the input handling to explicitly check if the input value is
an empty string before parsing it with parseFloat, and store an empty string in
state in that case. Only coerce the value to a number during validation to avoid
NaN propagation.

Comment on lines +71 to +78
const addTask = (taskData: Omit<Task, 'id' | 'events'>) => {
const newTask: Task = {
...taskData,
id: `task-${Date.now()}`,
events: [],
};
setTasks([...tasks, newTask]);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use collision-safe IDs

id: \task-${Date.now()}`risks clashes when tasks are added rapidly. Prefercrypto.randomUUID()(native) ornanoid` for uniqueness.

🤖 Prompt for AI Agents
In apps/calendar/src/app/[locale]/(root)/scheduler/page.tsx around lines 71 to
78, the task ID generation using `task-${Date.now()}` can cause collisions if
tasks are added quickly. Replace this with a collision-safe method by using
`crypto.randomUUID()` to generate the task ID, ensuring each ID is unique even
when tasks are created rapidly.

Comment on lines +346 to +355
type="number"
step="0.25"
min="0.25"
value={task.duration}
onChange={(e) =>
onUpdateTask(task.id, {
duration: parseFloat(e.target.value),
})
}
className="text-sm"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Persisting NaN durations corrupts scheduling

Empty or non-numeric input pushes NaN into task state, later breaking the algorithm.
Validate the value before calling onUpdateTask, or coerce with Number(e.target.value || 0.25).

🤖 Prompt for AI Agents
In apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx
around lines 346 to 355, the onChange handler for the duration input can pass
NaN to onUpdateTask if the input is empty or non-numeric, corrupting the task
state. Fix this by validating the input value before calling onUpdateTask,
ensuring it is a valid number, or coerce it using Number(e.target.value || 0.25)
to default to 0.25 when the input is invalid or empty.

Comment on lines +214 to +216
const progressPercentage = progress
? (progress.completed / task.duration) * 100
: 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Division by zero when task.duration === 0

progress.completed / task.duration yields Infinity.
Guard with Math.max(task.duration, 0.01) or simply skip the bar when duration is zero.

🤖 Prompt for AI Agents
In apps/calendar/src/app/[locale]/(root)/scheduler/components/TaskList.tsx
around lines 214 to 216, the calculation of progressPercentage divides
progress.completed by task.duration without checking if task.duration is zero,
which can cause a division by zero and result in Infinity. Fix this by guarding
the division with Math.max(task.duration, 0.01) to avoid zero division or by
skipping the progress bar rendering entirely when task.duration is zero.

Comment on lines +165 to +174
// Ensure the part start time is rounded to 15-minute increment
const partStart = roundToQuarterHour(slot.start, false);
const partEnd = partStart.add(partDuration, 'hour');

// Verify the end time doesn't exceed the slot
if (partEnd.isAfter(slot.end)) {
const adjustedDuration = slot.end.diff(partStart, 'hour', true);

if (adjustedDuration < adjustedTask.minDuration) {
logs.push({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

partDuration may round down to 0 h

hoursToQuarterHours(0.12) ⇒ 0.
After rounding, ensure partDuration ≥ 0.25 or bail with an explicit error to avoid infinite loops.

🤖 Prompt for AI Agents
In packages/ai/src/scheduling/algorithm.ts around lines 165 to 174, the
calculation of partDuration using hoursToQuarterHours may round down to zero,
causing potential infinite loops. After computing partDuration, add a check to
ensure it is at least 0.25 hours; if it is less, either set it to 0.25 or throw
an explicit error to prevent further processing with an invalid duration.

Comment on lines +96 to +105
while (remainingDuration > 0 && attempts < maxAttempts) {
attempts++;

const availableSlots = getAvailableSlots(
availableTimes[task.category],
categoryHours,
scheduledEvents
);

if (availableSlots.length === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

maxAttempts = 50 can truncate large, perfectly schedulable tasks

A 25 h task split into 0.5 h parts needs 50 iterations plus one; the loop aborts even when slots exist.
Either calculate Math.ceil(duration / minDuration) or remove the guard once slot progress is observed.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 96-97: packages/ai/src/scheduling/algorithm.ts#L96-L97
Added lines #L96 - L97 were not covered by tests


[warning] 99-103: packages/ai/src/scheduling/algorithm.ts#L99-L103
Added lines #L99 - L103 were not covered by tests


[warning] 105-105: packages/ai/src/scheduling/algorithm.ts#L105
Added line #L105 was not covered by tests

🤖 Prompt for AI Agents
In packages/ai/src/scheduling/algorithm.ts around lines 96 to 105, the loop uses
a fixed maxAttempts of 50 which can prematurely stop scheduling large tasks
split into many small parts. To fix this, replace the fixed maxAttempts with a
dynamic calculation like Math.ceil(duration / minDuration) to ensure enough
iterations for all parts, or modify the loop to continue if progress is being
made in scheduling slots, removing the arbitrary iteration limit.

Comment on lines +83 to +88
const adjustedTask = {
...task,
duration: hoursToQuarterHours(task.duration),
minDuration: ensureMinimumDuration(task.minDuration),
maxDuration: hoursToQuarterHours(task.maxDuration),
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Validate duration relationships upfront

minDuration, maxDuration, and duration are blindly adjusted; invalid configurations (e.g. min > max or max > duration) can create impossible constraints and endless retries.
Add an early sanity check and push a single error log instead of looping 50 times.

🧰 Tools
🪛 GitHub Check: codecov/patch

[warning] 83-88: packages/ai/src/scheduling/algorithm.ts#L83-L88
Added lines #L83 - L88 were not covered by tests

🤖 Prompt for AI Agents
In packages/ai/src/scheduling/algorithm.ts around lines 83 to 88, the code
adjusts task durations without validating their logical relationships, which can
cause impossible constraints and repeated retries. Add a validation step after
adjusting durations to check that minDuration is not greater than maxDuration
and maxDuration is not greater than duration. If these conditions fail, log a
single error message and handle the invalid configuration early to prevent
looping retries.

Comment on lines +76 to +81
const splitTasks = new Set(
events
.filter((e) => e.partNumber && e.partNumber > 1)
.map((e) => e.taskId)
).size;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

splitTasks under-counts tasks that are split.

Filtering on partNumber > 1 ignores the first part of a split task; tasks split into exactly two parts will contribute only one event (partNumber === 1) and will therefore be missed.
Use > 0 (or presence of partNumber !== undefined) then new Set to deduplicate:

-.filter((e) => e.partNumber && e.partNumber > 1)
+.filter((e) => e.partNumber != null)
📝 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.

Suggested change
const splitTasks = new Set(
events
.filter((e) => e.partNumber && e.partNumber > 1)
.map((e) => e.taskId)
).size;
const splitTasks = new Set(
events
.filter((e) => e.partNumber != null)
.map((e) => e.taskId)
).size;
🤖 Prompt for AI Agents
In
apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx
around lines 76 to 81, the calculation of splitTasks undercounts tasks because
it filters events with partNumber > 1, missing the first part of split tasks. To
fix this, change the filter condition to include all events with partNumber > 0
or partNumber defined, then use new Set to deduplicate taskIds, ensuring all
split tasks are counted correctly.

Comment on lines +113 to +117
const workingHours = 8; // Assume 8-hour work day
const utilizationRate = Math.min(
(scheduledDuration / workingHours) * 100,
100
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

utilizationRate can exceed 100 % across multi-day schedules.

The divisor is a hard-coded 8-hour day, but scheduledDuration may span several days. Divide by workingHours * activeDays (or the available window) to avoid inflated percentages.

-const workingHours = 8;
-const utilizationRate = Math.min(
-  (scheduledDuration / workingHours) * 100,
-  100
-);
+const activeDays =
+  new Set(events.map(e => e.range.start.format('YYYY-MM-DD'))).size || 1;
+const utilizationRate = Math.min(
+  (scheduledDuration / (8 * activeDays)) * 100,
+  100,
+);
📝 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.

Suggested change
const workingHours = 8; // Assume 8-hour work day
const utilizationRate = Math.min(
(scheduledDuration / workingHours) * 100,
100
);
const activeDays =
new Set(events.map(e => e.range.start.format('YYYY-MM-DD'))).size || 1;
const utilizationRate = Math.min(
(scheduledDuration / (8 * activeDays)) * 100,
100,
);
🤖 Prompt for AI Agents
In
apps/calendar/src/app/[locale]/(root)/scheduler/components/AlgorithmInsights.tsx
around lines 113 to 117, the utilizationRate calculation incorrectly divides
scheduledDuration by a fixed 8-hour workday, causing values to exceed 100% for
multi-day schedules. Modify the divisor to be workingHours multiplied by the
number of activeDays (or the total available scheduling window) to correctly
reflect utilization over multiple days and prevent inflated percentages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
calendar enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants