Thanks to visit codestin.com
Credit goes to github.com

Skip to content

chore: check cycle based on timezone#6461

Merged
batmnkh2344 merged 3 commits intomainfrom
operation-timezone
Oct 15, 2025
Merged

chore: check cycle based on timezone#6461
batmnkh2344 merged 3 commits intomainfrom
operation-timezone

Conversation

@batmnkh2344
Copy link
Collaborator

@batmnkh2344 batmnkh2344 commented Oct 10, 2025

Summary by Sourcery

Implement timezone-based cycle checking across backend and UI by scheduling hourly worker jobs, computing date ranges in the proper timezone, and adding a configurable timezone field in the general settings

New Features:

  • Support timezone-aware cycle checking by passing organization timezone to worker jobs and only executing checks at local midnight
  • Provide a timezone selection setting in the general settings UI via a new SelectTimezone component

Enhancements:

  • Change cycle check job schedule to run hourly and enforce execution only at the start of the day in each timezone using moment-timezone
  • Update cycle progress chart and date range calculations to respect configured timezone and use Moment for missing day filling
  • Refactor general settings form merge logic and restructure settings page layout with PageContainer and ScrollArea
  • Re-enable and integrate the general settings route and navigation entry

Important

Implement timezone-based cycle checking and UI updates for timezone selection in settings.

  • Behavior:
    • Implement timezone-aware cycle checking in dailyCheckCycles.ts and checkCycle() to run checks at local midnight.
    • Update getCycleProgressChart() in utils.ts to use organization timezone for date calculations.
  • UI:
    • Add SelectTimezone component in SelectTimezone.tsx for timezone selection in general settings.
    • Update GeneralSettingsPage.tsx to include timezone selection and adjust layout with PageContainer and ScrollArea.
  • Scheduling:
    • Change job schedule in index.ts to run hourly instead of daily.
  • Misc:
    • Refactor settings form logic in GeneralSettings.tsx to handle timezone configuration.
    • Restore and integrate general settings route in SettingsRoutes.tsx.

This description was created by Ellipsis for f13ab98. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Workspace General Settings: Timezone field and selector with auto-detected default; General settings route and nav restored.
  • UI Improvements

    • Redesigned General Settings page with a scrollable layout.
    • Cycle progress chart: improved active-point visuals.
  • Operational Changes

    • Background cycle checks now run hourly.
    • Date handling and daily/chart aggregations are timezone-aware for more accurate reporting.

@sourcery-ai
Copy link

sourcery-ai bot commented Oct 10, 2025

Reviewer's Guide

This PR equips daily cycle checks and progress chart computations with timezone awareness, refactors date utilities to use moment-timezone, updates the worker schedule, and extends the general settings UI to configure and persist TIMEZONE, along with minor route/layout and chart UI tweaks.

Class diagram for updated General Settings form and schema

classDiagram
  class TGeneralSettingsProps {
    +string TIMEZONE
    ...other props
  }
  class generalSettingsSchema {
    +TIMEZONE: string
    ...other schema fields
  }
  class SelectTimezone {
    +render()
  }
  TGeneralSettingsProps <|-- generalSettingsSchema
  GeneralSettings o-- SelectTimezone
Loading

File-Level Changes

Change Details Files
Timezone-aware cycle scheduling and execution
  • Pass org.timezone or global TIMEZONE into checkCycle job payloads
  • Change cron pattern to run hourly in initMQWorkers
  • Compute current moment in job timezone and exit if not midnight
  • Derive UTC day start/end for filters and apply to cycle queries
backend/plugins/operation_api/src/worker/dailyCheckCycles.ts
backend/plugins/operation_api/src/worker/index.ts
Refactor progress chart and date utilities for timezone support
  • Fetch TIMEZONE config in getCycleProgressChart and use $dateToString with timezone in aggregation
  • Convert cycle start/end dates to moment tz and calculate days with diff
  • Refactor fillMissingDays and fillMissingDaysWithStartDate to accept Moment, clone/add days, and format via moment
backend/plugins/operation_api/src/modules/cycle/utils.ts
backend/plugins/operation_api/src/modules/project/utils/charUtils.ts
Extend general settings UI with timezone configuration
  • Add TIMEZONE to schema, types, and set default via detectTimeZone in form hook
  • Introduce SelectTimezone component and include it in the GeneralSettings form
  • Merge form data by spreading existing configs then overriding with submitted values
  • Load and set TIMEZONE field on configs change and include it in updates
frontend/core-ui/src/modules/settings/general/schema/index.ts
frontend/core-ui/src/modules/settings/general/types.ts
frontend/core-ui/src/modules/settings/general/hooks/useGeneralSettingsForms.tsx
frontend/core-ui/src/modules/settings/general/components/GeneralSettings.tsx
frontend/core-ui/src/modules/settings/general/components/SelectTimezone.tsx
Enable General Settings route with layout enhancements
  • Wrap GeneralSettingsPage in PageContainer and ScrollArea for consistent layout
  • Un-comment and activate the General route in SettingsRoutes
  • Add 'General' entry to SETTINGS_PATH_DATA nav and define SettingsWorkspacePath.General
