Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: pr cards #46

Merged
merged 2 commits into from
Feb 11, 2025
Merged

feat: pr cards #46

merged 2 commits into from
Feb 11, 2025

Conversation

waltergalvao
Copy link
Member

@waltergalvao waltergalvao commented Feb 11, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a new pull request field to display the first approval timestamp.
    • Added a status badge and timeline view to enhance visibility of pull request events.
    • Implemented custom hooks for improved handling of pull request data and badges.
  • Refactor

    • Streamlined pull request components by consolidating multiple properties into a single data object.
    • Updated icon styles and simplified UI components for a more consistent user experience.
  • Style

    • Applied new card styling for a refined and polished appearance.

@sweetr-dev sweetr-dev bot added the huge Huge PR - High risk of reviewer fatigue label Feb 11, 2025
Copy link

coderabbitai bot commented Feb 11, 2025

Walkthrough

The changes update the logic for calculating the time to first approval in pull request tracking by using additional dates and a helper function. Additionally, the GraphQL queries and types now include a new firstApprovalAt field. Several UI components have been refactored to pass a single pullRequest object rather than multiple individual props. Some badge components have been removed and replaced with a new BadgeStatus component. New hooks and components have been added to encapsulate badge and pull request display logic, while some outdated visual components have been deleted.

Changes

File(s) Change Summary
apps/api/src/app/pull-requests/resolvers/.../pull-request-tracking.transformer.ts Updated logic for calculating timeToFirstApproval by using calculateTimeForEvent with additional date fields.
apps/web/src/api/pull-request.api.ts Added the new firstApprovalAt field to the GraphQL query tracking object.
apps/web/src/app/home/components/my-open-pull-requests/my-open-pull-requests.tsx, apps/web/src/app/home/components/team-open-pull-requests/team-open-pull-requests.tsx, apps/web/src/app/people/[handle]/pull-requests/page.tsx, apps/web/src/app/teams/[id]/pull-requests/page.tsx, apps/web/src/components/card-pull-request/card-pull-request.tsx Refactored components to pass a single pullRequest object, removing individual prop mappings and updating imports/usage.
apps/web/src/components/card-pull-request/card-pull-request.module.css, apps/web/src/components/card-pull-request/icon-pull-request-state.tsx Introduced a new .card CSS class and updated ThemeIcon properties (variant, size, and color adjustments).
apps/web/src/components/card-pull-request/badge-status.tsx, apps/web/src/components/card-pull-request/timeline-pull-request.tsx, apps/web/src/components/card-pull-request/use-badges.tsx, apps/web/src/components/card-pull-request/use-pr-card.tsx Added new components (BadgeStatus, TimelinePullRequest) and hooks (useBadges, usePrCard) to encapsulate badge management and pull request display logic.
apps/web/src/components/card-pull-request/badge-code-review-time.tsx, apps/web/src/components/card-pull-request/badge-merge-time.tsx Removed obsolete badge components and their associated interfaces and helper functions.
packages/graphql-types/frontend/gql.ts, packages/graphql-types/frontend/graphql.ts Updated GraphQL query and type definitions for PullRequests to include the firstApprovalAt field in the tracking object.

Possibly related PRs

  • feat: digests page #26: Both the current and this PR modify the handling of the firstApprovalAt field in the pull request tracking logic.
  • feat: metrics digest #35: This PR and the current one involve changes related to the calculation and usage of approval timestamps for pull requests.

Suggested labels

enhancement, large

Suggested reviewers

  • sweetrdev
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

@waltergalvao waltergalvao changed the title ref(web): pr card ref: pr card Feb 11, 2025
@waltergalvao waltergalvao changed the title ref: pr card feat: pr cards Feb 11, 2025
@waltergalvao waltergalvao marked this pull request as ready for review February 11, 2025 15:29
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 (11)
apps/web/src/components/card-pull-request/card-pull-request.tsx (2)

34-35: Hook usage seems clean.
Leveraging usePrCard to encapsulate pull request–specific logic (e.g., getTimeLabel) is a solid approach. Consider supplementing with unit tests to ensure stable behavior.


41-148: Consider lazy-loading the TimelinePullRequest.
Wrapping the timeline in a HoverCard is a great UX improvement. For performance-sensitive apps, you might load timeline details on demand (e.g., upon hover) to reduce initial bundle size.

apps/web/src/components/card-pull-request/icon-pull-request-state.tsx (1)

17-17: Favor theme-based colors over hard-coded hex.
Using variant="transparent" is a good move for a cleaner look, but consider referencing theme constants instead of hex codes to ensure consistent updates across the app.

Also applies to: 25-25, 33-33, 41-41

apps/web/src/components/card-pull-request/badge-status.tsx (2)

10-23: Consider aligning colors with Mantine’s theme system.
Hard-coding color variables is flexible, but leveraging the Mantine theme or a shared constants file may reduce styling discrepancies and make global updates simpler.


25-38: Implementation is straightforward and effective.
The extracted BadgeStatus component is cohesive. For a lighter footprint, you could also explore Mantine’s built-in <Badge> component, though your approach gives you more control.

apps/web/src/components/card-pull-request/use-pr-card.tsx (1)

16-26: Consider making comment thresholds configurable.

The hardcoded thresholds (30, 20) for comment count visualization could be made configurable through theme variables or constants.

+const COMMENT_THRESHOLDS = {
+  HIGH: 30,
+  MEDIUM: 20,
+} as const;
+
 const getCommentFlameProps = (comments: number) => {
-  if (comments >= 30) {
+  if (comments >= COMMENT_THRESHOLDS.HIGH) {
     return { color: theme.colors.red[8], fill: theme.colors.red[8] };
   }

-  if (comments >= 20) {
+  if (comments >= COMMENT_THRESHOLDS.MEDIUM) {
     return { color: theme.colors.red[6] };
   }

   return { color: theme.colors.red[4] };
 };
apps/web/src/components/card-pull-request/use-badges.tsx (3)

26-52: Consider making time thresholds configurable.

The hook uses hardcoded time thresholds (24h, 48h) for determining badge states. Consider making these configurable to allow for different team workflows and requirements.

+interface BadgeThresholds {
+  review: {
+    warning: number;
+    error: number;
+    success: number;
+  };
+  approval: {
+    warning: number;
+    error: number;
+    success: number;
+  };
+}
+
+const defaultThresholds: BadgeThresholds = {
+  review: {
+    warning: 24,
+    error: 48,
+    success: 2,
+  },
+  approval: {
+    warning: 24,
+    error: 48,
+    success: 2,
+  },
+};
+
-export const useBadges = (pullRequest: PullRequest) => {
+export const useBadges = (
+  pullRequest: PullRequest,
+  thresholds: BadgeThresholds = defaultThresholds,
+) => {

38-46: Consider centralizing color values in a theme configuration.

The color values are hardcoded in the component. Consider moving them to a centralized theme configuration for better maintainability and consistency.

+const badgeColors = {
+  error: {
+    start: 'var(--mantine-color-red-5)',
+    end: 'var(--mantine-color-pink-5)',
+  },
+};
+
 if (hasBadgeOf("error")) {
-  return {
-    start: "var(--mantine-color-red-5)",
-    end: "var(--mantine-color-pink-5)",
-  };
+  return badgeColors.error;
 }

1-179: Add unit tests for badge generation logic.

The badge generation logic is complex and would benefit from comprehensive unit tests to ensure reliability.

Would you like me to generate unit test cases for the badge generation logic? The tests would cover various scenarios such as:

  • Badge states for different time thresholds
  • Color determination based on badge states
  • Edge cases for merged/closed pull requests
apps/web/src/components/card-pull-request/timeline-pull-request.tsx (2)

28-30: Consider centralizing color values in a theme configuration.

The color values are hardcoded in the component. Consider moving them to a centralized theme configuration for better maintainability and consistency.

+const timelineColors = {
+  success: 'var(--mantine-color-green-4)',
+  error: 'var(--mantine-color-red-4)',
+  warning: 'var(--mantine-color-yellow-4)',
+};
+
-const successColor = "var(--mantine-color-green-4)";
-const errorColor = "var(--mantine-color-red-4)";
-const warningColor = "var(--mantine-color-yellow-4)";

114-119: Consider using a localization system for text strings.

Text strings are hardcoded in the component. Consider moving them to a localization system for better maintainability and internationalization support.

+const timelineMessages = {
+  draft: 'Drafted',
+  opened: 'Opened',
+  firstReviewed: 'First reviewed',
+  firstReview: 'First review',
+  approved: 'Approved',
+  approval: 'Approval',
+  closed: 'Closed',
+  merged: 'Merged',
+  merge: 'Merge',
+  in: 'in',
+  awaitingFor: 'awaiting for',
+  skipped: 'Skipped',
+};
+
-title={isDraft ? "Drafted" : "Opened"}
+title={isDraft ? timelineMessages.draft : timelineMessages.opened}

Also applies to: 129-141, 145-166, 169-184

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3fc4c10 and 4e917e5.

📒 Files selected for processing (17)
  • apps/api/src/app/pull-requests/resolvers/transformers/pull-request-tracking.transformer.ts (1 hunks)
  • apps/web/src/api/pull-request.api.ts (1 hunks)
  • apps/web/src/app/home/components/my-open-pull-requests/my-open-pull-requests.tsx (1 hunks)
  • apps/web/src/app/home/components/team-open-pull-requests/team-open-pull-requests.tsx (1 hunks)
  • apps/web/src/app/people/[handle]/pull-requests/page.tsx (1 hunks)
  • apps/web/src/app/teams/[id]/pull-requests/page.tsx (1 hunks)
  • apps/web/src/components/card-pull-request/badge-code-review-time.tsx (0 hunks)
  • apps/web/src/components/card-pull-request/badge-merge-time.tsx (0 hunks)
  • apps/web/src/components/card-pull-request/badge-status.tsx (1 hunks)
  • apps/web/src/components/card-pull-request/card-pull-request.module.css (1 hunks)
  • apps/web/src/components/card-pull-request/card-pull-request.tsx (1 hunks)
  • apps/web/src/components/card-pull-request/icon-pull-request-state.tsx (1 hunks)
  • apps/web/src/components/card-pull-request/timeline-pull-request.tsx (1 hunks)
  • apps/web/src/components/card-pull-request/use-badges.tsx (1 hunks)
  • apps/web/src/components/card-pull-request/use-pr-card.tsx (1 hunks)
  • packages/graphql-types/frontend/gql.ts (2 hunks)
  • packages/graphql-types/frontend/graphql.ts (2 hunks)
💤 Files with no reviewable changes (2)
  • apps/web/src/components/card-pull-request/badge-merge-time.tsx
  • apps/web/src/components/card-pull-request/badge-code-review-time.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/web/src/components/card-pull-request/card-pull-request.module.css
🧰 Additional context used
🪛 Biome (1.9.4)
apps/web/src/components/card-pull-request/timeline-pull-request.tsx

[error] 139-139: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


[error] 164-164: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

🔇 Additional comments (12)
apps/web/src/components/card-pull-request/card-pull-request.tsx (3)

16-24: Imports look well-organized.
No issues found with the new and updated imports; breaking out functionality into specialized modules (e.g., usePrCard, useBadges) helps keep the component thin and focused.


27-30: Good prop consolidation into a single pullRequest object.
This design choice simplifies prop management and makes the component easier to maintain. Keep up the modular approach.


36-38: Badge logic is well abstracted.
Extracting badge logic into useBadges and rendering them via BadgeStatus is a neat approach. It promotes reusability and keeps code organized.

Also applies to: 86-99

apps/web/src/components/card-pull-request/use-pr-card.tsx (1)

9-44: LGTM! Well-structured hook implementation.

The hook effectively encapsulates pull request display logic, making it reusable across components.

apps/api/src/app/pull-requests/resolvers/transformers/pull-request-tracking.transformer.ts (1)

37-41: LGTM! Improved time to first approval calculation.

The calculation now correctly considers multiple date fields in order of priority: firstApprovalAt, firstReadyAt, or prCreatedAt.

apps/web/src/api/pull-request.api.ts (1)

66-66: LGTM! Added firstApprovalAt field.

The field addition aligns with the tracking transformer changes and enhances pull request data.

apps/web/src/app/home/components/my-open-pull-requests/my-open-pull-requests.tsx (1)

83-85: LGTM! Simplified pull request rendering.

The refactor reduces prop drilling by passing the entire pull request object, making the code more maintainable and aligned with the single responsibility principle.

apps/web/src/app/home/components/team-open-pull-requests/team-open-pull-requests.tsx (1)

93-95: LGTM! Clean refactor to use a single pullRequest prop.

The changes simplify the component's interface by passing the entire pull request object instead of individual props, making the code more maintainable and reducing prop drilling.

apps/web/src/app/people/[handle]/pull-requests/page.tsx (1)

105-105: LGTM! Consistent refactor to use a single pullRequest prop.

The changes maintain consistency with other components by using the consolidated pull request object.

apps/web/src/app/teams/[id]/pull-requests/page.tsx (1)

186-186: LGTM! Improved prop passing pattern.

The change to pass a single pullRequest object instead of individual props is a good improvement that reduces prop drilling and makes the component more maintainable.

packages/graphql-types/frontend/gql.ts (1)

40-40: LGTM! GraphQL query properly updated.

The PullRequests query has been correctly updated to include the new firstApprovalAt field in the tracking object, maintaining type safety and schema consistency.

Also applies to: 1044-1044

packages/graphql-types/frontend/graphql.ts (1)

923-923: LGTM! Type definitions properly updated.

The PullRequestsQuery type has been correctly updated to include the new firstApprovalAt field with proper typing, ensuring type safety throughout the application.

Comment on lines +133 to +140
{hasReviews && timeToFirstReview && (
<>in {humanizeDuration(timeToFirstReview)}</>
)}
{!hasReviews && timeToFirstReview && (
<>awaiting for {humanizeDuration(timeToFirstReview)}</>
)}
{!hasReviews && isDone && <>Skipped</>}
</Text>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unnecessary Fragment usage.

The Fragment wrapper is unnecessary when there's only one child element.

{hasReviews && timeToFirstReview && (
-  <>in {humanizeDuration(timeToFirstReview)}</>
+  `in ${humanizeDuration(timeToFirstReview)}`
)}
{!hasReviews && timeToFirstReview && (
-  <>awaiting for {humanizeDuration(timeToFirstReview)}</>
+  `awaiting for ${humanizeDuration(timeToFirstReview)}`
)}
{!hasReviews && isDone && (
-  <>Skipped</>
+  "Skipped"
)}
📝 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
{hasReviews && timeToFirstReview && (
<>in {humanizeDuration(timeToFirstReview)}</>
)}
{!hasReviews && timeToFirstReview && (
<>awaiting for {humanizeDuration(timeToFirstReview)}</>
)}
{!hasReviews && isDone && <>Skipped</>}
</Text>
{hasReviews && timeToFirstReview && (
`in ${humanizeDuration(timeToFirstReview)}`
)}
{!hasReviews && timeToFirstReview && (
`awaiting for ${humanizeDuration(timeToFirstReview)}`
)}
{!hasReviews && isDone && "Skipped"}
</Text>
🧰 Tools
🪛 Biome (1.9.4)

[error] 139-139: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

@waltergalvao waltergalvao merged commit 0ea63d2 into main Feb 11, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
huge Huge PR - High risk of reviewer fatigue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants