Skip to content

fix(admin-ui): remove moment.js and standardize date handling with da…#2615

Merged
moabu merged 12 commits intomainfrom
admin-ui-issue-2577
Jan 30, 2026
Merged

fix(admin-ui): remove moment.js and standardize date handling with da…#2615
moabu merged 12 commits intomainfrom
admin-ui-issue-2577

Conversation

@faisalsiddique4400
Copy link
Contributor

@faisalsiddique4400 faisalsiddique4400 commented Jan 28, 2026

fix(admin-ui): remove moment.js and standardize date handling with dayjs (#2577)

Summary

The Admin UI was using both moment.js and dayjs for date and time handling, which is redundant and increases bundle size unnecessarily. This PR removes moment.js and standardizes all date-related functionality on dayjs.

Problem

  • Both moment.js and dayjs were being used for the same purpose.
  • moment.js has a larger bundle size (~23 KB gzipped) and slower load time compared to dayjs.
  • Maintaining two libraries for the same responsibility adds unnecessary complexity.

Fix Details

  • Removed moment.js dependency from the project.
  • Refactored all existing date and time logic to use dayjs.
  • Ensured feature parity by mapping equivalent APIs where required.
  • Verified all date formatting, parsing, and comparison logic remains intact.

Result

  • Reduced bundle size and improved load performance.
  • Single, consistent date-time library across the Admin UI.
  • Cleaner dependency graph and easier long-term maintenance.

Additional Notes

This change aligns with modern frontend best practices and prepares the Admin UI for improved performance and maintainability.

🔗 Ticket

Closes: #2577

Summary by CodeRabbit

  • New Features

    • Centralized date utilities added (new formats, strict parsing, diff and parsing helpers).
  • Refactor

    • Replaced legacy date-library usage across the UI with the new date utilities for consistent formatting, parsing and comparisons.
    • Adjusted chunking to exclude the legacy date library from the utilities vendor group.
  • Chores

    • Removed the legacy date library from dependencies and updated docs/build guidance.
  • Style

    • Minor syntactic and whitespace cleanups.
  • Tests

    • Updated tests to use the new date utilities.

✏️ Tip: You can customize this high-level summary in your review settings.

@mo-auto mo-auto added area-documentation Documentation needs to change as part of issue or PR comp-admin-ui Component affected by issue or PR kind-bug Issue or PR is a bug in existing functionality labels Jan 28, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 28, 2026

📝 Walkthrough

Walkthrough

Removes the moment dependency, introduces centralized Dayjs utilities (DATE_FORMATS, parseDateStrict, diffDate, etc.), updates components/tests to use those utilities, adjusts webpack splitChunks/docs, and deletes moment from package.json.

Changes

Cohort / File(s) Summary
Core date utilities
admin-ui/app/utils/dayjsUtils.ts
Adds DATE_FORMATS, diffDate, parseDateStrict; changes formatDate default to DATE_FORMATS.DATE_ONLY; removes some legacy exports and re-exports.
Dependency & bundling
admin-ui/package.json, admin-ui/config/.../webpack.config.client.dev.ts, admin-ui/config/.../webpack.config.client.prod.ts, admin-ui/docs/CODE_SPLITTING.md
Removes moment from dependencies and from utils-vendor splitChunks/docs; adjusts vendor grouping.
Small TS tweak
admin-ui/app/utilities.tsx
Minor TypeScript syntax change: removed trailing semicolon in require.context keys signature.
Auth-server components & tests
admin-ui/plugins/auth-server/..., admin-ui/plugins/auth-server/.../JwkListPage.test.tsx, .../KeysPage.test.tsx
Replaces inline moment/dayjs usage with formatDate, diffDate, createDate, etc., across rendering, queries, sorting, CSV export and tests.
Admin components
admin-ui/plugins/admin/components/Assets/JansAssetListPage.tsx
Switched formatting to formatDate, adjusted event typing/handling for search input.
Sessions, Scopes, Keys UI
admin-ui/plugins/auth-server/components/Sessions/SessionListPage.tsx, .../Scopes/ScopeForm.tsx, .../Clients/ClientCibaParUmaPanel.js, .../Configuration/Keys/Jwks/JwkItem.tsx
Replaced moment usage with dayjs utility functions while preserving null-safety and display logic.
User management & helpers
admin-ui/plugins/user-management/components/..., .../helper/validations.ts, .../utils/attributeTransformUtils.ts, .../utils/userFormUtils.ts
Replaced moment with dayjs utilities; tightened birthdate parsing/validation using YYYY‑MM‑DD regex + parseDateStrict; coerced attribute values to strings where needed.
Dashboards & DateRange
admin-ui/app/routes/Dashboards/DashboardPage.tsx, admin-ui/app/routes/Dashboards/DateRange/index.tsx
Replaced direct Dayjs operations with helpers (createDate, subtractDate, isAfterDate, isBeforeDate, isSameDate, formatDate).
SAML forms (formatting only)
admin-ui/plugins/saml/components/WebsiteSsoIdentityProviderForm.tsx, .../WebsiteSsoServiceProviderForm.tsx
Whitespace/indentation changes in boolean expressions for error display; no semantic changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

kind-dependencies

Suggested reviewers

  • duttarnab
  • moabu

Poem

🐰 I hopped through code to trim the load,
Swapped Moment for Dayjs down the road.
Dates now strict, small bundles delight,
Tests and UI gleam in morning light.
A cheerful rabbit celebrates the light!

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive Minor out-of-scope formatting changes detected in WebsiteSsoIdentityProviderForm.tsx and WebsiteSsoServiceProviderForm.tsx that adjust whitespace/indentation without functional impact, unrelated to moment.js removal. Consider whether whitespace-only formatting changes in SAML components should be included in this PR or separated into a dedicated formatting update.
✅ 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 clearly summarizes the main change: removing moment.js and standardizing date handling with dayjs, which is the primary objective of the pull request.
Linked Issues check ✅ Passed The PR comprehensively addresses #2577 objectives: removes moment.js dependency, replaces moment APIs with dayjs equivalents across all date/time handling, maintains functionality parity, and reduces bundle size.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 admin-ui-issue-2577

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.

@sonarqubecloud
Copy link

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
admin-ui/plugins/user-management/components/User2FADevicesModal.tsx (1)

124-132: Avoid epoch date when addedOn is missing.
Using (item.addedOn || 0) * 1000 renders 1970-01-01 for missing values, which is misleading. Prefer a guard and show -/empty instead.

🛠️ Suggested fix
-          dateAdded: formatDate((item.addedOn || 0) * 1000, 'YYYY-MM-DD HH:mm:ss'),
+          dateAdded: item?.addedOn
+            ? formatDate(item.addedOn * 1000, 'YYYY-MM-DD HH:mm:ss')
+            : '-',
admin-ui/plugins/admin/components/Assets/JansAssetListPage.tsx (1)

79-96: Mutating outer-scope let variables inside useCallback won't persist across renders.

memoLimit and memoPattern (lines 58-59) are let variables in the component scope. Reassigning them inside handleOptionsChange (lines 83-85) modifies copies captured at callback creation time, but these changes won't persist or affect subsequent renders. The refresh action (lines 150-152) will use stale values.

Additionally, keyCode is deprecated; prefer using event.key === 'Enter' instead.

🐛 Suggested fix using refs or state
-  let memoLimit: number = limit
-  let memoPattern: string | undefined = pattern
+  const memoLimitRef = React.useRef<number>(limit)
+  const memoPatternRef = React.useRef<string | undefined>(pattern)
+
+  // Keep refs in sync with state
+  useEffect(() => {
+    memoLimitRef.current = limit
+    memoPatternRef.current = pattern
+  }, [limit, pattern])

Then in handleOptionsChange:

   const handleOptionsChange = useCallback(
     (event: React.ChangeEvent<HTMLInputElement> | React.KeyboardEvent<HTMLInputElement>) => {
       const target = event.target as HTMLInputElement
       if (target.name === 'limit') {
-        memoLimit = Number(target.value)
+        memoLimitRef.current = Number(target.value)
       } else if (target.name === 'pattern') {
-        memoPattern = String(target.value) || undefined
-        if ('keyCode' in event && event.keyCode === 13) {
+        memoPatternRef.current = String(target.value) || undefined
+        if ('key' in event && event.key === 'Enter') {
           const newOptions = {
             limit: limit,
-            pattern: memoPattern,
+            pattern: memoPatternRef.current,
           }
           dispatch(fetchJansAssets(newOptions))
         }
       }
     },
     [limit, dispatch],
   )
🤖 Fix all issues with AI agents
In `@admin-ui/plugins/auth-server/components/Clients/ClientActiveTokens.js`:
- Around line 204-209: The date format string used when formatting
item.expirationDate and item.creationDate is incorrect ('YYYY/DD/MM HH:mm:ss'
uses day and month swapped); update the format passed to formatDate in the
ClientActiveTokens component (the two places assigning expirationDate and
creationDate) to the intended format (e.g., 'YYYY/MM/DD HH:mm:ss' or 'DD/MM/YYYY
HH:mm:ss') so dates render correctly; ensure both occurrences use the same
corrected format string.

In `@admin-ui/plugins/user-management/components/UserDetailViewPage.tsx`:
- Around line 96-98: The ternary that checks typeof valueToShow === 'boolean' is
dead because valueToShow is always a string earlier in UserDetailViewPage
(assigned on lines ~69-76); remove the unreachable boolean branch and simplify
the expression to just convert valueToShow to a string (e.g., use
String(valueToShow)) where it is currently rendered, or alternatively adjust the
earlier assignments so valueToShow can be boolean if that was intended—update
the expression in the render (the ternary using valueToShow) accordingly.

In `@admin-ui/plugins/user-management/utils/attributeTransformUtils.ts`:
- Around line 48-55: The birthdate branch using attributeName === BIRTHDATE_ATTR
should validate and format strictly: replace the loose isValidDate(normalized)
check with a strict parse using dayjs with customParseFormat in strict mode (use
the same utility from dayjsUtils.ts) to both validate the date logic (reject
overflow like 2024-02-30) and produce the parsed instance for formatting; update
the logic in the attributeTransformUtils.ts block that currently tests
normalized with birthdatePattern and calls isValidDate/formatDate so it uses the
strict dayjs parse result for validation and then format the parsed instance to
'YYYY-MM-DD' to avoid timezone drift.

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

🤖 Fix all issues with AI agents
In `@admin-ui/app/utils/dayjsUtils.ts`:
- Around line 58-61: Add a short JSDoc atop the isValidDate function stating it
uses dayjs(date).isValid() which is lenient (it normalizes overflow dates like
"2024-02-30") and therefore not suitable for strict format validation; recommend
callers use parseDateStrict for exact format adherence and mention the accepted
input types (string | number | Date | Dayjs | null | undefined) and that
null/undefined return false.
- Around line 118-120: Remove the redundant cloneDate function: delete the
export const cloneDate definition (the function named cloneDate returning
dayjs(date).clone()) from admin-ui/app/utils/dayjsUtils.ts because Day.js
instances are immutable and cloning is unnecessary; also remove any unused Dayjs
import or related unused references in that module to keep imports clean and
ensure no linter warnings about an unused symbol.

In `@admin-ui/plugins/user-management/components/UserDetailViewPage.tsx`:
- Around line 66-72: The current viewer branch treats dates leniently by calling
isValidDate(raw) and formatting with formatDate, causing overflow dates (e.g.,
"2024-02-30") to be normalized; replace that check with the strict parser
parseDateStrict(raw) so only strictly parsed dates are shown: call
parseDateStrict on raw (from data?.values?.[0]) and if it returns a valid date,
format it (via formatDate) into "YYYY-MM-DD" and assign to valueToShow,
otherwise set valueToShow = '' to match attributeTransformUtils behavior.

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

🤖 Fix all issues with AI agents
In `@admin-ui/app/utils/dayjsUtils.ts`:
- Around line 73-84: The createDate function currently performs lenient parsing
when a format is provided (it calls dayjs(date, format) without strict mode),
which differs from parseDateStrict; add a JSDoc comment above createDate that
clearly states: the accepted input types, that providing a format enables
lenient (non-strict) parsing, and that callers who need strict validation should
use parseDateStrict; mention the default behavior when date is null and that the
function returns a Dayjs instance.

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

🤖 Fix all issues with AI agents
In `@admin-ui/app/utils/dayjsUtils.ts`:
- Around line 97-104: The default format string in formatDate duplicates the
constant DATE_FORMATS.DATE_ONLY; update formatDate to use DATE_FORMATS.DATE_ONLY
as the default (adjust the function signature default and ensure DATE_FORMATS is
imported where formatDate is defined) so callers and tests use the centralized
constant for the date-only format.

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: 2

🤖 Fix all issues with AI agents
In `@admin-ui/plugins/auth-server/components/Scopes/ScopeForm.tsx`:
- Around line 679-683: The defaultValue for the date field in ScopeForm.tsx uses
a redundant ternary checking scope.creationDate; replace the ternary with a
direct call to formatDate(scope.creationDate, 'YYYY-MM-DD HH:mm:ss') (remove the
?: branch) because the formatDate utility already handles null/undefined; update
the defaultValue in the JSX where scope.creationDate is used to rely solely on
formatDate.
- Around line 608-612: The defaultValue ternary can be simplified: remove the
explicit null/undefined check around scope.creationDate and pass
scope.creationDate directly into formatDate (which already returns '' for
null/undefined); update the defaultValue expression in ScopeForm (the block
using formatDate) to use formatDate(scope.creationDate, 'YYYY-MM-DD HH:mm:ss')
only, leaving the rest of the component (ScopeForm) unchanged.

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

🤖 Fix all issues with AI agents
In `@admin-ui/app/routes/Dashboards/DashboardPage.tsx`:
- Around line 35-41: The import alias formatDateDayjs is unclear; rename it to a
more descriptive identifier such as formatDayjsDate (or formatDateWithDayjs) in
the import from '@/utils/dayjsUtils' and update all usages in DashboardPage.tsx
to that new name (references include formatDateDayjs and related dayjs helpers
like createDate, isAfterDate, isBeforeDate). Ensure the other formatDate import
from Utils/Util remains unchanged to avoid collisions, or migrate callers to the
dayjs helper if you choose to consolidate.
- Around line 342-348: Add a centralized month format constant to DATE_FORMATS
in dayjsUtils.ts (e.g., MONTH_KEY or MONTH) and replace the inline string
'YYYYMM' in the dateMonths useMemo with that constant; update the call sites
that use formatDateDayjs(debouncedStartDate, 'YYYYMM') /
formatDateDayjs(debouncedEndDate, 'YYYYMM') (refer to the dateMonths memo and
formatDateDayjs usage) so they import and use DATE_FORMATS.MONTH_KEY instead of
the hardcoded literal.

In `@admin-ui/app/utils/dayjsUtils.ts`:
- Around line 11-17: DATE_FORMATS contains a TOKEN_DATETIME using the
nonstandard 'YYYY/DD/MM HH:mm:ss' order which may confuse future maintainers;
add a brief inline comment next to the TOKEN_DATETIME entry in the DATE_FORMATS
constant explaining that this specific day-before-month format is intentional
and required for the ClientActiveTokens component (mentioning ClientActiveTokens
and TOKEN_DATETIME) so readers know it must not be changed.

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: 2

🤖 Fix all issues with AI agents
In `@admin-ui/plugins/auth-server/components/Scopes/ScopeForm.tsx`:
- Around line 674-678: Replace the duplicated literal date format in the
ScopeForm display with the centralized constant: change the call to
formatDate(scope.creationDate, 'YYYY-MM-DD HH:mm:ss') to use
DATE_FORMATS.DATETIME_SECONDS instead; update the Input defaultValue expression
where formatDate is used so it references DATE_FORMATS.DATETIME_SECONDS (ensure
DATE_FORMATS is imported if not already).
- Around line 607-611: Replace the hard-coded date format string in the
ScopeForm component with the centralized constant: change the call using
formatDate(scope.creationDate, 'YYYY-MM-DD HH:mm:ss') to use
DATE_FORMATS.DATETIME_SECONDS; update the import if necessary so DATE_FORMATS is
available in ScopeForm.tsx and ensure the Input defaultValue uses
formatDate(scope.creationDate, DATE_FORMATS.DATETIME_SECONDS) to keep formatting
consistent across the app.

@sonarqubecloud
Copy link

@moabu moabu merged commit 03c9355 into main Jan 30, 2026
9 checks passed
@moabu moabu deleted the admin-ui-issue-2577 branch January 30, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-documentation Documentation needs to change as part of issue or PR comp-admin-ui Component affected by issue or PR kind-bug Issue or PR is a bug in existing functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(admin-ui) momentJs and daysJs both libraries are being used for same purpose. need to remove moment.

4 participants