frontend/core-ui/src/pages/settings/workspace/GeneralSettingsPage.tsx
frontend/core-ui/src/modules/app/components/SettingsRoutes.tsx
frontend/core-ui/src/modules/settings/constants/data.ts
frontend/core-ui/src/modules/types/paths/SettingsPath.ts
Chart UI minor enhancements
  • Add activeDot styling for started and completed area series in CycleProgressChart
frontend/plugins/operation_ui/src/modules/cycle/components/detail/CycleProgressChart.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link

coderabbitai bot commented Oct 10, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds timezone-aware date handling across backend cycle utilities and workers, changes the daily cycles scheduler to run hourly, updates project/frontend chart date handling to use moment-timezone, and re-enables General settings with a TIMEZONE field and selector. Also tweaks chart active-dot visuals.

Changes

Cohort / File(s) Summary
Backend: Cycle utils
backend/plugins/operation_api/src/modules/cycle/utils.ts
Fetches TIMEZONE via TRPC; switches daily aggregation/projection and chart-range calculations to timezone-aware moment/moment-timezone logic and stringified dayDate.
Backend: Daily cycle worker
backend/plugins/operation_api/src/worker/dailyCheckCycles.ts
Always enqueues checks with timezone info; fetches TIMEZONE in non-SaaS; computes tzToday and UTC day window; skips when local hour != 0; constrains cycle queries to utcStart/utcEnd; passes timezone in job payloads.
Backend: Worker scheduler
backend/plugins/operation_api/src/worker/index.ts
Changes cron schedule for operations-daily-cycles-check from daily midnight to hourly (0 * * * *).
Backend: Project chart utils
backend/plugins/operation_api/src/modules/project/utils/charUtils.ts
Replaces date-fns usage with moment-timezone; updates fillMissingDays to accept a Moment baseDate and iterates/formats dates via moment.
Backend: Project GraphQL resolver
backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts
Wraps base/start dates with moment() before calling fillMissingDays; adapts chart data construction to moment-based dates.
Frontend: Settings routing & nav
frontend/core-ui/src/modules/app/components/SettingsRoutes.tsx, frontend/core-ui/src/modules/settings/constants/data.ts, frontend/core-ui/src/modules/types/paths/SettingsPath.ts
Re-enables General settings route; adds General nav item with icon; exposes SettingsWorkspacePath.General.
Frontend: General Settings (form + schema + UI)
frontend/core-ui/src/modules/settings/general/components/GeneralSettings.tsx, frontend/core-ui/src/modules/settings/general/components/SelectTimezone.tsx, frontend/core-ui/src/modules/settings/general/hooks/useGeneralSettingsForms.tsx, frontend/core-ui/src/modules/settings/general/schema/index.ts
Adds TIMEZONE field to schema and form defaults (auto-detected); new SelectTimezone component wired into RHF form; merges TIMEZONE into saved configs.
Frontend: General Settings page layout
frontend/core-ui/src/pages/settings/workspace/GeneralSettingsPage.tsx
Wraps GeneralSettings in PageContainer + ScrollArea, moves breadcrumbs, and adds scroll UI.
Frontend: Cycle chart UI
frontend/plugins/operation_ui/src/modules/cycle/components/detail/CycleProgressChart.tsx
Adds customized activeDot props to Area series (started/completed) to adjust active dot visuals.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Scheduler as Scheduler (hourly)
  participant Worker as operations-daily-cycles-check
  participant Config as TRPC Config Service
  participant OrgSvc as Orgs Service
  participant Queue as Job Queue
  participant DB as Cycles DB

  Scheduler->>Worker: Trigger job (hourly)
  alt SaaS
    Worker->>OrgSvc: List orgs
    loop each org
      Worker->>Queue: Enqueue checkCycle { orgId, timezone? }
    end
  else Non-SaaS
    Worker->>Config: getConfig(TIMEZONE)
    Worker->>Queue: Enqueue checkCycle { timezone }
  end

  Queue-->>Worker: Dequeue checkCycle { timezone }
  Worker->>Worker: tzToday = now.tz(timezone)
  alt tzToday.hour() == 0
    Worker->>Worker: compute utcStart/utcEnd for tz day
    par find ended today
      Worker->>DB: find cycles with endDate in [utcStart, utcEnd]
    and find started today
      Worker->>DB: find cycles with startDate in [utcStart, utcEnd]
    end
    Worker->>Queue: Enqueue per-cycle updates
  else
    Worker->>Worker: No-op (not midnight in tz)
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant Page as GeneralSettings Page
  participant Form as React Hook Form
  participant API as Config API

  Page->>Form: init defaultValues { TIMEZONE = detectTimeZone(), ... }
  Form-->>Page: render fields (language, currencies, TIMEZONE)
  User->>Form: select/change TIMEZONE
  User->>Form: submit
  Form->>Page: build merged updatedConfigs (existing + form)
  Page->>API: save updatedConfigs (includes TIMEZONE)
  API-->>Page: success
  Page->>User: toast + updated UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

I hop through hours, map each zone with care,
I stitch days with tz and guard the midnight air.
A general toggle springs to life, a timezone to select,
Charts blink brighter with new dots—
I thump once: "Sync complete!" 🐇🌙

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes implementing timezone-aware cycle checking, which is the core backend change of this PR, and it is clear and concise without including unnecessary detail.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch operation-timezone

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • You’re mixing date-fns and moment-timezone for similar tasks—consider standardizing on one library and moving recurring timezone/date logic into shared utilities to reduce duplication and confusion.
  • The cron job now fires hourly and relies on an in-job midnight check—if possible, schedule jobs at each org’s actual local midnight (e.g. by computing cron patterns per timezone) to avoid extra hourly invocations.
  • You fetch the TIMEZONE config in multiple modules—extract that into a single helper or cache it at startup to DRY up the repeated TRPC calls.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- You’re mixing date-fns and moment-timezone for similar tasks—consider standardizing on one library and moving recurring timezone/date logic into shared utilities to reduce duplication and confusion.
- The cron job now fires hourly and relies on an in-job midnight check—if possible, schedule jobs at each org’s actual local midnight (e.g. by computing cron patterns per timezone) to avoid extra hourly invocations.
- You fetch the TIMEZONE config in multiple modules—extract that into a single helper or cache it at startup to DRY up the repeated TRPC calls.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Caution

Changes requested ❌

Reviewed everything up to 7aa0dfe in 2 minutes and 2 seconds. Click for details.
  • Reviewed 539 lines of code in 13 files
  • Skipped 0 files when reviewing.
  • Skipped posting 17 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. backend/plugins/operation_api/src/modules/cycle/utils.ts:130
  • Draft comment:
    Consider adding error handling around the TRPC call for fetching the timezone to safely fall back if the config is unavailable.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
2. backend/plugins/operation_api/src/modules/cycle/utils.ts:210
  • Draft comment:
    Verify that removing the $dateToString conversion in the projection (using '_id' directly) yields the expected date string format.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
3. backend/plugins/operation_api/src/modules/cycle/utils.ts:238
  • Draft comment:
    Using moment’s tz() for cycle start/end conversion is appropriate; ensure that cycle.startDate/endDate are stored in a compatible format.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
4. backend/plugins/operation_api/src/modules/cycle/utils.ts:256
  • Draft comment:
    The calculation of total days using 'end.diff(start, "days") + 1' looks good; verify that the boundaries are as expected in different timezones.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the PR author to verify the behavior of the code in different timezones, which falls under asking the author to ensure the behavior is intended. This violates the rules.
5. backend/plugins/operation_api/src/worker/dailyCheckCycles.ts:56
  • Draft comment:
    Using utcStart and utcEnd for cycle queries ensures timezone alignment; double-check that database timestamps are in UTC.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the PR author to double-check that database timestamps are in UTC, which violates the rule against asking the author to confirm or double-check things. It does not provide a specific code suggestion or point out a specific issue with the code.
6. backend/plugins/operation_api/src/worker/index.ts:13
  • Draft comment:
    The job scheduler pattern was changed to '0 * * * *' (hourly). Confirm that this adjustment is intentional to support timezone-based checks.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.
7. frontend/core-ui/src/modules/app/components/SettingsRoutes.tsx:125
  • Draft comment:
    Uncommenting and lazy-loading GeneralSettings is appropriate; ensure its bundle size and load time remain optimized.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the author to ensure that the bundle size and load time remain optimized, which falls under the category of asking the author to ensure something is tested or verified. This violates the rules.
8. frontend/core-ui/src/modules/settings/constants/data.ts:125
  • Draft comment:
    The new 'General' nav item inclusion looks correct; verify that its positioning within the navigation meets design expectations.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is asking the PR author to verify the positioning of a new navigation item, which falls under asking the author to double-check or ensure something. This violates the rules.
9. frontend/core-ui/src/modules/settings/general/components/GeneralSettings.tsx:27
  • Draft comment:
    Merging config values using spread operators in updateCurrency is clear; consider explicit handling for missing or invalid config values.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% While the suggestion isn't wrong, it's more of a "nice to have" than a clear issue. The code works as is - undefined/null values will be handled by JavaScript's spread operator. Without seeing the types or validation requirements, we can't be certain that explicit validation is needed. The comment is somewhat speculative. The code could potentially crash if configs is null/undefined. Also, invalid values could cause issues downstream if there's no validation. The configs null case is already handled by the loading check. For validation, without seeing the full validation requirements, this suggestion is too speculative. The comment should be removed as it's more of a speculative suggestion without clear evidence that explicit validation is required.
10. frontend/core-ui/src/modules/settings/general/components/SelectTimezone.tsx:9
  • Draft comment:
    The SelectTimezone component neatly integrates TimezoneSelect with react-hook-form; implementation looks good.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
11. frontend/core-ui/src/modules/settings/general/hooks/useGeneralSettingsForms.tsx:18
  • Draft comment:
    Using detectTimeZone() for the TIMEZONE default is a solid approach; ensure it returns a valid timezone string for moment-timezone compatibility.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative and suggests ensuring compatibility without providing a specific actionable suggestion or identifying a potential issue. It violates the rule against making purely informative comments.
12. frontend/core-ui/src/modules/settings/general/schema/index.ts:13
  • Draft comment:
    Including TIMEZONE in the schema enhances validation; consider validating against a set of allowed timezone strings if needed.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.
13. frontend/core-ui/src/modules/types/paths/SettingsPath.ts:11
  • Draft comment:
    Uncommenting the General path ensures the route is available; this straightforward change is correct.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
14. frontend/core-ui/src/pages/settings/workspace/GeneralSettingsPage.tsx:7
  • Draft comment:
    Wrapping content in PageContainer and ScrollArea improves layout and usability; implementation looks solid.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
15. frontend/plugins/operation_ui/src/modules/cycle/components/detail/CycleProgressChart.tsx:110
  • Draft comment:
    Adding an activeDot for the 'started' area enhances visual emphasis; ensure it aligns with overall chart design.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
16. frontend/plugins/operation_ui/src/modules/cycle/components/detail/CycleProgressChart.tsx:118
  • Draft comment:
    Similarly, the activeDot for the 'completed' area improves data visibility; the update is consistent with design improvements.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
17. backend/plugins/operation_api/src/worker/index.ts:40
  • Draft comment:
    The file is missing a newline at the end. Consider adding a newline for consistency and to avoid potential issues with tooling.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% While missing newlines can cause issues with some tools, this is typically caught by linters and formatters. The comment is about a code style issue rather than the actual functional changes being made. The rules specifically state to focus on the changes in the diff and that we should assume build tools would catch such issues. The missing newline could potentially cause merge conflicts or issues with some tools, so maybe it's worth keeping the comment? No, this is exactly the kind of issue that would be caught by standard build tools and linters. It's not related to the actual code changes being made. Delete the comment. It's about a minor formatting issue that would be caught by build tools, and it's not related to the actual changes being made to the cron pattern.

Workflow ID: wflow_RegpCUdV9aY8W342

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

export const fillMissingDays = (
data: { date: string; started: number; completed: number }[],
baseDate: Date,
baseDate: Moment,
Copy link
Contributor

Choose a reason for hiding this comment

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

Mixing moment and date-fns in this file might lead to inconsistencies; consider unifying date handling across utility functions.


const tzToday = tz(new Date(), timezone);

if (tzToday.hour() !== 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Relying on tzToday.hour() === 0 might skip execution if the job isn’t triggered exactly at midnight; consider checking within a small time window.

Copy link

@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 (5)
frontend/plugins/operation_ui/src/modules/cycle/components/detail/CycleProgressChart.tsx (1)

17-17: Consider replacing any with a proper type.

The statistics prop uses the any type, which bypasses TypeScript's type safety. Consider defining a proper interface for the statistics object structure.

Example refactor:

+interface ICycleStatistics {
+  chartData: IGetCycleProgressChart;
+  // Add other statistics properties as needed
+}
+
 export const CycleProgressChart = ({
   cycleId,
   isCompleted,
   statistics,
 }: {
   cycleId: string;
   isCompleted: boolean;
-  statistics: any;
+  statistics: ICycleStatistics;
 }) => {
backend/plugins/operation_api/src/worker/index.ts (1)

26-29: Replace console.log with structured logger.

Use a shared logger (levelled, JSON) instead of console.log for operability.

As per coding guidelines

Also applies to: 36-39

backend/plugins/operation_api/src/modules/project/utils/charUtils.ts (2)

28-38: Unify date handling; avoid mixing moment and date-fns here.

fillMissingDays is moment-based, while other helpers still use date-fns with string dates. This risks type/runtime mismatches (e.g., differenceInCalendarDays(targetDate, lastDate) where lastDate is string). Prefer converting remaining helpers to moment-timezone for consistency and TZ correctness, or normalize types to Date everywhere before operations.


2-2: Use type-only import for Moment.

Avoids pulling value space and clarifies intent:

-import { Moment } from 'moment-timezone';
+import type { Moment } from 'moment-timezone';
backend/plugins/operation_api/src/worker/dailyCheckCycles.ts (1)

18-22: Consider deduping hourly enqueues.

Hourly adds create 24 jobs/day/org; dedupe with deterministic jobId to reduce noise.

Example:

- sendWorkerQueue('operations', 'checkCycle').add('checkCycle', {
-   subdomain: org.subdomain,
-   timezone: org.timezone,
- });
+ const jobId = `checkCycle:${org.subdomain}:${new Date().toISOString().slice(0,10)}`;
+ sendWorkerQueue('operations', 'checkCycle').add(
+   'checkCycle',
+   { subdomain: org.subdomain, timezone: org.timezone },
+   { jobId, removeOnComplete: true, removeOnFail: 100 }
+ );

Apply similarly for the non‑SaaS branch.

Also applies to: 37-41

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64e3a85 and 7aa0dfe.

📒 Files selected for processing (13)
  • backend/plugins/operation_api/src/modules/cycle/utils.ts (6 hunks)
  • backend/plugins/operation_api/src/modules/project/utils/charUtils.ts (3 hunks)
  • backend/plugins/operation_api/src/worker/dailyCheckCycles.ts (3 hunks)
  • backend/plugins/operation_api/src/worker/index.ts (2 hunks)
  • frontend/core-ui/src/modules/app/components/SettingsRoutes.tsx (2 hunks)
  • frontend/core-ui/src/modules/settings/constants/data.ts (3 hunks)
  • frontend/core-ui/src/modules/settings/general/components/GeneralSettings.tsx (4 hunks)
  • frontend/core-ui/src/modules/settings/general/components/SelectTimezone.tsx (1 hunks)
  • frontend/core-ui/src/modules/settings/general/hooks/useGeneralSettingsForms.tsx (2 hunks)
  • frontend/core-ui/src/modules/settings/general/schema/index.ts (1 hunks)
  • frontend/core-ui/src/modules/types/paths/SettingsPath.ts (1 hunks)
  • frontend/core-ui/src/pages/settings/workspace/GeneralSettingsPage.tsx (1 hunks)
  • frontend/plugins/operation_ui/src/modules/cycle/components/detail/CycleProgressChart.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Write concise, technical TypeScript code
Use functional and declarative programming patterns; avoid classes
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Avoid console logs
Always use absolute paths for imports
Use TypeScript for all code (no .js/.jsx)
Prefer interfaces over types for object shapes
Avoid enums; use maps instead
Use the function keyword for pure functions
Avoid unnecessary curly braces in simple conditionals; use concise syntax

Files:

  • backend/plugins/operation_api/src/worker/index.ts
  • frontend/core-ui/src/pages/settings/workspace/GeneralSettingsPage.tsx
  • frontend/core-ui/src/modules/settings/general/components/GeneralSettings.tsx
  • frontend/core-ui/src/modules/settings/general/components/SelectTimezone.tsx
  • frontend/core-ui/src/modules/types/paths/SettingsPath.ts
  • frontend/core-ui/src/modules/settings/general/schema/index.ts
  • frontend/plugins/operation_ui/src/modules/cycle/components/detail/CycleProgressChart.tsx
  • frontend/core-ui/src/modules/settings/general/hooks/useGeneralSettingsForms.tsx
  • backend/plugins/operation_api/src/worker/dailyCheckCycles.ts
  • frontend/core-ui/src/modules/app/components/SettingsRoutes.tsx
  • backend/plugins/operation_api/src/modules/cycle/utils.ts
  • frontend/core-ui/src/modules/settings/constants/data.ts
  • backend/plugins/operation_api/src/modules/project/utils/charUtils.ts
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use declarative JSX
Use Shadcn UI, Radix UI, and Tailwind for components and styling
Implement responsive, mobile-first design with Tailwind CSS
Minimize useEffect and setState usage
Wrap client components in React.Suspense with a fallback
Use dynamic loading for non-critical components
Include explicit width and height (or sizes) when rendering images
Implement lazy loading for images
Limit 'use client': favor server components and Next.js SSR
Use 'use client' only for Web API access in small components
Do not use 'use client' components for data fetching or state management

Files:

  • frontend/core-ui/src/pages/settings/workspace/GeneralSettingsPage.tsx
  • frontend/core-ui/src/modules/settings/general/components/GeneralSettings.tsx
  • frontend/core-ui/src/modules/settings/general/components/SelectTimezone.tsx
  • frontend/plugins/operation_ui/src/modules/cycle/components/detail/CycleProgressChart.tsx
  • frontend/core-ui/src/modules/settings/general/hooks/useGeneralSettingsForms.tsx
  • frontend/core-ui/src/modules/app/components/SettingsRoutes.tsx
🧬 Code graph analysis (2)
frontend/core-ui/src/modules/settings/general/components/GeneralSettings.tsx (1)
frontend/core-ui/src/modules/settings/general/components/SelectTimezone.tsx (1)
  • SelectTimezone (5-25)
backend/plugins/operation_api/src/modules/cycle/utils.ts (1)
backend/plugins/operation_api/src/modules/project/utils/charUtils.ts (1)
  • fillMissingDays (26-57)
🪛 ESLint
frontend/core-ui/src/modules/settings/general/components/GeneralSettings.tsx

[error] 68-68: Expected an assignment or function call and instead saw an expression.

(@typescript-eslint/no-unused-expressions)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Sourcery review
  • GitHub Check: core-ui
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (16)
frontend/plugins/operation_ui/src/modules/cycle/components/detail/CycleProgressChart.tsx (1)

110-110: LGTM! Clean visual enhancement for chart interactivity.

The activeDot customization on both Area series improves the chart's hover interaction by providing clear visual feedback with appropriate sizing and consistent color usage from STATUS_COLORS.

Also applies to: 121-121

frontend/core-ui/src/modules/app/components/SettingsRoutes.tsx (2)

35-39: LGTM!

The lazy import for GeneralSettings follows the established pattern and correctly maps to the GeneralSettingsPage module.


126-129: LGTM!

The General route configuration is correctly structured and aligns with other workspace settings routes.

frontend/core-ui/src/modules/types/paths/SettingsPath.ts (1)

11-11: LGTM!

The General path addition follows the existing enum pattern and is positioned appropriately.

frontend/core-ui/src/modules/settings/constants/data.ts (1)

7-7: LGTM!

The General navigation entry is correctly structured with an appropriate icon and follows the established pattern for settings navigation items.

Also applies to: 124-128

frontend/core-ui/src/modules/settings/general/schema/index.ts (1)

13-13: LGTM!

The TIMEZONE field addition is correctly typed as a string. The TimezoneSelect component handles the valid timezone values, making additional schema validation unnecessary.

frontend/core-ui/src/modules/settings/general/hooks/useGeneralSettingsForms.tsx (1)

2-2: LGTM!

The TIMEZONE initialization using detectTimeZone() provides a sensible default based on the user's environment.

Also applies to: 18-18

frontend/core-ui/src/modules/settings/general/components/SelectTimezone.tsx (1)

1-25: LGTM!

The SelectTimezone component correctly integrates with react-hook-form using useFormContext and properly binds the TimezoneSelect control to the form field.

frontend/core-ui/src/pages/settings/workspace/GeneralSettingsPage.tsx (1)

3-20: LGTM!

The refactored layout using PageContainer and ScrollArea provides better structure and scrolling behavior. The constrained content width (max-w-2xl) improves readability for settings forms.

frontend/core-ui/src/modules/settings/general/components/GeneralSettings.tsx (3)

5-14: LGTM!

The import reordering and additions are appropriate for the new timezone functionality and improved state management.


27-41: LGTM!

The refactored updateCurrency now correctly merges all existing configs before overlaying new data, ensuring no config values are accidentally dropped during updates.


93-93: LGTM!

The SelectTimezone component is properly integrated into the form flow.

backend/plugins/operation_api/src/worker/index.ts (1)

13-15: Hourly schedule LGTM; matches timezone gating strategy.

The hourly trigger is fine, assuming checkCycle short-circuits outside local midnight.

Please confirm checkCycle returns early for non‑midnight hours to avoid unnecessary work (it should, given tzToday.hour() check).

backend/plugins/operation_api/src/modules/cycle/utils.ts (2)

192-196: Timezone-aware day bucketing via $dateToString looks correct.

Properly groups by local day before summing.


134-144: Verify TIMEZONE config return shape (string vs { value }). sendTRPCMessage returns the raw TRPC result and the core service implementation isn't in this repo — confirm core.configs.getConfig returns a plain string ('UTC') or an object (e.g., { value: 'UTC' }) and update to use timezone.value or handle both cases. Locations: backend/plugins/operation_api/src/modules/cycle/utils.ts:134-144, backend/plugins/operation_api/src/worker/dailyCheckCycles.ts:26-31.

backend/plugins/operation_api/src/worker/dailyCheckCycles.ts (1)

50-53: Midnight-hour guard is good.

Prevents work outside local midnight; aligns with hourly schedule.

Be mindful of TZ config correctness; a wrong/empty timezone would skip processing or run at wrong hour.

import { STATUS_TYPES } from '@/status/constants/types';
import { differenceInCalendarDays, startOfDay } from 'date-fns';
import { sendTRPCMessage } from 'erxes-api-shared/utils';
import { tz } from 'moment-timezone';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix moment-timezone import/usage (named tz is not exported).

Use default import and moment.tz(...) to avoid runtime/build errors.

Apply:

-import { tz } from 'moment-timezone';
+import moment from 'moment-timezone';

-  const start = tz(new Date(cycle.startDate), timezone);
-  const end = tz(new Date(cycle.endDate), timezone);
+  const start = moment.tz(new Date(cycle.startDate), timezone);
+  const end = moment.tz(new Date(cycle.endDate), timezone);

Also applies to: 253-259

🤖 Prompt for AI Agents
In backend/plugins/operation_api/src/modules/cycle/utils.ts around line 4 (and
similarly lines 253-259), the code imports a named export "tz" from
'moment-timezone' which doesn't exist at runtime; replace the named import with
a default import (import moment from 'moment-timezone') and update all calls
from tz(...) to moment.tz(...), ensuring any types/aliases are adjusted
accordingly so the module uses moment.tz for timezone-aware operations.

sendTRPCMessage,
sendWorkerQueue,
} from 'erxes-api-shared/utils';
import { tz } from 'moment-timezone';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Fix moment-timezone import/usage (named tz is not exported).

Switch to default import and moment.tz(...).

-import { tz } from 'moment-timezone';
+import moment from 'moment-timezone';

-  const tzToday = tz(new Date(), timezone);
+  const tzToday = moment.tz(new Date(), timezone);

-  const utcStart = tzToday.startOf('day').toDate();
-  const utcEnd = tzToday.endOf('day').toDate();
+  const utcStart = tzToday.startOf('day').toDate();
+  const utcEnd = tzToday.endOf('day').toDate();

Scan for similar incorrect imports:

Also applies to: 48-53, 56-58


🏁 Script executed:

#!/bin/bash
rg -nP "import\s*\{\s*tz\s*\}\s*from\s*'moment-timezone'"

Length of output: 197


🏁 Script executed:

#!/bin/bash
sed -n '1,50p' backend/plugins/operation_api/src/modules/cycle/utils.ts

Length of output: 1323


🏁 Script executed:

#!/bin/bash
rg -nP "tz\s*\(" backend/plugins/operation_api/src/modules/cycle/utils.ts

Length of output: 117


Fix moment-timezone import and usage
Replace import { tz } from 'moment-timezone'; with import moment from 'moment-timezone'; and update all tz(...) calls to moment.tz(...) in:

  • backend/plugins/operation_api/src/worker/dailyCheckCycles.ts
  • backend/plugins/operation_api/src/modules/cycle/utils.ts
🤖 Prompt for AI Agents
In backend/plugins/operation_api/src/worker/dailyCheckCycles.ts (around line 8)
and backend/plugins/operation_api/src/modules/cycle/utils.ts (search for tz
usage), replace the incorrect named import "import { tz } from
'moment-timezone';" with the default import "import moment from
'moment-timezone';" and update every call of tz(...) to use moment.tz(...);
ensure any existing references or typings are adjusted to use the moment
namespace (e.g., moment.tz(...)) consistently across both files.

Comment on lines +63 to +68
const timezone = configs?.find((data: any) => data.code === 'TIMEZONE');

methods.setValue('dealCurrency', currencies?.value);
methods.setValue('mainCurrency', mainCurrency?.value);

timezone && methods.setValue('TIMEZONE', timezone?.value);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix the unused expression on line 68.

The conditional expression on line 68 is flagged by ESLint because the result is not used. While it works, it violates best practices and linting rules.

Apply this diff to use an explicit conditional:

-      const timezone = configs?.find((data: any) => data.code === 'TIMEZONE');
-
       methods.setValue('dealCurrency', currencies?.value);
       methods.setValue('mainCurrency', mainCurrency?.value);
-
-      timezone && methods.setValue('TIMEZONE', timezone?.value);
+      
+      const timezone = configs?.find((data: any) => data.code === 'TIMEZONE');
+      if (timezone) {
+        methods.setValue('TIMEZONE', timezone.value);
+      }
📝 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 timezone = configs?.find((data: any) => data.code === 'TIMEZONE');
methods.setValue('dealCurrency', currencies?.value);
methods.setValue('mainCurrency', mainCurrency?.value);
timezone && methods.setValue('TIMEZONE', timezone?.value);
methods.setValue('dealCurrency', currencies?.value);
methods.setValue('mainCurrency', mainCurrency?.value);
const timezone = configs?.find((data: any) => data.code === 'TIMEZONE');
if (timezone) {
methods.setValue('TIMEZONE', timezone.value);
}
🧰 Tools
🪛 ESLint

[error] 68-68: Expected an assignment or function call and instead saw an expression.

(@typescript-eslint/no-unused-expressions)

🤖 Prompt for AI Agents
In frontend/core-ui/src/modules/settings/general/components/GeneralSettings.tsx
around lines 63 to 68, the expression "timezone && methods.setValue(...)" is an
unused conditional expression flagged by ESLint; replace it with an explicit
conditional statement (e.g., if (timezone) { methods.setValue('TIMEZONE',
timezone.value); }) so the side effect is performed clearly and the lint error
is resolved.

Copy link

@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: 1

🧹 Nitpick comments (1)
backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts (1)

628-631: Consider making fillUntilTargetDate timezone-aware
In backend/plugins/operation_api/src/modules/project/utils/charUtils.ts, fillUntilTargetDate uses native Date with date-fns (differenceInCalendarDays, addDays, format), which default to the system/local timezone. To ensure targetDate calculations respect your configured timezone, switch to timezone-aware utilities (e.g. zonedTimeToUtc/utcToZonedTime from date-fns-tz or moment-timezone).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7aa0dfe and f13ab98.

📒 Files selected for processing (1)
  • backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Write concise, technical TypeScript code
Use functional and declarative programming patterns; avoid classes
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Avoid console logs
Always use absolute paths for imports
Use TypeScript for all code (no .js/.jsx)
Prefer interfaces over types for object shapes
Avoid enums; use maps instead
Use the function keyword for pure functions
Avoid unnecessary curly braces in simple conditionals; use concise syntax

Files:

  • backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts
🧬 Code graph analysis (1)
backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts (1)
backend/plugins/operation_api/src/modules/project/utils/charUtils.ts (1)
  • fillMissingDays (26-57)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: operation_api-ci
  • GitHub Check: core-ui
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts (1)

672-672: fillFromLastDate uses date-fns on “YYYY-MM-DD” strings – no Moment conversion needed
This function deliberately mirrors the Date-based fillMissingDaysWithStartDate (not the Moment-based fillMissingDays), so it’s safe to leave it using addDays/format unless you specifically need timezone-aware logic.

import { differenceInCalendarDays } from 'date-fns';
import { requireLogin } from 'erxes-api-shared/core-modules';
import { cursorPaginate } from 'erxes-api-shared/utils';
import moment from 'moment';
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify timezone configuration is applied for timezone-aware date handling.

The changes correctly adapt to the updated fillMissingDays signature by wrapping dates with moment(). However, using moment(date) without an explicit timezone parameter defaults to the server's local timezone rather than the configured organization timezone.

According to the PR objectives, timezone configuration should be fetched (via sendTRPCMessage) and applied to date calculations. Ensure that either:

  1. The timezone is fetched and applied at this resolver level (e.g., moment.tz(date, timezone)), or
  2. The timezone handling is implemented within fillMissingDays or at another layer

Without explicit timezone handling, date calculations may behave inconsistently across different server environments, defeating the purpose of timezone-aware cycle checking.

Run the following script to verify how timezone is being handled:

Also applies to: 601-601, 617-617, 645-645, 664-664


🏁 Script executed:

#!/bin/bash
# Description: Check if timezone configuration is fetched and applied in project resolvers or charUtils

# Check if timezone is fetched in this file or related files
echo "=== Checking for timezone fetching in project resolvers ==="
rg -n -C5 "sendTRPCMessage|getTimezone|timezone" --type=ts backend/plugins/operation_api/src/modules/project/

# Check how moment is used in charUtils
echo -e "\n=== Checking moment usage in charUtils ==="
rg -n -C5 "moment\.tz|moment\(" --type=ts backend/plugins/operation_api/src/modules/project/utils/charUtils.ts

# Check if fillMissingDays handles timezone internally
echo -e "\n=== Checking fillMissingDays implementation ==="
ast-grep --pattern $'export const fillMissingDays = ($$$) => {
  $$$
}'

Length of output: 3987


Apply organization timezone to Moment calls
Fetch the org’s timezone (e.g. via sendTRPCMessage) and replace each plain moment(date) (project.ts:11, 601, 617, 645, 664) with moment.tz(date, timezone), or embed that logic in fillMissingDays/fillUntilTargetDate, to prevent defaulting to the server’s local timezone.

🤖 Prompt for AI Agents
In
backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts
around lines 11, 601, 617, 645, and 664, Moment is being called without the
organization's timezone which causes dates to default to the server local TZ;
fetch the org timezone (e.g. via sendTRPCMessage) and replace plain moment(date)
calls with moment.tz(date, timezone) or, preferably, modify
fillMissingDays/fillUntilTargetDate to accept a timezone parameter and apply
moment.tz(date, timezone) internally so all date parsing/normalization uses the
org timezone consistently.

@sonarqubecloud
Copy link

@batmnkh2344 batmnkh2344 merged commit 1354ad8 into main Oct 15, 2025
10 of 12 checks passed
@batmnkh2344 batmnkh2344 deleted the operation-timezone branch October 15, 2025 09:02
Copy link

@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: 0

♻️ Duplicate comments (1)
backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts (1)

11-11: Timezone issue flagged in previous review remains unresolved.

The concern raised in the previous review is still valid: moment(date) defaults to the server's local timezone rather than the organization's configured timezone. To ensure timezone-aware date handling per the PR objectives, fetch the organization's timezone (e.g., via sendTRPCMessage) and replace moment(date) with moment.tz(date, timezone), or refactor fillMissingDays to accept and apply a timezone parameter internally.

Also applies to: 601-601, 617-617, 645-645, 664-664

🧹 Nitpick comments (1)
backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts (1)

11-11: Consider migrating from Moment to modern date libraries.

Moment.js is in maintenance mode and its maintainers recommend alternatives (Luxon, date-fns, or Temporal) for new development. While not urgent for this PR, consider planning a migration to a modern, actively maintained date library to benefit from improved immutability, smaller bundle sizes, and ongoing feature development.

Based on learnings.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f13ab98 and 1ec5848.

📒 Files selected for processing (1)
  • backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Write concise, technical TypeScript code
Use functional and declarative programming patterns; avoid classes
Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
Avoid console logs
Always use absolute paths for imports
Use TypeScript for all code (no .js/.jsx)
Prefer interfaces over types for object shapes
Avoid enums; use maps instead
Use the function keyword for pure functions
Avoid unnecessary curly braces in simple conditionals; use concise syntax

Files:

  • backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts
🧬 Code graph analysis (1)
backend/plugins/operation_api/src/modules/project/graphql/resolvers/queries/project.ts (1)
backend/plugins/operation_api/src/modules/project/utils/charUtils.ts (1)
  • fillMissingDays (26-57)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: core-ui
  • GitHub Check: Analyze (javascript-typescript)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant