Skip to content

Conversation

@drifter089
Copy link
Owner

@drifter089 drifter089 commented Jan 9, 2026

Summary

Creates a reusable KpiCard component that displays goal progress, time tracking, cadence, and role assignments in a compact format. This consolidates the previously separate EditTeamMetricCard and SidebarMetricCard implementations into a single unified component.

Key Changes

  • Add new KpiCard component at src/components/metric/kpi-card.tsx
  • Replace EditTeamMetricCard implementation with KpiCard wrapper
  • Replace SidebarMetricCard in dashboard sidebar with KpiCard
  • Add barrel export for metric components
  • Use consistent metric naming (chartTransform?.title ?? metric.name)
  • Display stacked progress bars: goal progress (row 1) + time progress (row 2)
  • Show time elapsed %, time remaining, and cadence
  • Show assigned roles with first role + count format
  • Add accessibility improvements (aria-labels, aria-hidden)

Summary by CodeRabbit

  • Refactor

    • Consolidated metric card components across the dashboard and team views into a unified KpiCard component.
    • Streamlined metric card interface while maintaining existing drag-and-drop, settings, visibility toggle, and progress visualization features.
  • Documentation

    • Added centralized exports for metric components (KpiCard, GoalProgressDisplay, RoleAssignment) for improved code organization.

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

@vercel
Copy link

vercel bot commented Jan 9, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
org-os Ready Ready Preview, Comment Jan 9, 2026 1:57pm

@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

This PR introduces a new shared KpiCard component that consolidates metric card functionality including drag-and-drop, settings, visibility controls, and progress visualization. Existing metric card implementations in the dashboard sidebar and team edit pages are refactored to use this new component, with the component exported from the metric module's index.

Changes

Cohort / File(s) Summary
New KpiCard Component
src/components/metric/kpi-card.tsx
Introduces draggable KPI card with platform color bar, title, processing badge, settings dialog, visibility toggle, goal/time progress indicators, role display, and canvas state handling.
Module Exports
src/components/metric/index.ts
Centralizes exports for GoalProgressDisplay, KpiCard, and RoleAssignment components.
Dashboard Sidebar Refactor
src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
Replaces internal SidebarMetricCard component with KpiCard; adjusts metric-related props from chartNodesOnCanvas/onToggleChartVisibility to isOnCanvas/onToggleVisibility.
Team Metric Card Refactor
src/app/teams/_components/edit-team-metric-card.tsx
Simplifies EditTeamMetricCard to delegate rendering directly to KpiCard component.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A card for metrics, shared and bright,
With drag-and-drop and colors right,
KpiCard hops into place with glee,
Replacing scattered code—now unified! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: introducing a unified KpiCard component that consolidates previous implementations and includes goal progress tracking features.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@claude
Copy link
Contributor

claude bot commented Jan 9, 2026

Pull Request Review

Overview

This PR successfully consolidates two separate metric card implementations (EditTeamMetricCard and SidebarMetricCard) into a single reusable KpiCard component. The change reduces code duplication and creates a more maintainable codebase. Net result: +293/-201 lines (92 net lines added, primarily due to enhanced functionality).


Strengths

  1. Excellent Code Consolidation

    • Successfully eliminates duplication between two similar components
    • Well-designed prop interface with clear optional parameters for different use cases
    • Good use of default parameters (showSettings = true, enableDragDrop = false)
  2. Accessibility Improvements

    • Added aria-label to drag handle (line 110)
    • Added aria-hidden="true" to decorative elements (lines 113, 122)
    • Maintains semantic HTML structure
  3. Consistent Naming

    • Uses chartTransform?.title ?? metric.name pattern consistently with existing codebase conventions
    • Follows the established pattern from DashboardMetricCard
  4. Good Component Documentation

    • Clear JSDoc comments for formatTimeRemaining function
    • Well-structured prop comments grouping canvas-specific props
  5. Clean Barrel Export

    • Properly added to src/components/metric/index.ts for clean imports

⚠️ Issues & Concerns

1. Potential Division by Zero Bug (Lines 78-81)

