Skip to content

Conversation

@dhirukumar
Copy link
Contributor

Proposed change

Resolves #2673

Summary

This PR implements skeleton loading components for the About, Organization, and Snapshots pages to improve user experience during data fetching. Users now see structured loading states instead of generic spinners, making the application feel more responsive and modern.

Before & After

Before:

  • Generic loading spinner shown during data fetch
  • No indication of page structure while loading
  • Less engaging user experience

After:

  • Page-specific skeleton loaders during data fetch
  • Clear indication of content structure
  • Consistent loading pattern across About, Organization, and Snapshots pages

Snapshots(Before)

Screenshot 2025-11-30 at 12 51 56 PM

Snapshots(After)

Screenshot 2025-11-30 at 12 55 12 PM

Organizations(Before)

Screenshot 2025-11-30 at 12 57 19 PM

Organizations(After)

Screenshot 2025-11-30 at 12 58 27 PM

About(Before)

Screenshot 2025-11-30 at 12 51 56 PM

About(After)

Screenshot 2025-11-30 at 1 01 30 PM

Changes Made

1. Created AboutSkeleton Component (src/components/skeletons/AboutSkeleton.tsx)

  • Added a comprehensive skeleton loader that mirrors the complete structure of the About page
  • Includes skeleton placeholders for all sections:
  • Uses HeroUI Skeleton components for smooth loading animations
  • Maintains responsive design matching the actual page layout

2. Created SnapshotSkeleton Component (src/components/skeletons/SnapshotSkeleton.tsx)

  • Added skeleton loader for snapshot cards
  • Includes placeholders for:
  • Matches the design and layout of actual snapshot cards
  • Responsive grid layout support

3. Updated About Page (src/app/about/page.tsx)

  • Replaced LoadingSpinner with AboutSkeleton for better loading UX
  • Imported the new AboutSkeleton component
  • Changed loading state to display skeleton instead of generic spinner
  • No changes to existing functionality or data fetching logic

4. Updated Snapshots Page (src/app/snapshots/page.tsx)

  • Integrated SnapshotSkeleton component for loading state
  • Improved user experience during snapshot data fetching
  • Maintains consistent loading pattern across the application

5. Updated SkeletonBase Component (src/components/SkeletonsBase.tsx)

  • Added 'about' case to the switch statement to return AboutSkeleton
  • Properly separated 'snapshots' case to return SnapshotSkeleton
  • Fixed unreachable code issue by properly separating case statements
  • Maintains support for existing skeleton types (chapters, issues, projects, committees, users, organizations)

6. Updated About Page Tests (__tests__/unit/pages/About.test.tsx)

  • Updated 'renders LoadingSpinner when project data is loading' test
  • Changed test to look for skeleton elements instead of loading spinner with alt text
  • Uses document.querySelectorAll to find skeleton container elements with specific CSS classes
  • All tests pass successfully

7. Updated Snapshots Page Tests (__tests__/unit/pages/Snapshots.test.tsx)

  • Updated tests to work with new SnapshotSkeleton component
  • Modified loading state assertions to check for skeleton elements
  • Maintained test coverage for snapshot page features

Technical Details

Files Created:

  • frontend/src/components/skeletons/AboutSkeleton.tsx (new component)
  • frontend/src/components/skeletons/SnapshotSkeleton.tsx (new component)

Files Modified:

  • frontend/src/components/SkeletonsBase.tsx (added new cases, fixed linting issue)
  • frontend/src/app/about/page.tsx (integrated AboutSkeleton)
  • frontend/src/app/snapshots/page.tsx (integrated SnapshotSkeleton)
  • frontend/__tests__/unit/pages/About.test.tsx (updated tests, removed duplicates)
  • frontend/__tests__/unit/pages/Snapshots.test.tsx (updated tests)

Benefits

  • Improved UX: Users see structured loading states instead of generic spinners
  • Better perceived performance: Skeletons show layout structure, making pages feel faster
  • Consistent with modern web practices: Skeleton loaders are industry standard
  • Responsive design: Skeletons adapt to all screen sizes just like actual pages
  • Better code quality: Fixed linting issues (unreachable code, trailing whitespace)
  • Unified loading experience: Consistent skeleton pattern across multiple pages

Testing

  • ✅ Loading states properly tested with skeleton elements
  • ✅ No breaking changes to existing functionality
  • ✅ Manual testing verified skeletons display correctly during loading
  • make check-test runs successfully

Checklist

  • I've read and followed the contributing guidelines.
  • I've run make check-test locally; all checks and tests passed.
  • Code follows the project's coding standards and conventions
  • Fixed existing code quality issues (unreachable code, trailing whitespace)

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 30, 2025

Summary by CodeRabbit

  • New Features

    • Enhanced loading states with skeleton placeholders on About and Snapshots pages for improved user experience during content loading.
  • Improvements

    • Updated snapshot action button label for greater clarity.
    • Refined milestone status visual positioning.
    • Improved loading UI with better placeholder grid layouts.

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

Walkthrough

Replaces LoadingSpinner with skeleton placeholders on About and Snapshots pages, adds AboutSkeleton and SnapshotSkeleton components, updates SkeletonsBase to register them and use stable keys, and updates unit tests to assert skeleton-based loading states.

Changes

Cohort / File(s) Summary
New skeleton components
frontend/src/components/skeletons/AboutSkeleton.tsx, frontend/src/components/skeletons/SnapshotSkeleton.tsx
Adds AboutSkeleton (full About page skeleton) and SnapshotSkeleton (card skeleton with optional parts) as new default-export React components.
Pages: loading UI changes
frontend/src/app/about/page.tsx, frontend/src/app/snapshots/page.tsx
Replaces LoadingSpinner with AboutSkeleton; snapshots page now shows a grid of 12 SnapshotSkeleton placeholders while loading, guards rendering behind the loading check, and renames snapshot action label from "View Details" to "View Snapshot".
Skeleton registry / helpers
frontend/src/components/SkeletonsBase.tsx
Imports new skeletons, adds snapshotCardRender() and stable string keys (*-skeleton-{index}), maps organizations to the user skeleton renderer, and adds branches for snapshots and about.
Unit tests
frontend/__tests__/unit/pages/About.test.tsx, frontend/__tests__/unit/pages/Snapshots.test.tsx
Tests updated to assert skeleton presence: About test selects elements with class .bg-gray-100.dark:bg-gray-800 and Snapshots test queries role="status" asserting at least one loading element exists (replacing image-based LoadingSpinner assertions).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review AboutSkeleton and SnapshotSkeleton markup for accessibility (roles, aria labels) and responsive/dark-mode classes.
  • Verify SkeletonsBase changes preserve existing skeleton branches and that stable keys don't introduce duplicate-key issues.
  • Confirm pages' loading guards and renamed button label don't break downstream logic or tests.

Possibly related PRs

Suggested reviewers

  • arkid15r
  • kasya

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add skeleton loading states for About, Organization, and Snapshot pages' clearly summarizes the main change: adding skeleton components for loading states across three pages.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the motivation, changes made, technical details, benefits, and testing performed.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issue #2673: adds skeleton components to Snapshots and About pages, maintains layout consistency, reuses existing skeleton patterns, and ensures responsive design.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing skeleton loading states as specified in issue #2673. Minor code quality fixes (unreachable code, trailing whitespace) and test updates are directly supporting the main objective.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8db0854 and ac84948.

📒 Files selected for processing (1)
  • frontend/src/app/about/page.tsx (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/app/about/page.tsx

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

🧹 Nitpick comments (5)
frontend/__tests__/unit/pages/About.test.tsx (1)

414-416: Loading-state assertion works but is tightly coupled to Tailwind classes

The new check correctly verifies the skeleton-based loading state, but querying via document.querySelectorAll('.bg-gray-100.dark\\:bg-gray-800') is brittle and bypasses Testing Library’s querying patterns. Consider exposing a more semantic handle from AboutSkeleton (e.g., role="status" on the main containers or a data-testid) and then using screen.getAllByRole('status') or getAllByTestId(...) here. That would also avoid the awkward escaped selector and keep the test resilient to styling changes.

frontend/__tests__/unit/pages/Snapshots.test.tsx (1)

62-63: Good switch to role-based loading assertion

Using screen.getAllByRole('status') aligns nicely with SnapshotSkeleton’s role="status" and is more robust than image alt-text checks. If you want to tighten clarity, you could also rename the test description from “renders loading spinner” to mention skeletons, but that’s purely cosmetic.

frontend/src/app/snapshots/page.tsx (1)

9-9: Snapshot skeleton grid and loading guard are wired correctly

The new SnapshotSkeleton import, “View Snapshot” label, and the isLoading-guarded grid (skeletons vs. real cards / empty state) match the intended UX and the updated tests. If you ever revisit this, you could consider leaning directly on Apollo’s loading flag instead of a separate isLoading state to cut a bit of bookkeeping, but the current approach is functionally sound.

Also applies to: 44-44, 63-79

frontend/src/components/skeletons/SnapshotSkeleton.tsx (1)

10-36: SnapshotSkeleton structure looks solid; consider adding an accessible name

The component gives a clear, flexible skeleton layout for snapshot cards, and role="status" works well with the tests and intent of signaling a loading region. Right now, though, that status region has no accessible name or text, so screen readers may not convey what’s happening. Consider adding something like aria-label="Loading snapshot" (or a visually hidden descriptive text) on the root <div> so assistive tech users get meaningful feedback while the skeleton is shown.

frontend/src/components/skeletons/AboutSkeleton.tsx (1)

3-152: Comprehensive AboutSkeleton matches the page layout; optional a11y/test improvements

This skeleton does a good job mirroring all the major About sections (mission, features, leaders, contributors, tech, roadmap, story, timeline, stats) so the layout remains stable while data loads. To make it both more accessible and less tied to Tailwind classes in tests, you might consider giving the main skeleton cards a semantic marker—e.g., a wrapper with role="status"/aria-busy="true" or a dedicated data-testid—and then updating the About tests to query by role or test id instead of CSS selectors. That would keep the implementation free to evolve its exact styling without breaking tests while also giving assistive tech a clearer signal that content is loading.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 28ef47f and 0a24171.

📒 Files selected for processing (7)
  • frontend/__tests__/unit/pages/About.test.tsx (1 hunks)
  • frontend/__tests__/unit/pages/Snapshots.test.tsx (1 hunks)
  • frontend/src/app/about/page.tsx (2 hunks)
  • frontend/src/app/snapshots/page.tsx (3 hunks)
  • frontend/src/components/SkeletonsBase.tsx (2 hunks)
  • frontend/src/components/skeletons/AboutSkeleton.tsx (1 hunks)
  • frontend/src/components/skeletons/SnapshotSkeleton.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-12T17:36:57.255Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/__tests__/unit/pages/createProgram.test.tsx:70-86
Timestamp: 2025-07-12T17:36:57.255Z
Learning: When testing React page components that use mocked form components, validation logic should be tested at the form component level, not the page level. Page-level tests should focus on authentication, role checking, submission handling, and navigation logic.

Applied to files:

  • frontend/__tests__/unit/pages/Snapshots.test.tsx
📚 Learning: 2025-11-17T16:47:05.578Z
Learnt from: anurag2787
Repo: OWASP/Nest PR: 2671
File: frontend/__tests__/unit/components/MultiSearch.test.tsx:427-427
Timestamp: 2025-11-17T16:47:05.578Z
Learning: In the frontend test files for the OWASP/Nest repository, `expect(true).toBe(true)` no-op assertions may be intentionally added as workarounds when ESLint rule jest/expect-expect doesn't detect expectations inside helper functions or waitFor callbacks. These can be resolved by configuring the ESLint rule's assertFunctionNames option to recognize custom assertion helpers instead of flagging them as redundant.

Applied to files:

  • frontend/__tests__/unit/pages/About.test.tsx
🧬 Code graph analysis (1)
frontend/src/app/snapshots/page.tsx (1)
frontend/src/types/snapshot.ts (1)
  • Snapshot (15-20)
🪛 GitHub Check: SonarCloud Code Analysis
frontend/src/components/SkeletonsBase.tsx

[warning] 23-23: Do not use Array index in keys

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrTsasVm_AGdvKrIhXg&open=AZrTsasVm_AGdvKrIhXg&pullRequest=2757

frontend/src/app/snapshots/page.tsx

[warning] 66-66: Do not use Array index in keys

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrTsa0Qm_AGdvKrIhXl&open=AZrTsa0Qm_AGdvKrIhXl&pullRequest=2757

frontend/__tests__/unit/pages/About.test.tsx

[warning] 415-415: String.raw should be used to avoid escaping \.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrTsa0om_AGdvKrIhXm&open=AZrTsa0om_AGdvKrIhXm&pullRequest=2757

frontend/src/components/skeletons/SnapshotSkeleton.tsx

[warning] 16-19: Use instead of the "status" role to ensure accessibility across all devices.

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrTsawkm_AGdvKrIhXh&open=AZrTsawkm_AGdvKrIhXh&pullRequest=2757

🔇 Additional comments (2)
frontend/src/app/about/page.tsx (1)

42-42: AboutSkeleton integration for loading state looks correct

Importing AboutSkeleton and returning it when projectMetadataLoading || topContributorsLoading || leadersLoading is true cleanly replaces the old spinner and keeps the rest of the control flow (404 handling, main render) unchanged. This should give a stable layout during load without altering data or error semantics.

Also applies to: 100-104

frontend/src/components/SkeletonsBase.tsx (1)

3-6: Extended SkeletonsBase mappings are consistent and fix the special cases cleanly

Factoring user and snapshot skeleton grids into userCardRender / snapshotCardRender, reusing the user grid for organizations, and adding explicit cases for snapshots and about keeps SkeletonsBase cohesive and avoids the previous “generic card” mismatch. The early returns for these index names also make the control flow clearer and sidestep the old unreachable-wrapper issue.

Also applies to: 7-27, 62-69

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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a24171 and 2b9e737.

📒 Files selected for processing (5)
  • frontend/__tests__/unit/pages/About.test.tsx (1 hunks)
  • frontend/src/app/about/page.tsx (5 hunks)
  • frontend/src/app/snapshots/page.tsx (3 hunks)
  • frontend/src/components/SkeletonsBase.tsx (2 hunks)
  • frontend/src/components/skeletons/SnapshotSkeleton.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/src/components/skeletons/SnapshotSkeleton.tsx
  • frontend/tests/unit/pages/About.test.tsx
  • frontend/src/app/snapshots/page.tsx
🔇 Additional comments (3)
frontend/src/components/SkeletonsBase.tsx (1)

3-70: LGTM! Clean implementation of new skeleton loading states.

The changes follow existing patterns consistently:

  • Updated key generation using template strings improves clarity over raw indices
  • New snapshotCardRender properly mirrors userCardRender structure
  • Switch cases for 'organizations', 'snapshots', and 'about' correctly return early, maintaining consistency with the 'users' case
  • No control flow issues or unreachable code
frontend/src/app/about/page.tsx (2)

42-42: LGTM! AboutSkeleton successfully replaces LoadingSpinner.

The integration correctly addresses the PR objective by providing a skeleton-based loading state instead of the generic spinner, maintaining consistent UX across the application.

Also applies to: 123-123


53-71: LGTM! Helper functions improve code organization.

The new getMilestoneStatus and getMilestoneIcon functions cleanly extract milestone rendering logic, making the code more maintainable and testable. The mapping logic is correct and usage is consistent.

Also applies to: 241-241, 248-248

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

🧹 Nitpick comments (2)
frontend/src/app/about/page.tsx (2)

53-71: Milestone helpers are clear and align with backend progress semantics

getMilestoneStatus and getMilestoneIcon nicely centralize milestone-display logic and match the 0–100% progress contract from the backend snippet, making the roadmap UI easier to reason about and test. As an optional robustness tweak, you could use >= 100 instead of === 100 if you ever change how progress is computed, but it isn’t required given the current backend implementation.


260-262: Index key on static projectStory list is acceptable despite Sonar warning

Using the array index as the key here is reasonable because projectStory is static, ordered content that isn’t re-ordered or dynamically mutated, and it avoids potential duplicate-key issues you’d get from using the paragraph text itself. The Sonar warning is generic; in this specific case you can likely treat it as a false positive. If you ever need to make this list dynamic, consider changing projectStory to include explicit IDs and keying on those, but that feels out of scope for this PR.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b9e737 and 5a75871.

📒 Files selected for processing (1)
  • frontend/src/app/about/page.tsx (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/app/about/page.tsx (1)
backend/apps/github/api/internal/nodes/milestone.py (1)
  • progress (40-45)
🪛 GitHub Check: SonarCloud Code Analysis
frontend/src/app/about/page.tsx

[warning] 261-261: Do not use Array index in keys

See more on https://sonarcloud.io/project/issues?id=OWASP_Nest&issues=AZrV3MpFs0OCvQ2jhcFA&open=AZrV3MpFs0OCvQ2jhcFA&pullRequest=2757

🔇 Additional comments (4)
frontend/src/app/about/page.tsx (4)

42-42: AboutSkeleton import cleanly integrates page-specific loading UI

Importing AboutSkeleton here keeps the About page’s loading state consistent with the new skeleton system and avoids coupling to a generic spinner. No issues from this change.


120-124: Switch to AboutSkeleton for loading state is correct and on-brief

Using <AboutSkeleton /> when any of the queries are loading keeps layout stable and aligns the About page with the platform’s skeleton-based loading pattern, without touching the data-fetching logic.


239-249: Refactoring milestone tooltip to use helpers improves consistency

Wiring the tooltip content and icon through getMilestoneStatus(milestone.progress) and getMilestoneIcon(milestone.progress) removes duplicated status logic and keeps text and icon state in sync for roadmap milestones. This is a solid cleanup with no apparent edge-case regressions.


275-278: Timeline dot offset change is a harmless Tailwind normalization

Changing from a hard-coded top-[10px] to top-2.5 keeps the visual alignment while relying on Tailwind’s spacing scale, which is more consistent with utility-class conventions. No functional or accessibility concerns from this tweak.

@sonarqubecloud
Copy link

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

@dhirukumar Thanks for working on this!
The PR description and title says that this should cover About, Organization and Snapshot pages, but I only see skeletons on About and Snapshot pages.

Do you plan to add Organization page too?

Also left a request ⬇️ and there are conflicts that you need to fix ⚙️

Copy link
Collaborator

Choose a reason for hiding this comment

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

The skeleton state is narrower than the final page layout, which causes a visible jump on reload.
Could you update this to match the Snapshot page layout?

Snapshots-.-OWASP-Nest.mp4

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.

Missing Skeleton Loading State in Snapshot & About Pages

2 participants