const timeElapsedPercent = goalProgress
  ? (goalProgress.daysElapsed /
      (goalProgress.daysElapsed + goalProgress.daysRemaining)) *
    100
  : null;

Risk: If both daysElapsed and daysRemaining are 0, this will result in NaN.

Recommendation:

const timeElapsedPercent = goalProgress
  ? (goalProgress.daysElapsed + goalProgress.daysRemaining) > 0
    ? (goalProgress.daysElapsed /
        (goalProgress.daysElapsed + goalProgress.daysRemaining)) *
      100
    : 0
  : null;

2. Unsafe Array Access (Lines 262, 265)

style={{ backgroundColor: roles[0]!.color }}
// ...
{roles[0]!.title}

Issue: Using non-null assertion (!) when roles.length > 0 check exists, but this is fragile if the array is modified between check and access.

Recommendation: Consider extracting the first role:

{roles.length > 0 && (
  <>
    {(() => {
      const firstRole = roles[0];
      return (
        <div className="flex items-center gap-1 text-[10px]">
          <div
            className="h-1.5 w-1.5 shrink-0 rounded-full"
            style={{ backgroundColor: firstRole.color }}
          />
          <span className="text-muted-foreground truncate font-medium">
            {firstRole.title}
          </span>
          {roles.length > 1 && (
            <span className="text-muted-foreground/60 shrink-0">
              +{roles.length - 1}
            </span>
          )}
        </div>
      );
    })()}
  </>
)}

Or simpler:

const firstRole = roles[0];
{roles.length > 0 && firstRole ? (
  // ... use firstRole directly
) : (
  // ... no role state
)}

3. Hardcoded Color Values

Lines 207-210 and 227 use hardcoded color classes:

  • bg-green-500, bg-primary, bg-amber-500
  • bg-blue-500

Recommendation: Extract these to constants or use Tailwind config variables for consistency with the design system.

4. Missing Import Path Resolution

Line 14: import type { GoalProgress } from "@/lib/goals";

Issue: The file path should be @/lib/goals/types based on the grep results. The current import suggests there's a barrel export at @/lib/goals/index.ts, but this wasn't verified in the PR diff.

Verification needed: Ensure @/lib/goals/index.ts properly exports GoalProgress type.


🔍 Additional Observations

1. Test Coverage

  • No test files found for the new KpiCard component
  • Recommendation: Add unit tests, especially for:
    • Edge cases (empty roles, missing goal progress, division by zero)
    • Drag and drop behavior
    • Button interaction states

2. Performance Consideration

Line 88: draggable={canDrag ? true : undefined}

Minor optimization: This could be simplified to draggable={canDrag || undefined} since true is not needed (any truthy value enables dragging).

3. Inline Styles

Lines 213, 229, 262 use inline style prop for dynamic values. This is acceptable for truly dynamic values (progress percentages, role colors), but consider if there's a more Tailwind-native approach for progress bars.

4. Component Size

The component is 283 lines, which is reasonable but getting large. If more features are added, consider extracting sub-components:

  • <GoalProgressBars />
  • <RoleDisplay />
  • <MetricHeader />

🎯 Recommendations Priority

High Priority:

  1. ✅ Fix potential division by zero bug (lines 78-81)
  2. ✅ Verify @/lib/goals import path is correct
  3. ✅ Add test coverage for new component

Medium Priority:
4. Consider extracting first role to avoid repeated non-null assertions
5. Extract hardcoded color values to constants

Low Priority:
6. Simplify draggable prop expression
7. Consider component size if adding more features


Conclusion

This is a solid refactoring PR that successfully consolidates duplicate code and adds valuable features (goal progress, time tracking). The code quality is generally high, with good accessibility practices and clear documentation.

Recommendation: Approve with minor fixes for the division by zero bug and import path verification. The other issues are suggestions for improvement but not blockers.

Great work on the consolidation! 🎉

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

🧹 Nitpick comments (3)
src/app/teams/_components/edit-team-metric-card.tsx (1)

4-4: Consider using barrel export for consistency.

The KpiCard component is exported via the barrel export at src/components/metric/index.ts. Using the barrel export would be more consistent with the module's public API.

♻️ Optional refactor to use barrel export
-import { KpiCard } from "@/components/metric/kpi-card";
+import { KpiCard } from "@/components/metric";
src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx (1)

13-13: Consider using barrel export for consistency.

Same as edit-team-metric-card.tsx, using the barrel export would be more consistent.

♻️ Optional refactor to use barrel export
-import { KpiCard } from "@/components/metric/kpi-card";
+import { KpiCard } from "@/components/metric";
src/components/metric/kpi-card.tsx (1)

197-246: Enhance accessibility of progress bars.

The progress bars display goal and time progress visually but lack semantic ARIA attributes for screen readers. Adding role="progressbar", aria-valuenow, aria-valuemin, aria-valuemax, and descriptive aria-label attributes would improve accessibility.

♻️ Proposed accessibility enhancements
 {/* Goal Progress Row */}
 <div className="flex items-center gap-1.5 text-[10px]">
-  <div className="bg-muted h-1 w-14 overflow-hidden rounded-full">
+  <div 
+    className="bg-muted h-1 w-14 overflow-hidden rounded-full"
+    role="progressbar"
+    aria-label="Goal progress"
+    aria-valuenow={Math.round(goalProgress.progressPercent)}
+    aria-valuemin={0}
+    aria-valuemax={100}
+  >
     <div
       className={cn(
         "h-full transition-all",
         goalProgress.progressPercent >= 100
           ? "bg-green-500"
           : goalProgress.progressPercent >= 70
             ? "bg-primary"
             : "bg-amber-500",
       )}
       style={{
         width: `${Math.min(goalProgress.progressPercent, 100)}%`,
       }}
     />
   </div>

 {/* Time Progress Row */}
 <div className="flex items-center gap-1.5 text-[10px]">
-  <div className="bg-muted h-1 w-14 overflow-hidden rounded-full">
+  <div 
+    className="bg-muted h-1 w-14 overflow-hidden rounded-full"
+    role="progressbar"
+    aria-label="Time elapsed"
+    aria-valuenow={Math.round(timeElapsedPercent)}
+    aria-valuemin={0}
+    aria-valuemax={100}
+  >
     <div
       className="h-full bg-blue-500 transition-all"
       style={{
         width: `${Math.min(timeElapsedPercent, 100)}%`,
       }}
     />
   </div>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b024a1 and d6d53de.

📒 Files selected for processing (4)
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/components/metric/index.ts
  • src/components/metric/kpi-card.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Use TypeScript 5.9 with strict type checking for all frontend and backend code

Files:

  • src/components/metric/index.ts
  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use @trivago/prettier-plugin-sort-imports with inline type imports for import organization

Files:

  • src/components/metric/index.ts
  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
src/**/*.tsx

📄 CodeRabbit inference engine (GEMINI.md)

Prefer Server Components for initial data fetching; use Client Components ('use client') only for interactivity

Files:

  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
src/**/*/*.tsx

📄 CodeRabbit inference engine (GEMINI.md)

Client Components must use import { api } from '@/trpc/react' for standard HTTP/Hooks wrapper

Files:

  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
src/components/**/*.tsx

📄 CodeRabbit inference engine (GEMINI.md)

Place colocated components in _components/ folders next to their parent component

Use shadcn/ui components from src/components/ui/; add new components via CLI: npx shadcn@latest add [component-name]

Files:

  • src/components/metric/kpi-card.tsx
**/*.tsx

📄 CodeRabbit inference engine (GEMINI.md)

Use Tailwind CSS 4 for styling with shadcn/ui and Radix UI primitive components

Files:

  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
src/app/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

src/app/**/*.tsx: Use the dual tRPC API pattern: direct calls in Server Components (api.team.getById) for 10x faster performance, and React hooks in Client Components (api.team.getById.useQuery)
Use getUserDisplayName(userId, members) utility (client-side sync) from @/lib/helpers/get-user-name for displaying user names in components

Files:

  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/components/dashboard-metric-card.tsx,src/app/dashboard/[teamId]/_components/public-dashboard-metric-card.tsx : Dashboard metric cards are duplicated with public variant. Consolidate into single component with `readOnly` mode prop instead of maintaining separate components.
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/(metric|dashboard)/**/*.tsx : Use three-stage metrics transformation: API → DataPoints (DataIngestionTransformer), DataPoints → ChartConfig (ChartTransformer), ChartConfig → UI (DashboardMetricChart)
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/lib/metrics/**/*.ts : Goal calculation utility is 271 lines and should be refactored to approximately 50 lines. Simplify logic and extract helper functions.
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Use shared MetricDialogBase component from base/ for all metric dialog implementations
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Metric dialog components have nearly identical wrapper patterns (5 files). Consider implementing a factory pattern or generic wrapper to reduce duplication across provider dialogs.
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/teams/[teamId]/_components/role-node.tsx,src/app/teams/[teamId]/_components/public-role-node.tsx : These role node components are 75% identical and should be consolidated. Extract shared `RoleNodeTemplate` component with `isEditable` prop to DRY up the code.
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Use shared MetricDialogBase component from base/ for all metric dialog implementations

Applied to files:

  • src/components/metric/index.ts
  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/components/dashboard-metric-card.tsx,src/app/dashboard/[teamId]/_components/public-dashboard-metric-card.tsx : Dashboard metric cards are duplicated with public variant. Consolidate into single component with `readOnly` mode prop instead of maintaining separate components.

Applied to files:

  • src/components/metric/index.ts
  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Create metric dialogs with pattern: [Provider]MetricDialog.tsx (dialog wrapper) + [Provider]MetricContent.tsx (form content) in src/app/metric/_components/[provider]/, then register in index.ts

Applied to files:

  • src/components/metric/index.ts
  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/lib/metrics/**/*.ts : Goal calculation utility is 271 lines and should be refactored to approximately 50 lines. Simplify logic and extract helper functions.

Applied to files:

  • src/components/metric/index.ts
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Metric dialog components should follow the pattern: [Provider]MetricDialog.tsx (dialog wrapper) and [Provider]MetricContent.tsx (form content). Register in src/app/metric/_components/index.ts and inherit from shared MetricDialogBase.

Applied to files:

  • src/components/metric/index.ts
  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/(metric|dashboard)/**/*.tsx : Use three-stage metrics transformation: API → DataPoints (DataIngestionTransformer), DataPoints → ChartConfig (ChartTransformer), ChartConfig → UI (DashboardMetricChart)

Applied to files:

  • src/components/metric/index.ts
  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/metric/_components/**/*.tsx : Metric dialog components have nearly identical wrapper patterns (5 files). Consider implementing a factory pattern or generic wrapper to reduce duplication across provider dialogs.

Applied to files:

  • src/components/metric/index.ts
  • src/components/metric/kpi-card.tsx
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: Applies to src/lib/metrics/**/*.ts : Metric transformation logic should be organized in `src/lib/metrics/` to support the 3-stage pipeline: Ingestion → Aggregation → Visualization

Applied to files:

  • src/components/metric/index.ts
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/hooks/**/*.ts : For role-metric cache updates, optimistically update both role cache (role.getByTeamId) and dashboard cache (dashboard.getDashboardCharts) to maintain UI consistency

Applied to files:

  • src/components/metric/index.ts
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/dashboard/[teamId]/**/*.{ts,tsx} : Dashboard cache updates for role-metric assignments must update both `role.getByTeamId` and `dashboard.getDashboardCharts` caches during mutations. Use onMutate for optimistic updates on both caches, then invalidate both on success.

Applied to files:

  • src/components/metric/index.ts
  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
📚 Learning: 2025-12-29T12:52:42.935Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T12:52:42.935Z
Learning: Applies to src/app/teams/[teamId]/_components/role-node.tsx,src/app/teams/[teamId]/_components/public-role-node.tsx : These role node components are 75% identical and should be consolidated. Extract shared `RoleNodeTemplate` component with `isEditable` prop to DRY up the code.

Applied to files:

  • src/app/teams/_components/edit-team-metric-card.tsx
📚 Learning: 2025-12-20T22:12:00.576Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-20T22:12:00.576Z
Learning: Applies to src/app/teams/[teamId]/**/*.tsx : React Flow nodes must store minimal data (e.g., just `roleId`); fetch full Role data from TanStack Query cache in the Node component to keep canvas and sidebars in sync

Applied to files:

  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/teams/[teamId]/**/*.tsx : Use reusable canvas library patterns from src/lib/canvas/ (create-canvas-store.tsx, use-auto-save.ts, save-status.tsx, edge-action-buttons.tsx, floating-edge-utils.ts)

Applied to files:

  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
📚 Learning: 2025-12-29T21:27:04.176Z
Learnt from: CR
Repo: drifter089/orgOS PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:27:04.176Z
Learning: Applies to src/app/teams/[teamId]/**/*.tsx : Use shared React Flow primitives (BaseNode, BaseHandle, ZoomSlider) from src/components/react-flow/ in all canvas implementations

Applied to files:

  • src/app/teams/_components/edit-team-metric-card.tsx
  • src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx
🧬 Code graph analysis (2)
src/app/teams/_components/edit-team-metric-card.tsx (2)
src/components/metric/index.ts (1)
  • KpiCard (2-2)
src/components/metric/kpi-card.tsx (1)
  • KpiCard (55-283)
src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx (2)
src/components/metric/index.ts (1)
  • KpiCard (2-2)
src/components/metric/kpi-card.tsx (1)
  • KpiCard (55-283)
⏰ 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). (1)
  • GitHub Check: claude-review
🔇 Additional comments (8)
src/app/teams/_components/edit-team-metric-card.tsx (1)

11-16: LGTM! Clean delegation pattern.

The component successfully delegates to the shared KpiCard while maintaining its public interface. The default props (showSettings=true, enableDragDrop=false) are appropriate for the edit team context.

src/components/metric/index.ts (1)

1-3: LGTM! Clean barrel export pattern.

The barrel export provides a centralized public API for metric components, making imports more consistent across the codebase.

src/app/dashboard/[teamId]/_components/dashboard-sidebar.tsx (1)

180-191: LGTM! Successful integration of KpiCard.

The prop mapping is correct and maintains backward compatibility:

  • isOnCanvas is properly computed from the chartNodesOnCanvas Set
  • onToggleChartVisibility (parent prop) correctly maps to onToggleVisibility (KpiCard prop)
  • All drag-drop handlers are properly wired
  • The component functionality is fully preserved
src/components/metric/kpi-card.tsx (5)

20-32: LGTM! Time formatting logic is sound.

The helper correctly handles different cadences and uses Math.max to prevent negative values. Colocation is appropriate since this is only used within KpiCard.


66-84: LGTM! Component setup is well-structured.

The initialization logic is correct:

  • Processing state properly disables dragging
  • Title fallback pattern (chartTransform?.title ?? metric.name) aligns with established conventions
  • Time elapsed percentage calculation is mathematically sound
  • Proper null handling with optional chaining and nullish coalescing

86-104: LGTM! Drag-and-drop implementation is robust.

The implementation correctly:

  • Uses draggable={canDrag ? true : undefined} to avoid adding the attribute when false
  • Calls stopPropagation() to prevent event bubbling
  • Guards handler invocation with conditional checks
  • Applies appropriate styling for all drag states

256-279: LGTM! Role display implementation is correct.

The role display properly handles multiple roles by showing the first role with a colored indicator and a "+N" count for additional roles. The non-null assertions on lines 262 and 265 are justified because they're guarded by the roles.length > 0 check. The "No role" fallback provides appropriate feedback.


34-53: LGTM! Well-documented interface with sensible defaults.

The interface clearly separates required props from optional canvas-specific props. The JSDoc comments provide good context for each prop's purpose, and the defaults (showSettings=true, enableDragDrop=false) are appropriate for the primary use cases.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants