Repository: ballerine-io/ballerine
Pull request #3246: fix: exclude child workflows & use cases state for status graph (BAL-3985, BAL-3993)
Author: login: r4zendev
Created: 2025-04-16T12:46:25Z | Merged: 2025-04-16T13:13:19Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Enhanced status and risk level displays with both color and descriptive text labels for improved clarity in dashboards and charts.
  - Metrics and charts now display a "No Data Available" message when relevant data is missing.

- **Bug Fixes**
  - Improved type safety for status badge labels in filters.

- **Refactor**
  - Updated internal logic to use more descriptive status and risk definitions.
  - Streamlined data queries to focus on root-level case records and active states.
  - Updated navigation links to include additional query parameters for date filtering.

- **Style**
  - Minor adjustments to import order for consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts b/apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts
index ef5423c304..b158f8ef49 100644
--- a/apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts
+++ b/apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts
@@ -3,6 +3,7 @@ import { useEffect, useMemo, type ComponentProps } from 'react';
 import { titleCase } from 'string-ts';
 import { z } from 'zod';
 
+import { StateTag } from '@ballerine/common';
 import { DateRangePicker } from '@/common/components/organisms/DateRangePicker/DateRangePicker';
 import { useLocale } from '@/common/hooks/useLocale/useLocale';
 import { useZodSearchParams } from '@/common/hooks/useZodSearchParams/useZodSearchParams';
@@ -22,20 +23,30 @@ export const HomeSearchSchema = z.object({
     .optional(),
 });
 
-const RISK_LEVEL_COLORS = {
-  low: '#4CAF50',
-  medium: '#FFB74D',
-  high: '#FF5722',
-  critical: '#F44336',
-};
+type PieChartDefinition = Record<string, { color: string; text: string }>;
 
-const STATUS_COLORS = {
-  active: '#007aff',
-  completed: '#4CAF50',
-  failed: '#F44336',
-  // pending: '#FFB74D',
+const RISK_LEVEL_DEFINITION: PieChartDefinition = {
+  low: { color: '#4CAF50', text: 'Low Risk' },
+  medium: { color: '#FFB74D', text: 'Medium Risk' },
+  high: { color: '#FF5722', text: 'High Risk' },
+  critical: { color: '#F44336', text: 'Critical Risk' },
 };
 
+const STATUS_DEFINITION: PieChartDefinition = {
+  [StateTag.APPROVED]: { color: '#4CAF50', text: 'Approved' },
+  [StateTag.REVISION]: { color: '#FFB74D', text: 'Revisions' },
+  [StateTag.EDIT]: { color: '#FFB74D', text: 'Edit' },
+  [StateTag.REJECTED]: { color: '#F44336', text: 'Rejected' },
+  [StateTag.RESOLVED]: { color: '#4CAF50', text: 'Resolved' },
+  [StateTag.MANUAL_REVIEW]: { color: '#007AFF', text: 'Manual Review' },
+  [StateTag.COLLECTION_FLOW]: { color: '#961EEE', text: 'Collection in Progress' },
+  [StateTag.PENDING_PROCESS]: { color: '#FFB74D', text: 'Pending ID Verification' },
+  [StateTag.FAILURE]: { color: '#F44336', text: 'Failed' },
+  [StateTag.DATA_ENRICHMENT]: { color: '#961EEE', text: 'Awaiting 3rd Party Data' },
+  [StateTag.DISMISSED]: { color: '#4CAF50', text: 'Dismissed' },
+  [StateTag.FLAGGED]: { color: '#F44336', text: 'Flagged' },
+} as const;
+
 export const useHomeLogic = () => {
   const locale = useLocale();
   const { data: session } = useAuthenticatedUserQuery();
@@ -92,12 +103,22 @@ export const useHomeLogic = () => {
 
   const { data: currentStats, isLoading: isLoadingCurrentStats } = useCaseCurrentStats();
 
-  const getStatusColor = (status: string) => {
-    return STATUS_COLORS[status.toLowerCase() as keyof typeof STATUS_COLORS] ?? '#65afff';
+  const getStatusDefinition = (status: string) => {
+    return (
+      STATUS_DEFINITION[status.toLowerCase() as keyof typeof STATUS_DEFINITION] ?? {
+        color: '#65afff',
+        text: 'Unknown',
+      }
+    );
   };
 
-  const getRiskColor = (risk: string) => {
-    return RISK_LEVEL_COLORS[risk.toLowerCase() as keyof typeof RISK_LEVEL_COLORS] ?? '#65afff';
+  const getRiskDefinition = (risk: string) => {
+    return (
+      RISK_LEVEL_DEFINITION[risk.toLowerCase() as keyof typeof RISK_LEVEL_DEFINITION] ?? {
+        color: '#65afff',
+        text: 'Unknown',
+      }
+    );
   };
 
   type ConfigItem = { label: string; color: string };
@@ -109,7 +130,7 @@ export const useHomeLogic = () => {
         ...acc,
         [curr.status]: {
           label: titleCase(curr.status),
-          color: getStatusColor(curr.status),
+          color: getStatusDefinition(curr.status),
         },
       }),
       {},
@@ -123,7 +144,7 @@ export const useHomeLogic = () => {
         ...acc,
         [curr.riskLevel]: {
           label: titleCase(curr.riskLevel),
-          color: getRiskColor(curr.riskLevel),
+          color: getRiskDefinition(curr.riskLevel),
         },
       }),
       {},
@@ -137,37 +158,13 @@ export const useHomeLogic = () => {
         ...acc,
         [curr.riskLevel]: {
           label: titleCase(curr.riskLevel),
-          color: getRiskColor(curr.riskLevel),
+          color: getRiskDefinition(curr.riskLevel),
         },
       }),
       {},
     );
   }, [currentStats]);
 
-  const casesByStatus = useMemo(() => {
-    if (!currentStats) return [];
-    return currentStats.casesByStatus.map(item => ({
-      ...item,
-      href: `/${locale}/case-management?filter[status][0]=${item.status}`,
-    }));
-  }, [currentStats]);
-
-  const ongoingCasesByRisk = useMemo(() => {
-    if (!currentStats) return [];
-    return currentStats.ongoingCasesByRisk.map(item => ({
-      ...item,
-      href: `/${locale}/case-management?filter[status][0]=active&filter[riskLevel][0]=${item.riskLevel}`,
-    }));
-  }, [currentStats]);
-
-  const approvedCasesByRisk = useMemo(() => {
-    if (!currentStats) return [];
-    return currentStats.approvedCasesByRisk.map(item => ({
-      ...item,
-      href: `/${locale}/case-management?filter[status][0]=completed&filter[riskLevel][0]=${item.riskLevel}`,
-    }));
-  }, [currentStats]);
-
   return {
     firstName,
     fullName,
@@ -190,9 +187,9 @@ export const useHomeLogic = () => {
     casesTo,
     setCasesDate: onCasesDatesChange,
 
-    casesByStatus,
-    ongoingCasesByRisk,
-    approvedCasesByRisk,
+    casesByStatus: currentStats?.casesByStatus ?? [],
+    ongoingCasesByRisk: currentStats?.ongoingCasesByRisk ?? [],
+    approvedCasesByRisk: currentStats?.approvedCasesByRisk ?? [],
 
     totalActiveMerchants: metrics?.totalActiveMerchants ?? 0,
     addedMerchantsCount: metrics?.addedMerchantsCount ?? 0,
@@ -204,7 +201,7 @@ export const useHomeLogic = () => {
     statusConfig,
     ongoingRiskConfig,
     approvedRiskConfig,
-    getStatusColor,
-    getRiskColor,
+    getStatusDefinition,
+    getRiskDefinition,
   };
 };
diff --git a/apps/backoffice-v2/src/pages/Entities/components/Cases/hooks/useCases/useCases.tsx b/apps/backoffice-v2/src/pages/Entities/components/Cases/hooks/useCases/useCases.tsx
index e4b75b43ef..b3d5abb894 100644
--- a/apps/backoffice-v2/src/pages/Entities/components/Cases/hooks/useCases/useCases.tsx
+++ b/apps/backoffice-v2/src/pages/Entities/components/Cases/hooks/useCases/useCases.tsx
@@ -94,7 +94,7 @@ export const useCases = () => {
                 value: 'caseStatus',
                 options: [
                   ...(statuses?.map(status => ({
-                    label: tagToBadgeData[status]?.text,
+                    label: tagToBadgeData[status as keyof typeof tagToBadgeData]?.text,
                     value: status,
                     key: status,
                   })) ?? []),
diff --git a/apps/backoffice-v2/src/pages/Home/Home.page.tsx b/apps/backoffice-v2/src/pages/Home/Home.page.tsx
index 15e5d0b8ee..a79210dd76 100644
--- a/apps/backoffice-v2/src/pages/Home/Home.page.tsx
+++ b/apps/backoffice-v2/src/pages/Home/Home.page.tsx
@@ -45,8 +45,8 @@ export const Home: FunctionComponent = () => {
     statusConfig,
     ongoingRiskConfig,
     approvedRiskConfig,
-    getStatusColor,
-    getRiskColor,
+    getStatusDefinition,
+    getRiskDefinition,
   } = useHomeLogic();
 
   if (isLoadingCustomer || isLoadingMetrics || isLoadingCurrentStats) {
@@ -93,8 +93,8 @@ export const Home: FunctionComponent = () => {
               statusConfig={statusConfig}
               ongoingRiskConfig={ongoingRiskConfig}
               approvedRiskConfig={approvedRiskConfig}
-              getStatusColor={getStatusColor}
-              getRiskColor={getRiskColor}
+              getStatusDefinition={getStatusDefinition}
+              getRiskDefinition={getRiskDefinition}
             />
 
             <DynamicMetricsSection
diff --git a/apps/backoffice-v2/src/pages/Home/components/CaseGraphs/CaseGraphs.tsx b/apps/backoffice-v2/src/pages/Home/components/CaseGraphs/CaseGraphs.tsx
index 7c4077b553..56f5b52d7b 100644
--- a/apps/backoffice-v2/src/pages/Home/components/CaseGraphs/CaseGraphs.tsx
+++ b/apps/backoffice-v2/src/pages/Home/components/CaseGraphs/CaseGraphs.tsx
@@ -1,4 +1,3 @@
-import dayjs from 'dayjs';
 import { Loader2 } from 'lucide-react';
 import type { FunctionComponent } from 'react';
 import { Bar, BarChart, CartesianGrid, Tooltip, XAxis, YAxis } from 'recharts';
@@ -13,10 +12,7 @@ export const CaseGraphs: FunctionComponent<{
   from: ReturnType<typeof useHomeLogic>['mmFrom'];
   to: ReturnType<typeof useHomeLogic>['mmTo'];
 }> = ({ from, to }) => {
-  const { data: liveCasesData, isLoading } = useCaseDailyStats({
-    from,
-    to: to ? dayjs(to).add(1, 'day').format('YYYY-MM-DD') : undefined,
-  });
+  const { data: liveCasesData, isLoading } = useCaseDailyStats({ from, to });
 
   return (
     <div className="grid grid-cols-6">
@@ -38,69 +34,75 @@ export const CaseGraphs: FunctionComponent<{
                   Data shown from case opening date to closing date
                 </p>
 
-                <div className={'flex h-72 w-full justify-center'}>
-                  <BarChart
-                    width={800}
-                    height={300}
-                    data={liveCasesData}
-                    margin={{
-                      top: 20,
-                      right: 30,
-                      left: 20,
-                      bottom: 30,
-                    }}
-                    barSize={35}
-                  >
-                    <CartesianGrid strokeDasharray="3 3" vertical={false} opacity={0.5} />
-                    <XAxis
-                      dataKey="date"
-                      axisLine={false}
-                      tickLine={false}
-                      tick={{ fill: '#6B7280', fontSize: 12 }}
-                      padding={{ left: 10, right: 10 }}
-                      label={{
-                        value: 'Date',
-                        position: 'insideBottom',
-                        offset: -15,
-                        fill: '#4B5563',
-                        fontSize: 14,
-                        fontWeight: 500,
+                {liveCasesData.length ? (
+                  <div className={'flex h-72 w-full justify-center'}>
+                    <BarChart
+                      width={800}
+                      height={300}
+                      data={liveCasesData}
+                      margin={{
+                        top: 20,
+                        right: 30,
+                        left: 20,
+                        bottom: 30,
                       }}
-                    />
-                    <YAxis
-                      axisLine={false}
-                      tickLine={false}
-                      tick={{ fill: '#6B7280', fontSize: 12 }}
-                      label={{
-                        value: 'Cases',
-                        angle: -90,
-                        position: 'insideLeft',
-                        offset: -5,
-                        fill: '#4B5563',
-                        fontSize: 14,
-                        fontWeight: 500,
-                      }}
-                    />
-                    <Tooltip
-                      cursor={{ fill: 'rgba(59, 130, 246, 0.1)' }}
-                      contentStyle={{
-                        borderRadius: '6px',
-                        border: 'none',
-                        boxShadow:
-                          '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
-                        padding: '8px 12px',
-                      }}
-                      labelStyle={{ fontWeight: 'bold', marginBottom: '4px' }}
-                    />
-                    <Bar
-                      dataKey="count"
-                      fill="#3B82F6"
-                      radius={[4, 4, 0, 0]}
-                      animationDuration={1500}
-                      fillOpacity={0.85}
-                    />
-                  </BarChart>
-                </div>
+                      barSize={35}
+                    >
+                      <CartesianGrid strokeDasharray="3 3" vertical={false} opacity={0.5} />
+                      <XAxis
+                        dataKey="date"
+                        axisLine={false}
+                        tickLine={false}
+                        tick={{ fill: '#6B7280', fontSize: 12 }}
+                        padding={{ left: 10, right: 10 }}
+                        label={{
+                          value: 'Date',
+                          position: 'insideBottom',
+                          offset: -15,
+                          fill: '#4B5563',
+                          fontSize: 14,
+                          fontWeight: 500,
+                        }}
+                      />
+                      <YAxis
+                        axisLine={false}
+                        tickLine={false}
+                        tick={{ fill: '#6B7280', fontSize: 12 }}
+                        label={{
+                          value: 'Cases',
+                          angle: -90,
+                          position: 'insideLeft',
+                          offset: -5,
+                          fill: '#4B5563',
+                          fontSize: 14,
+                          fontWeight: 500,
+                        }}
+                      />
+                      <Tooltip
+                        cursor={{ fill: 'rgba(59, 130, 246, 0.1)' }}
+                        contentStyle={{
+                          borderRadius: '6px',
+                          border: 'none',
+                          boxShadow:
+                            '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
+                          padding: '8px 12px',
+                        }}
+                        labelStyle={{ fontWeight: 'bold', marginBottom: '4px' }}
+                      />
+                      <Bar
+                        dataKey="count"
+                        fill="#3B82F6"
+                        radius={[4, 4, 0, 0]}
+                        animationDuration={1500}
+                        fillOpacity={0.85}
+                      />
+                    </BarChart>
+                  </div>
+                ) : (
+                  <div className="flex h-72 w-full items-center justify-center text-slate-500">
+                    No Data Available
+                  </div>
+                )}
               </>
             )}
           </CardContent>
diff --git a/apps/backoffice-v2/src/pages/Home/components/CasePieChart/CasePieChart.tsx b/apps/backoffice-v2/src/pages/Home/components/CasePieChart/CasePieChart.tsx
index 82852eda1f..9cdf98db39 100644
--- a/apps/backoffice-v2/src/pages/Home/components/CasePieChart/CasePieChart.tsx
+++ b/apps/backoffice-v2/src/pages/Home/components/CasePieChart/CasePieChart.tsx
@@ -1,23 +1,22 @@
 import { FunctionComponent, useMemo } from 'react';
 import { Cell, Pie, PieChart } from 'recharts';
 
+import { ctw } from '@/common/utils/ctw/ctw';
 import { ChartContainer } from '@ballerine/ui';
-import { titleCase } from 'string-ts';
 import { useNavigate } from 'react-router-dom';
-import { ctw } from '@/common/utils/ctw/ctw';
 
 type PieChartData = { status?: string; riskLevel?: string; count: number; href?: string };
 
 export type CasePieChartProps = {
   data: PieChartData[];
-  getColor: (key: string) => string;
+  getDefinition: (key: string) => { color: string; text: string };
   nameKey: 'status' | 'riskLevel';
   config: Record<string, { label: string; color: string }>;
 };
 
 export const CasePieChart: FunctionComponent<CasePieChartProps> = ({
   data,
-  getColor,
+  getDefinition,
   nameKey,
   config,
 }) => {
@@ -25,6 +24,14 @@ export const CasePieChart: FunctionComponent<CasePieChartProps> = ({
 
   const navigate = useNavigate();
 
+  if (data.length === 0) {
+    return (
+      <div className={'flex h-[184px] w-[184px] items-center justify-center text-slate-500'}>
+        No Data Available
+      </div>
+    );
+  }
+
   return (
     <>
       <ChartContainer className="h-[184px] w-[184px]" config={config}>
@@ -53,7 +60,7 @@ export const CasePieChart: FunctionComponent<CasePieChartProps> = ({
             {data.map((entry, index) => (
               <Cell
                 key={`cell-${index}`}
-                fill={getColor(entry[nameKey] as string)}
+                fill={getDefinition(entry[nameKey] as string).color}
                 className={ctw('outline-none', entry.href && 'cursor-pointer')}
                 onClick={() => {
                   if (entry.href) {
@@ -72,12 +79,10 @@ export const CasePieChart: FunctionComponent<CasePieChartProps> = ({
             <li key={index} className={'flex items-center space-x-4 border-b py-1 text-xs'}>
               <span
                 className={`flex h-2 w-2 rounded-full`}
-                style={{ backgroundColor: getColor(key) }}
+                style={{ backgroundColor: getDefinition(key).color }}
               />
               <div className={'flex w-full justify-between'}>
-                <span className={'text-slate-500'}>
-                  {nameKey === 'riskLevel' ? `${titleCase(key)} Risk` : titleCase(key)}
-                </span>
+                <span className={'text-slate-500'}>{getDefinition(key).text}</span>
                 <span>{entry.count}</span>
               </div>
             </li>
diff --git a/apps/backoffice-v2/src/pages/Home/components/DynamicMetricsSection/DynamicMetricsSection.tsx b/apps/backoffice-v2/src/pages/Home/components/DynamicMetricsSection/DynamicMetricsSection.tsx
index 5c25d1c0e1..011c817866 100644
--- a/apps/backoffice-v2/src/pages/Home/components/DynamicMetricsSection/DynamicMetricsSection.tsx
+++ b/apps/backoffice-v2/src/pages/Home/components/DynamicMetricsSection/DynamicMetricsSection.tsx
@@ -1,11 +1,10 @@
 import { Separator } from '@radix-ui/react-separator';
+import qs from 'qs';
 
 import { DateRangePicker } from '@/common/components/organisms/DateRangePicker/DateRangePicker';
 import { useHomeLogic } from '@/common/hooks/useHomeLogic/useHomeLogic';
-import { REPORT_TYPE_TO_DISPLAY_TEXT } from '@/pages/MerchantMonitoring/schemas';
 import { StatsCard } from '@/pages/Home/components/StatsCard/StatsCard';
-import qs from 'qs';
-import { useMemo } from 'react';
+import { REPORT_TYPE_TO_DISPLAY_TEXT } from '@/pages/MerchantMonitoring/schemas';
 
 export const DynamicMetricsSection = ({
   locale,
diff --git a/apps/backoffice-v2/src/pages/Home/components/PortfolioRiskStatistics/PortfolioRiskStatistics.tsx b/apps/backoffice-v2/src/pages/Home/components/PortfolioRiskStatistics/PortfolioRiskStatistics.tsx
index 1f1000bd79..6d267da9fa 100644
--- a/apps/backoffice-v2/src/pages/Home/components/PortfolioRiskStatistics/PortfolioRiskStatistics.tsx
+++ b/apps/backoffice-v2/src/pages/Home/components/PortfolioRiskStatistics/PortfolioRiskStatistics.tsx
@@ -127,36 +127,43 @@ export const PortfolioRiskStatistics: FunctionComponent<
         <Card className={'flex h-full flex-col px-3'}>
           <CardHeader className={'pb-2 font-bold'}>Top 10 Content Violations</CardHeader>
           <CardContent>
-            <Table>
-              <TableHeader className={'[&_tr]:border-b-0'}>
-                <TableRow className={'hover:bg-[unset]'}>
-                  <TableHead className={'h-0 ps-0 text-foreground'}>Indicator</TableHead>
-                  <TableHead className={'h-0 px-0 text-foreground'}>Amount</TableHead>
-                </TableRow>
-              </TableHeader>
-              <TableBody ref={parent}>
-                {filteredRiskIndicators.map(({ name, count, id }, index) => (
-                  <TableRow key={name} className={'border-b-0 hover:bg-[unset]'}>
-                    <TableCell className={ctw('pb-0 ps-0', index !== 0 && 'pt-2')}>
-                      <Link
-                        to={`/${locale}/merchant-monitoring?${qs.stringify({
-                          'findings[0]': id,
-                          from: from ?? undefined,
-                          to: to ?? undefined,
-                        })}`}
-                        className={`block h-full cursor-pointer rounded bg-blue-200 p-1 transition-all`}
-                        style={{ width: `${widths[index]}%` }}
-                      >
-                        {titleCase(name ?? '')}
-                      </Link>
-                    </TableCell>
-                    <TableCell className={'!px-0 pb-0'}>
-                      {Intl.NumberFormat().format(count)}
-                    </TableCell>
+            {filteredRiskIndicators.length ? (
+              <Table>
+                <TableHeader className={'[&_tr]:border-b-0'}>
+                  <TableRow className={'hover:bg-[unset]'}>
+                    <TableHead className={'h-0 ps-0 text-foreground'}>Indicator</TableHead>
+                    <TableHead className={'h-0 px-0 text-foreground'}>Amount</TableHead>
                   </TableRow>
-                ))}
-              </TableBody>
-            </Table>
+                </TableHeader>
+                <TableBody ref={parent}>
+                  {filteredRiskIndicators.map(({ name, count, id }, index) => (
+                    <TableRow key={name} className={'border-b-0 hover:bg-[unset]'}>
+                      <TableCell className={ctw('pb-0 ps-0', index !== 0 && 'pt-2')}>
+                        <Link
+                          to={`/${locale}/merchant-monitoring?${qs.stringify({
+                            allowAllDates: !from && !to,
+                            'findings[0]': id,
+                            from: from ?? undefined,
+                            to: to ?? undefined,
+                          })}`}
+                          className={`block h-full cursor-pointer rounded bg-blue-200 p-1 transition-all`}
+                          style={{ width: `${widths[index]}%` }}
+                        >
+                          {titleCase(name ?? '')}
+                        </Link>
+                      </TableCell>
+                      <TableCell className={'!px-0 pb-0'}>
+                        {Intl.NumberFormat().format(count)}
+                      </TableCell>
+                    </TableRow>
+                  ))}
+                </TableBody>
+              </Table>
+            ) : (
+              <div className={'flex h-72 w-full items-center justify-center text-slate-500'}>
+                No Data Available
+              </div>
+            )}
           </CardContent>
         </Card>
       </div>
@@ -174,6 +181,7 @@ export const PortfolioRiskStatistics: FunctionComponent<
                 </div>
                 <Link
                   to={`/${locale}/merchant-monitoring?${qs.stringify({
+                    allowAllDates: !from && !to,
                     isAlert: 'Alerted',
                     from: from ?? undefined,
                     to: to ?? undefined,
diff --git a/apps/backoffice-v2/src/pages/Home/components/StaticMetricsSection/StaticMetricsSection.tsx b/apps/backoffice-v2/src/pages/Home/components/StaticMetricsSection/StaticMetricsSection.tsx
index 28d57ce2e0..f51e8ace29 100644
--- a/apps/backoffice-v2/src/pages/Home/components/StaticMetricsSection/StaticMetricsSection.tsx
+++ b/apps/backoffice-v2/src/pages/Home/components/StaticMetricsSection/StaticMetricsSection.tsx
@@ -14,8 +14,8 @@ export const StaticMetricsSection = ({
   statusConfig,
   ongoingRiskConfig,
   approvedRiskConfig,
-  getStatusColor,
-  getRiskColor,
+  getStatusDefinition,
+  getRiskDefinition,
 }: Pick<
   ReturnType<typeof useHomeLogic>,
   | 'isOngoingMonitoringEnabled'
@@ -27,8 +27,8 @@ export const StaticMetricsSection = ({
   | 'statusConfig'
   | 'ongoingRiskConfig'
   | 'approvedRiskConfig'
-  | 'getStatusColor'
-  | 'getRiskColor'
+  | 'getStatusDefinition'
+  | 'getRiskDefinition'
 >) => {
   return (
     <div className="grid grid-cols-4 gap-6 2xl:grid-cols-6">
@@ -46,7 +46,7 @@ export const StaticMetricsSection = ({
           <PieChartCard
             title="Active (ongoing) Cases By Status"
             data={casesByStatus}
-            getColor={getStatusColor}
+            getDefinition={getStatusDefinition}
             nameKey="status"
             config={statusConfig}
           />
@@ -54,7 +54,7 @@ export const StaticMetricsSection = ({
           <PieChartCard
             title="Active (ongoing) Cases By Risk Level"
             data={ongoingCasesByRisk}
-            getColor={getRiskColor}
+            getDefinition={getRiskDefinition}
             nameKey="riskLevel"
             config={ongoingRiskConfig}
           />
@@ -62,7 +62,7 @@ export const StaticMetricsSection = ({
           <PieChartCard
             title="Approved (done) Cases By Risk Level"
             data={approvedCasesByRisk}
-            getColor={getRiskColor}
+            getDefinition={getRiskDefinition}
             nameKey="riskLevel"
             config={approvedRiskConfig}
           />
diff --git a/services/workflows-service/src/metrics/repository/metrics.repository.ts b/services/workflows-service/src/metrics/repository/metrics.repository.ts
index 0895252711..5e8ef3b50c 100644
--- a/services/workflows-service/src/metrics/repository/metrics.repository.ts
+++ b/services/workflows-service/src/metrics/repository/metrics.repository.ts
@@ -74,21 +74,22 @@ export class MetricsRepository {
     );
   }
 
-  async getCasesByStatus(projectIds: TProjectIds) {
+  async getActiveCasesByState(projectIds: TProjectIds) {
     const results = await this.prismaService.workflowRuntimeData.groupBy({
-      by: ['status'],
+      by: ['state'],
       where: {
+        status: 'active',
         projectId: { in: projectIds ?? [] },
       },
       _count: {
-        status: true,
+        state: true,
       },
     });
 
     return results.map(result =>
       plainToClass(CasesByStatusMetricModel, {
-        status: result.status,
-        count: Number(result._count.status),
+        status: result.state,
+        count: Number(result._count.state),
       }),
     );
   }
diff --git a/services/workflows-service/src/metrics/repository/sql/build-cases-metrics.sql.ts b/services/workflows-service/src/metrics/repository/sql/build-cases-metrics.sql.ts
index 8013089d1f..d43ee9899b 100644
--- a/services/workflows-service/src/metrics/repository/sql/build-cases-metrics.sql.ts
+++ b/services/workflows-service/src/metrics/repository/sql/build-cases-metrics.sql.ts
@@ -29,4 +29,5 @@ WHERE "projectId" IN (${projectIds?.join(',')})
     context->'pluginsOutput'->'riskEvaluation'->>'riskScore' IS NOT NULL
     OR context->'pluginsOutput'->'risk_evaluation'->>'riskScore' IS NOT NULL
   )
+  AND parent_runtime_data_id IS NULL
 GROUP BY risk_level`;
diff --git a/services/workflows-service/src/metrics/repository/sql/build-daily-live-cases.sql.ts b/services/workflows-service/src/metrics/repository/sql/build-daily-live-cases.sql.ts
index 903d66b4d7..80649b1dc7 100644
--- a/services/workflows-service/src/metrics/repository/sql/build-daily-live-cases.sql.ts
+++ b/services/workflows-service/src/metrics/repository/sql/build-daily-live-cases.sql.ts
@@ -21,9 +21,13 @@ export const buildDailyLiveCasesQuery = (
   // Determine the date range boundaries
   const fromDateSql = fromDate
     ? Prisma.sql`${fromDate}::timestamp`
-    : Prisma.sql`(SELECT MIN("createdAt") FROM "WorkflowRuntimeData" WHERE ${projectIdsSubqueryFilter})`; // Default: earliest relevant record
+    : Prisma.sql`(SELECT MIN("createdAt") FROM "WorkflowRuntimeData" WHERE ${projectIdsSubqueryFilter} AND parent_runtime_data_id IS NULL)`; // Default: earliest relevant record
 
-  const toDateSql = toDate ? Prisma.sql`${toDate}::timestamp` : Prisma.sql`CURRENT_DATE`; // Default: today
+  const toDateSql = toDate
+    ? Prisma.sql`${toDate}::timestamp`
+    : fromDate
+    ? Prisma.sql`${fromDate}::timestamp`
+    : Prisma.sql`CURRENT_DATE`; // Default: today
 
   return Prisma.sql`
     WITH RECURSIVE dates AS (
@@ -41,7 +45,8 @@ export const buildDailyLiveCasesQuery = (
       LEFT JOIN "WorkflowRuntimeData" w ON
         w."createdAt" <= d.date AND
         (w."resolvedAt" IS NULL OR w."resolvedAt" >= d.date) AND
-        w."projectId" ${projectIdsInClause}
+        w."projectId" ${projectIdsInClause} AND
+        w.parent_runtime_data_id IS NULL
       GROUP BY d.date
     )
     SELECT
diff --git a/services/workflows-service/src/metrics/service/metrics.service.ts b/services/workflows-service/src/metrics/service/metrics.service.ts
index 16ed8cdbb9..9114d44179 100644
--- a/services/workflows-service/src/metrics/service/metrics.service.ts
+++ b/services/workflows-service/src/metrics/service/metrics.service.ts
@@ -37,7 +37,7 @@ export class MetricsService {
     approvedCasesByRisk: CasesByRiskLevelMetricModel[];
   }> {
     const [casesByStatus, ongoingCasesByRisk, approvedCasesByRisk] = await Promise.all([
-      this.metricsRepository.getCasesByStatus(projectIds),
+      this.metricsRepository.getActiveCasesByState(projectIds),
       this.metricsRepository.getCasesByRiskLevel(projectIds, 'active'),
       this.metricsRepository.getCasesByRiskLevel(projectIds, 'completed'),
     ]);


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (4)</summary><blockquote>

<details>
<summary>services/workflows-service/src/metrics/repository/metrics.repository.ts (1)</summary><blockquote>

`77-95`: **Method refactored to use state instead of status**

The method has been appropriately renamed from `getCasesByStatus` to `getActiveCasesByState` to better reflect its purpose. The implementation now:
1. Groups by `state` instead of `status`
2. Filters only for records with `status: 'active'`
3. Maps the `state` value to the `status` property in the return model

This maintains backward compatibility with consumers while improving the data model to focus on active cases grouped by state.

Consider adding type safety to ensure that `state` values are compatible with what consumers expect in the `status` field of the returned model.

</blockquote></details>
<details>
<summary>apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts (3)</summary><blockquote>

`168-173`: **Removed href mapping from case status data.**

The code now returns the raw data without adding href properties. Consider removing the commented-out code if this change is intentional and permanent.

```diff
-  return currentStats.casesByStatus;
-  // return currentStats.casesByStatus.map(item => ({
-  //   ...item,
-  //   href: `/${locale}/case-management?filter[status][0]=${item.status}`,
-  // }));
+  return currentStats.casesByStatus;
```

---

`177-182`: **Removed href mapping from ongoing cases by risk data.**

The code now returns the raw data without adding href properties. Consider removing the commented-out code if this change is intentional and permanent.

```diff
-  return currentStats.ongoingCasesByRisk;
-  // return currentStats.ongoingCasesByRisk.map(item => ({
-  //   ...item,
-  //   href: `/${locale}/case-management?filter[status][0]=active&filter[riskLevel][0]=${item.riskLevel}`,
-  // }));
+  return currentStats.ongoingCasesByRisk;
```

---

`186-191`: **Removed href mapping from approved cases by risk data.**

The code now returns the raw data without adding href properties. Consider removing the commented-out code if this change is intentional and permanent.

```diff
-  return currentStats.approvedCasesByRisk;
-  // return currentStats.approvedCasesByRisk.map(item => ({
-  //   ...item,
-  //   href: `/${locale}/case-management?filter[status][0]=completed&filter[riskLevel][0]=${item.riskLevel}`,
-  // }));
+  return currentStats.approvedCasesByRisk;
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

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

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between dbd078b89e1fbd345ffe6441755fc5820d61523f and c337fde5d9904facfcf633520754d951a493c057.

</details>

<details>
<summary>📒 Files selected for processing (12)</summary>

* `apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts` (8 hunks)
* `apps/backoffice-v2/src/pages/Entities/components/Cases/hooks/useCases/useCases.tsx` (1 hunks)
* `apps/backoffice-v2/src/pages/Home/Home.page.tsx` (2 hunks)
* `apps/backoffice-v2/src/pages/Home/components/CaseGraphs/CaseGraphs.tsx` (2 hunks)
* `apps/backoffice-v2/src/pages/Home/components/CasePieChart/CasePieChart.tsx` (3 hunks)
* `apps/backoffice-v2/src/pages/Home/components/DynamicMetricsSection/DynamicMetricsSection.tsx` (1 hunks)
* `apps/backoffice-v2/src/pages/Home/components/PortfolioRiskStatistics/PortfolioRiskStatistics.tsx` (2 hunks)
* `apps/backoffice-v2/src/pages/Home/components/StaticMetricsSection/StaticMetricsSection.tsx` (3 hunks)
* `services/workflows-service/src/metrics/repository/metrics.repository.ts` (1 hunks)
* `services/workflows-service/src/metrics/repository/sql/build-cases-metrics.sql.ts` (1 hunks)
* `services/workflows-service/src/metrics/repository/sql/build-daily-live-cases.sql.ts` (2 hunks)
* `services/workflows-service/src/metrics/service/metrics.service.ts` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (6)</summary>

<details>
<summary>apps/backoffice-v2/src/pages/Entities/components/Cases/hooks/useCases/useCases.tsx (1)</summary><blockquote>

<details>
<summary>apps/backoffice-v2/src/pages/Entity/components/Case/consts.ts (1)</summary>

* `tagToBadgeData` (3-16)

</details>

</blockquote></details>
<details>
<summary>apps/backoffice-v2/src/pages/Home/components/CaseGraphs/CaseGraphs.tsx (1)</summary><blockquote>

<details>
<summary>apps/backoffice-v2/src/domains/metrics/hooks/queries/useCaseDailyStats/useCaseDailyStats.tsx (1)</summary>

* `useCaseDailyStats` (6-14)

</details>

</blockquote></details>
<details>
<summary>apps/backoffice-v2/src/pages/Home/components/PortfolioRiskStatistics/PortfolioRiskStatistics.tsx (4)</summary><blockquote>

<details>
<summary>apps/backoffice-v2/src/common/components/atoms/Table/Table.tsx (1)</summary>

* `Table` (4-8)

</details>
<details>
<summary>apps/backoffice-v2/src/common/components/atoms/Table/TableRow.tsx (1)</summary>

* `TableRow` (4-16)

</details>
<details>
<summary>apps/backoffice-v2/src/common/components/atoms/Table/TableHead.tsx (1)</summary>

* `TableHead` (4-18)

</details>
<details>
<summary>apps/backoffice-v2/src/common/components/organisms/TextEditor/extensions/link/link.ts (1)</summary>

* `Link` (7-87)

</details>

</blockquote></details>
<details>
<summary>apps/backoffice-v2/src/pages/Home/components/StaticMetricsSection/StaticMetricsSection.tsx (1)</summary><blockquote>

<details>
<summary>apps/backoffice-v2/src/pages/Home/components/PieChartCard/PieChartCard.tsx (1)</summary>

* `PieChartCard` (6-20)

</details>

</blockquote></details>
<details>
<summary>services/workflows-service/src/metrics/repository/metrics.repository.ts (2)</summary><blockquote>

<details>
<summary>services/workflows-service/src/types.ts (1)</summary>

* `TProjectIds` (16-16)

</details>
<details>
<summary>services/workflows-service/src/metrics/repository/models/cases-by-status.model.ts (1)</summary>

* `CasesByStatusMetricModel` (4-12)

</details>

</blockquote></details>
<details>
<summary>apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts (1)</summary><blockquote>

<details>
<summary>packages/common/src/consts/index.ts (1)</summary>

* `StateTag` (3-16)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (4)</summary>

* GitHub Check: Analyze (javascript)
* GitHub Check: test_linux
* GitHub Check: lint
* GitHub Check: build (ubuntu-latest)

</details>

<details>
<summary>🔇 Additional comments (29)</summary><blockquote>

<details>
<summary>apps/backoffice-v2/src/pages/Home/Home.page.tsx (2)</summary>

`48-49`: **Function naming improved to reflect enhanced functionality**

The rename from color-only functions to definition-returning functions better represents the enhanced functionality that now includes both color and text information. This matches the broader refactoring approach for status and risk level representations.

---

`96-97`: **Props updated to match function renaming**

Appropriate propagation of the renamed functions to child components maintains consistency throughout the component hierarchy.

</details>
<details>
<summary>apps/backoffice-v2/src/pages/Home/components/DynamicMetricsSection/DynamicMetricsSection.tsx (1)</summary>

`2-7`: **Import organization improved**

The import rearrangement improves code organization while removing unused imports. This is a minor but valuable cleanup that contributes to code maintainability.

</details>
<details>
<summary>apps/backoffice-v2/src/pages/Entities/components/Cases/hooks/useCases/useCases.tsx (1)</summary>

`97-97`: **Type safety improved for status labels**

Adding the type assertion `status as keyof typeof tagToBadgeData` ensures type safety when accessing the text property of the badge data. This strengthens the TypeScript type checking and aligns with the enhanced status definition structure used elsewhere in the application.

</details>
<details>
<summary>apps/backoffice-v2/src/pages/Home/components/CaseGraphs/CaseGraphs.tsx (2)</summary>

`15-15`: **Query parameter handling simplified**

The simplified parameter passing to `useCaseDailyStats` improves code clarity by removing unnecessary date manipulation.

---

`37-105`: **Graceful handling of empty data added**

Adding a conditional render to display "No Data Available" when there's no data to show improves the user experience by providing clear feedback. This enhancement prevents confusion that might arise from seeing an empty chart area.

</details>
<details>
<summary>services/workflows-service/src/metrics/repository/sql/build-cases-metrics.sql.ts (1)</summary>

`32-32`: **Improvement to filter out child workflows**

Good addition of the `parent_runtime_data_id IS NULL` condition to ensure metrics only include root workflows. This prevents double counting when aggregating metrics and aligns with the filtering approach used in other metrics queries.

</details>
<details>
<summary>services/workflows-service/src/metrics/service/metrics.service.ts (1)</summary>

`40-40`: **Method name change aligns with new functionality**

The change from `getCasesByStatus` to `getActiveCasesByState` correctly reflects the updated repository method that now groups cases by state rather than status while filtering for active status only.

</details>
<details>
<summary>services/workflows-service/src/metrics/repository/sql/build-daily-live-cases.sql.ts (3)</summary>

`24-24`: **Improvement to filter out child workflows**

Good addition of the `parent_runtime_data_id IS NULL` condition to ensure metrics only include root workflows. This prevents double counting when aggregating metrics.

---

`26-30`: **Enhanced date range fallback logic**

The improved fallback logic for `toDateSql` now uses `fromDate` as a fallback when `toDate` is not provided, instead of immediately defaulting to the current date. This allows for single-day range queries when only `fromDate` is specified.

---

`48-49`: **Consistent filtering of child workflows**

Good addition of the `parent_runtime_data_id IS NULL` condition in the JOIN criteria, maintaining consistency with the other filter changes and ensuring only root workflows are counted in the metrics.

</details>
<details>
<summary>apps/backoffice-v2/src/pages/Home/components/StaticMetricsSection/StaticMetricsSection.tsx (5)</summary>

`17-18`: **Props updated to use definition objects instead of colors.**

The component now uses `getStatusDefinition` and `getRiskDefinition` which return objects containing both color and text properties, replacing the previous color-only getter functions. This aligns with the refactoring in `useHomeLogic`.

---

`30-31`: **Type definition updated to match new props.**

The Pick type is correctly updated to include the new definition-returning functions.

---

`49-50`: **PieChartCard component updated to use new definition prop.**

The component now correctly passes `getDefinition` instead of `getColor` to align with the updated interface in CasePieChart.

---

`57-58`: **PieChartCard component updated to use new definition prop.**

The component now correctly passes `getDefinition` instead of `getColor` to align with the updated interface in CasePieChart.

---

`65-66`: **PieChartCard component updated to use new definition prop.**

The component now correctly passes `getDefinition` instead of `getColor` to align with the updated interface in CasePieChart.

</details>
<details>
<summary>apps/backoffice-v2/src/pages/Home/components/PortfolioRiskStatistics/PortfolioRiskStatistics.tsx (3)</summary>

`130-166`: **Added conditional rendering for empty data state.**

Good improvement to handle cases when no content violations data is available. This enhances user experience by providing clear feedback instead of showing an empty table.

---

`144-145`: **Added query parameter for date filtering.**

The `allowAllDates` parameter is now correctly included when both `from` and `to` are undefined, ensuring consistent date filtering behavior across the application.

---

`184-185`: **Added query parameter for date filtering.**

The `allowAllDates` parameter is now correctly included for the "Unresolved Monitoring Alerts" link too, ensuring consistent date filtering behavior across the application.

</details>
<details>
<summary>apps/backoffice-v2/src/pages/Home/components/CasePieChart/CasePieChart.tsx (5)</summary>

`12-13`: **Updated component props to use definition objects.**

The component now accepts `getDefinition` which returns rich objects with both `color` and `text` properties instead of just a color value, providing more flexibility and consistency.

---

`27-33`: **Added graceful handling for empty data.**

Good improvement to display a "No Data Available" message when there's no data to render, enhancing user experience with clear feedback.

---

`63-64`: **Updated color access to use definition object.**

Now correctly uses the `color` property from the definition object returned by `getDefinition`.

---

`82-83`: **Updated color access to use definition object.**

Now correctly uses the `color` property from the definition object returned by `getDefinition`.

---

`85-86`: **Using predefined text from definition object.**

Now uses the `text` property from the definition object instead of applying `titleCase` to the key, ensuring consistent text display across the application.

</details>
<details>
<summary>apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts (5)</summary>

`26-31`: **Enhanced risk level definitions with descriptive text.**

Good improvement to include both color and descriptive text in the risk level definitions, providing richer information for UI components.

---

`33-46`: **Enhanced status definitions with descriptive text and used StateTag constants.**

Good improvement to:
1. Include both color and descriptive text in the status definitions
2. Use the `StateTag` constants from the common package, improving type safety and maintainability

---

`104-111`: **Refactored to return definition objects instead of just colors.**

The function now returns a complete definition object with both color and text properties, providing more context for UI components.

---

`113-120`: **Refactored to return definition objects instead of just colors.**

The function now returns a complete definition object with both color and text properties, providing more context for UI components.

---

`229-231`: **Updated exported functions to reflect new definition-returning functions.**

The hook now correctly exports the new `getStatusDefinition` and `getRiskDefinition` functions instead of the previous color-only functions.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T12:49:02Z
user: login: jonathan-shemer
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T12:54:52Z
user: login: r4zendev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T12:57:24Z

Review comments:
diff_hunk: @@ -146,26 +165,29 @@ export const useHomeLogic = () => {
 
   const casesByStatus = useMemo(() => {
     if (!currentStats) return [];
-    return currentStats.casesByStatus.map(item => ({
-      ...item,
-      href: `/${locale}/case-management?filter[status][0]=${item.status}`,
-    }));
+    return currentStats.casesByStatus;
+    // return currentStats.casesByStatus.map(item => ({
+    //   ...item,
+    //   href: `/${locale}/case-management?filter[status][0]=${item.status}`,
+    // }));
   }, [currentStats]);
 
   const ongoingCasesByRisk = useMemo(() => {
     if (!currentStats) return [];
-    return currentStats.ongoingCasesByRisk.map(item => ({
-      ...item,
-      href: `/${locale}/case-management?filter[status][0]=active&filter[riskLevel][0]=${item.riskLevel}`,
-    }));
+    return currentStats.ongoingCasesByRisk;
+    // return currentStats.ongoingCasesByRisk.map(item => ({
+    //   ...item,
+    //   href: `/${locale}/case-management?filter[status][0]=active&filter[riskLevel][0]=${item.riskLevel}`,
+    // }));
   }, [currentStats]);
 
   const approvedCasesByRisk = useMemo(() => {
     if (!currentStats) return [];
-    return currentStats.approvedCasesByRisk.map(item => ({
-      ...item,
-      href: `/${locale}/case-management?filter[status][0]=completed&filter[riskLevel][0]=${item.riskLevel}`,
-    }));
+    return currentStats.approvedCasesByRisk;
+    // return currentStats.approvedCasesByRisk.map(item => ({
+    //   ...item,
+    //   href: `/${locale}/case-management?filter[status][0]=completed&filter[riskLevel][0]=${item.riskLevel}`,
+    // }));
path: apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts
user: login: jonathan-shemer
body: ```suggestion
    return currentStats.approvedCasesByRisk;
```
can we discard commented-out code?
created_at: 2025-04-16T12:53:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -146,26 +165,29 @@ export const useHomeLogic = () => {
 
   const casesByStatus = useMemo(() => {
     if (!currentStats) return [];
-    return currentStats.casesByStatus.map(item => ({
-      ...item,
-      href: `/${locale}/case-management?filter[status][0]=${item.status}`,
-    }));
+    return currentStats.casesByStatus;
+    // return currentStats.casesByStatus.map(item => ({
+    //   ...item,
+    //   href: `/${locale}/case-management?filter[status][0]=${item.status}`,
+    // }));
   }, [currentStats]);
 
   const ongoingCasesByRisk = useMemo(() => {
     if (!currentStats) return [];
-    return currentStats.ongoingCasesByRisk.map(item => ({
-      ...item,
-      href: `/${locale}/case-management?filter[status][0]=active&filter[riskLevel][0]=${item.riskLevel}`,
-    }));
+    return currentStats.ongoingCasesByRisk;
+    // return currentStats.ongoingCasesByRisk.map(item => ({
+    //   ...item,
+    //   href: `/${locale}/case-management?filter[status][0]=active&filter[riskLevel][0]=${item.riskLevel}`,
+    // }));
   }, [currentStats]);
 
   const approvedCasesByRisk = useMemo(() => {
     if (!currentStats) return [];
-    return currentStats.approvedCasesByRisk.map(item => ({
-      ...item,
-      href: `/${locale}/case-management?filter[status][0]=completed&filter[riskLevel][0]=${item.riskLevel}`,
-    }));
+    return currentStats.approvedCasesByRisk;
+    // return currentStats.approvedCasesByRisk.map(item => ({
+    //   ...item,
+    //   href: `/${locale}/case-management?filter[status][0]=completed&filter[riskLevel][0]=${item.riskLevel}`,
+    // }));
path: apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts
user: login: r4zendev
body: we can, i left it since we will likely need to implement this feature in the future.
i also left the code in the pie charts that handles passed `href` props accordingly.
created_at: 2025-04-16T12:57:24Z
author_association: CONTRIBUTOR

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-04-16T12:46:29Z
body: ###  ⚠️  No Changeset found

Latest commit: 311e625b77570117aa6ad849245f2ac8ae276ce9

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/ballerine-io/ballerine/new/bal-3985?filename=.changeset/famous-paws-count.md&value=---%0A%22%40ballerine%2Fbackoffice-v2%22%3A%20patch%0A%22%40ballerine%2Fworkflows-service%22%3A%20patch%0A---%0A%0Afix%3A%20exclude%20child%20workflows%20%26%20use%20cases%20state%20for%20status%20graph%20(BAL-3985%2C%20BAL-3993)%0A)


author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-04-16T12:46:33Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

This set of changes refactors the color mapping logic for statuses and risk levels in the backoffice application by replacing simple color mappings with more descriptive objects containing both color and text. Functions and components that previously relied on color-only accessors are updated to use the new definition-returning functions. Several UI components are modified to handle empty data cases by displaying "No Data Available" messages. On the backend, SQL queries and repository methods are refined to filter for root workflow data and to update aggregation logic, including renaming and altering method signatures for clarity and accuracy.

## Changes

| File(s)                                                                                           | Change Summary |
|-------------------------------------------------------------------------------------------------|----------------|
| apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts                                | Refactored status and risk color mappings to return objects with color and text; updated function names and signatures; removed URL href logic from memoized arrays. |
| apps/backoffice-v2/src/pages/Home/Home.page.tsx<br>apps/backoffice-v2/src/pages/Home/components/StaticMetricsSection/StaticMetricsSection.tsx<br>apps/backoffice-v2/src/pages/Home/components/CasePieChart/CasePieChart.tsx | Updated to use new definition-returning functions/props for status and risk; updated prop signatures and usages accordingly. |
| apps/backoffice-v2/src/pages/Entities/components/Cases/hooks/useCases/useCases.tsx              | Improved type safety in status-to-badge mapping by asserting status keys. |
| apps/backoffice-v2/src/pages/Home/components/CaseGraphs/CaseGraphs.tsx                          | Removed unused import; simplified date handling; added conditional rendering for empty data. |
| apps/backoffice-v2/src/pages/Home/components/DynamicMetricsSection/DynamicMetricsSection.tsx    | Reordered import statements; no logic changes. |
| apps/backoffice-v2/src/pages/Home/components/PortfolioRiskStatistics/PortfolioRiskStatistics.tsx| Added conditional rendering for empty data; enhanced navigation links with new query parameter `allowAllDates`. |
| services/workflows-service/src/metrics/repository/metrics.repository.ts                         | Renamed and updated method to aggregate by state, filtering for active cases; updated return mapping accordingly. |
| services/workflows-service/src/metrics/repository/sql/build-cases-metrics.sql.ts                | Added filter to only include root workflow runtime data (`parent_runtime_data_id IS NULL`) in risk level metrics query. |
| services/workflows-service/src/metrics/repository/sql/build-daily-live-cases.sql.ts             | Refined date boundaries and root workflow filtering in daily live cases query; adjusted default date logic. |
| services/workflows-service/src/metrics/service/metrics.service.ts                               | Updated repository method call to use new aggregation logic for active cases by state in `getCasesMetrics`. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
  participant UI
  participant useHomeLogic
  participant StaticMetricsSection
  participant CasePieChart

  UI->>useHomeLogic: Call useHomeLogic()
  useHomeLogic-->>UI: Returns { getStatusDefinition, getRiskDefinition, ... }

  UI->>StaticMetricsSection: Render with getStatusDefinition, getRiskDefinition
  StaticMetricsSection->>CasePieChart: Pass getDefinition prop
  CasePieChart->>CasePieChart: Use getDefinition(key) to get { color, text }
```

```mermaid
sequenceDiagram
  participant MetricsService
  participant MetricsRepository
  participant SQL

  MetricsService->>MetricsRepository: getActiveCasesByState(projectIds)
  MetricsRepository->>SQL: Query cases grouped by state, filter status='active'
  SQL-->>MetricsRepository: Return aggregated results
  MetricsRepository-->>MetricsService: Return mapped cases by state
```

## Possibly related PRs

- [ballerine-io/ballerine#3243](https://github.com/ballerine-io/ballerine/pull/3243): Refactors and extends `useHomeLogic` by reintroducing URL hrefs with filters and adding state/config flags, directly modifying the same hook and data structures as this PR but in an opposite direction regarding URL logic.

## Poem

> A rabbit hopped through colored fields,  
> Where statuses and risks revealed  
> Their hues and names with pride anew—  
> No more just blue, but meaning too!  
> If data’s missing, don’t despair,  
> “No Data” signs pop up with care.  
> Backend roots now clear and bright—  
> Metrics shine in morning light! 🐇✨

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

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

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between c337fde5d9904facfcf633520754d951a493c057 and 311e625b77570117aa6ad849245f2ac8ae276ce9.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts` (8 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* apps/backoffice-v2/src/common/hooks/useHomeLogic/useHomeLogic.ts

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (6)</summary>

* GitHub Check: test_linux
* GitHub Check: spell_check
* GitHub Check: Analyze (javascript)
* GitHub Check: format
* GitHub Check: build (ubuntu-latest)
* GitHub Check: lint

</details>

</details>
<!-- internal state start -->


<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEejqANiS4AzeAA8uJewwvYljBBfoB3fBQBrGwt8H2QAMkhsRBJGNBjkRFxqWJt/SCTqaMgiKm5YSAAKACEAQQAZMABmAE4ADgBWABpIMsramqqASgMAOWxmAUouKoAmABYANgMAVRiKLgpxgC8yJQkjfWNwKDX+GxwCYjJlGnomVnYuXn5hUXEpGXkmJSpVdS0dLZMoOFRUTCHQikchUM4KS4YTiQKg+DIDZhoCjyOQKV4qNSabS6MCGbamAxobjcRAAegEaAYAXwNjsDBIYAko1JiAoDFJF2Y+AwpNg+HwATJ0RIAAkWCRyvgiPB2cKxWxJdKGBpcIgOAYAERagwAYh1kFKAEljqCUvREAikfIaZ5MKREGZYLEXrEKCRuBZKdJILgnTw3RJ4Phsoh4MwPc78CE+IjifAMERkGk+BQkAFIFYpBZkJhzclcMLkD51AUuW7IEpkvArPQlHYMOogxhkL7qCgMK53LEBPhfQpo+gMLXpAxU9wHrEaPZNDA/VH6AADABKhoAygBpAD65QAogA1HflTcAYQA8uVT0vVwvB4vV9BStAZquT+fL9fbiIxDny26uVJ6FzGF3U9el6FRZc1y3XcDyPAARHcADFDV6Q1oENU9ehvICF3vR9n03BDkNQ9DMIXFofCdcsSEpAp2GRBQoW0Zt0H7dIgLQH1nFwDMVBICwNFnWJMgLZAAhIWRkHjSBcIfJ8XyIlC0IwrD0HLDBQkYzIoSTCgWB9P0w24fxwVw/MSGgNAiBvMgBnbJIaPoG0PWYjJcFTBNEA0Mw/EgGxsA7cRuUQFoF1IXBV3zaJjyjfxsKHGTwqXNMYujci1NdMg0DYQCErdOt4zodBkDCkgIqixA4JIetG25eLFyStMqpqoKMAXQS4GkWJyDhfzAqbZA3QLCgsF9VJsAsCwK2q+NaqwQQvx4womAHICp1wLo/PYnJJDINysmQdJU0QdMkg8ogWjrNAJvEBMfXwViVvSBcdUmBo0FpGx6q46dIA1GYMACDSfAwDUUAOMb224PAUGQDSeLSALaG8gxOsgNguXgVZzm5OwiGwMEm0/e4SpE6LcfgazQu5Ih8HjIhkpOmKMDx9KcKJXh8AAxmAmZ1mMqibhaDNe6ohiAzupIOECobVqwCGgmGzuvqxAG+yaDQJyIbnbw2IoMBuQseQVdarzHViDG6extSqEkmSGHiaRilkSKDvShcabphNj0dxBnZ5tmEoXDm9IAn2En9tNsPLUNwwseA7CK1E/y5+mJfRjm09bHjNaURdYDdL7/XwbhKHEb1iz7GYl3KZAmCY2blerGgKC8yBDWbDXaBaMbxaRW24c02h4DdMQjeA4bRr9JgKDdRBjKHNPYQrahOJsPTmHtgm3ShV3VRvdISHDXB5H7tA7YTrfZ/YPfEBvVAkZm8hkaMRD4zQSbZB7v0FZGoqFvuH5De6c+QCmAi5ekLY/TOGMhQcEJs1alXKgdVKcVbyJTKjzVBFAbyVwKEgve0RmqzVat9JBPNiGyybO1IweoDQWBbtQNWBB05KFcEiJhwV9iQBgSZf+fBoYCHjgwHhUJGzSE2JARCAVVbcgyJTDAWRyzYCFmaLgBCKrYMKGTNUblzqbQALx6D0fTG8gAkwgwcg0SlC5raIqlwM69NDHGIAN56wce5emABuH60JHF3QAL73ywAuOU4pFQyhvKAgI3koDSP6nI0MRBFHDViCo4WZx1GNSZrFCghRjoBA8foyARiTEJnMZYihT9bEFKKU4kprj3FlKID49adTAnBJkmEhUUpImQGibEyAzNtI8TdBAug6iVwbm3PuQ8r4LxXhvHY86GduCbQsZBaZME5mKRIipJZACxCQDwXrdB61NrSVCTEeUEpenKn3oM4ZyQoTgNAhMmSeF5LzPfEs/xRBVnrI+XJAiuzlJkSKIcni4lZBJ3kGZFIllrLHJLKcta3ELkhO6bcpUKo76DJ3PYWB4JIVAP0lc0U4S7lRP5OmdJIsWG8PFhog6NjSHoPIU1apbL4wOU1tw5lolsFkOybzXJNCoAEqJUVS2WMipnztguB2EcXYVXdp7em4cnayADi0dmxJQ50E1X7bVUdbQJiKuvfSsZS6AVnufIsKKFwF2qjeTmpc4HwG9Cw4eo9RloGlqvG29rSWb0VdvG++Y8Wam1AYCAYAjAczJBSKkNI6QMiZCyNkpJuBWWkKSHcYjy5kguAvdgZIjW8hpUKGIFbhRGtxY4aNGpdT6iNCaU4RULSsCtNwhgsA7QSNRtPft5r0aKATp6qBk5ZCl2KvMVq7Z07WrTjaBcOjpA3hYRSWgpAV7JF4kMbMyLfTSUhguOwDDKDO1POOAa0dbaCVXKXBgE6Haf2/rESkkCWwPQXMkIg0B8DFE1qQOCq976DzhDA4Rlh5Anxtce/BOjiqQGhTaeDJB0NWUA8BndJAwPJGCbyrWkAhDRB4mu1VHUEDIDIMmSBBk2yUbdrDH0boRbxFYtC7hZ7/04ZA/h8DxMxAtDIBaFZGGMgfTKvISie0v3SFDHdM9KpuKur0u6k+glegPV7FRDMdz+B8Hru5KMfkQhwgBJe/KKNaGtus5wliLDIZsM9ITLhNpeFwP4TwbAQiZSiPEEWowOnyDeS1M22NBJE3kkpNSWkMp03MlZOyHN9pSQ3Iy+KDQaWSANvVBFltBpjQgg7eaS0DEbR9oHQ6IdkYPBjLeVOsWuaeO+QQcFUK4VCGICFeykVQqKKOu6xVVl1D+uYM5S1cbc9n0TiNtRrqZr7T8AYAwAmi6XPSHctgMQBM07xCSRgNgLzLWbzPViiJDBqVgKAqev0brkA5sQDEegzm/TwvEAwAAsmVVMDBECrnuONkt3J2Dad02NPgIQlRGcYqZqawRNJWZbnQWzRXSgOdNqLLb7D3MsU84SvhTkBF+eEYF8RtXQt5abZsaLxIk1xdTYlxkyWs25bJJl0H5AdKkk1QAcTyLActjtBdEmF/l2ndC22lbBJ2ir1oDjVfNbVtGRkTL8uFrIIQd9jmcZTgBRbcRJqi3JZqsD1YVXUF1z4TjscPQTthTwQ7WcPsEFdRwtgLcKwj3uOPPBwYc60GHndMHK9T4JWTIiXAt1/kfCEsBIclA04w4C8mdOFJjP9rgXr5AdLwQsPrsPVqH9x7D3np6ODw6kQ8UNvIS+C545SCNQRtAUTONWATL6HxenKDFhiC0dQGQ+RhFYhqHTkBW8GgkNoT0QiSBgzYC91r9IoSUCKvd502ec7saN9VuBAByZAAApVcAANPRu3UnoKSLIeOd0/yuRkSO0g3dIACBhkP1AwNjl5AQ9JTiIvOaD+HhQlOeUMORFhEdWgKwHhY+eQDJTiXIL0fyT+dHaXLHZhB6XHNzRzQ6A4LzYlUnfzERdgSnSRCfZXFbd7WIVzDhbHdII7JRb0QnKVEnXzEginItcLGNONBNBnWLFNBLekVnTNVLXNTncUDkFgUtXnTVAABU9WPG3z50dkUJIGUJr0l0K2lxKxODl3K27UqyVxf0HTRm53YCP2Lm4EsT61t0GhAi9HAjhXCjGzqgogQD7QnkVhzHmjuCORM2YjTh7D7EVTFXZXWhvHTyQN2iwGhUEkxymmiAkP5XCjsPX0FgySKhYWFEsTcIwEKGhS6A0CehwS2mM1yUgBnzcGkCNzn34kT1eBT0M3sOWwtWASAJLymiCysDACVTThOT/UsA0Mdk3Qeh9T93kGiDTiQXyMKIkmKMiISMgB6h4SRHHl/iwFaNzmyIeh3leEenYHX3oHHwein1KBn2rBUCsEX0U1azkynliAXEQPvXPlYyPnHC/n9BICkDEWU2rxzzO0aOTzunuzbCVTywT3Vxz1XR6JGJiFwX1yPi5joF1QSkhmhNrwOEVVwB8ERIcP8FeCThhmfwHXoGkmSNIHQPs0YWxxoOmjxzwO4UIJ80EXJzIOC1jRkgUKUO33kI011ww0WEcLAlsNyS4HmNkHaSIGcWaVwWGzKnyIlOhWlNlLcVKOlNaW4mlMgCCUGQXB5I0O3xvAsKhC4HzyKjdXkWSWYNFgU3HDyK5XGx5S7lSLKiFR4Miz4MJAEOTXizTVEJS2zQkKyzYGkPDDB15zglkEUWYBlF+08QByB1kR5GjNjPjL+xlEB2B25G0O1F0PbQMPhCMMVzaNV0MgjJzxEiPjLWOQyLdEJOONFn/EnA+wAEdddMSQ1WILNKAeB8BQwF0WEyMkh0AbBvcz0gcc0wQ0FMSjcuzV0lwdx5DLxoBNxoAABNeQncdc08QiNceQ8oUoDc9cncM/aAfEsdACbslQFEj5SNH2CgWgMY9/fiZHGcNXSsrErpGIX7LkS8g3IqMgt0BbSACfDrRRKaF0OHVPERVoqgugHvDAceSGRsvgICXgLqDsWIG0Ls6sk7VUOs8sTWEcs4ak+hWkrA1hUQXAhgggonbzdgtkgLDkydELMHT0uneNH0kkQQ/0lnDNIMjnUMkgcM2Q1UUkeQkyNIeOfAHmPeJAL7MkKSuBGSoMeS/MRSrMvM5tAs2XEWLtREYwss82YElZdDP0DUQDGwgARgAAYhluQaAXk9wgxPRTYwYYgUzc8x1h5E43sHpOimxS8ECkAXJ5ASASw+zOJkh584dOJxk+RvA+yl9EBc1BJ+SfigxogjYP0IRxL0ALBbc7Z9imyYrrjYgTk9JR908aIvCL1Ud6ACl2xh4HYCAKAIcfBB8EYR5Ry+1RBBRwYZIGrjieYO5WrqB/Bdd+1fCIqoRUxpAfFL5EB8BuqzLmtYrYDOMhhkxuwYYTlAQdj6A2zsBKB5Bpzsoyo+zg5JpQhEiCMN0MgypTcdsSBcEnQsAQj8EzsyF3cBZH56wN9HiMx4xBRBJDRtYMikRuoHoRr8oYQ0wWqZRJrW41qXTHJ1rDi194bUrWtTjJ9A0LjZ8KqwY8EAC/IHA6AwAnRKZYAeJAjCoOqDRg9gD3105/oMA54oxrzvtuR1B/A05Mcy5EBPKcyMArD790xWiLSAr2xOwPBIY0q2AZJS87rJoHrdcTqzrncqAvc+zH4+BFbLrGJi8mxFtxYEKcxg8TbWazLgjHYnIsBEDviYhsL0EyAR16R04taGILq9bW5yiVi0BAwiBHMQbAYzYjAMdMCuF6S6D8d8DQC2C4dmLSDC02K+gOLacotuKYs/TmcRDBL2cQyucZDIyJKFKftMykyxbSRK6Ez/tsyUydKMc9DTRwRDKe0qtTDyzIwIyecKN67q6m62VGsvRmtHtLEes+scIBtwjBiRsWUnS6oJtcAqlpsV7ZtgcsxZBBIYpr555uQQ8iBcr05KScLIbxZJ6eV4AFaPt1DNC4FHznz8ry664e7uznslN/kkE+sWEv6ZjXDl62pqMARaQSYDI3RYgXTMAGNV0H7t9n6FwuAw9ojVYpA4gEh395AdEWhUH2J0HnRfZsGEaToMwfj+I0THbUh2J9UUTzhiHk5EbMx+Ijc55vzIZTSeIzor8CZP0EpYLgJEQKSOxTCX4o6MDKLY7sC/R46mTWDicU6ycWL07B0oAO57ymEq7EyR6Qcy6B6ihLk86mdhCksxDgz0tS7+6y067NLtHG7kzWpbGtGG6szHGzbVR7AFwug8rJ6mDr8H5VFwRk4RT6Z1RIBdAp7NFwiNlF7rFgGFwDAImoAOUck0pIBYnJsTp8jEnCsc6jB5hAxIFSQ/BAgkcwgwBCnEtzGvdG7SQxkBz+bkRSRantKGnBz/Bd7VQCt8zW026ytiyjLSzLbTKvc+QGp3TfZnYesAKsocpTdwpShCGjVpnzJ2oE9chgxuA05E5dZN9IB+SkBERIAfbngxHuzmNRIXzLm3rljVi4abaF1tjg9dj+BkL68Ow3AGtRBCSiwqInidEbITqP4SoD9KQJwD91nzDgwXkrJcgSBQ6nnOMZbRYmAAoeIIJqyiNXTV1AW2GypFZpUOYio54bpIM50FEZJSWGENAsWccPtAXrCy5SzUK8BoYeIuQlApogJcjOGYXvybnsWMbcWqMo7o6pGnMZHaCaL6C1YFHGKlHODWK1HIAEzxnE9LrcpzQFFbSZb1F4gYyRE0ipmrdRJChOZFpDRaBdFoB+T8BLXrWugKlg5EBDWcgyolmJwVnTWSBzW9IHWbW7WA2nXF12EXsZJXGAclx3RGn2rZBOk11KAim81SmggLNEBKmk3qmgzWmAd6mY2Onmnc2vJ2mmmum75s7vSqninU3ymM3q3RKc3h783jJC3ZAWQ2yLByRsBqxaA+jfYwBi3aXO3cUendK+nCyDKFde0e7TLVwABFcoE506hiYUWWj/XtzBi2Yekh5qlhqaVozlx3Zw9AFmu6Q6lmroim6zNOIK7kdRUoXoOCHW9gTcCgdFsMEgTcRAzcW+9uVcMCmYcocoKFmjYCRxb8b2ld+QalwilhOvAyAczKGea145f59OBcac1999sRNgb91eX9l+3Z8kuGCaCwUTcBwh8eZweWg7DAOazxL1ftHiftDBhK6Gl5HD8QZW52wudfbC/F0ciy2IU5gzJUQfT59wJeRGxAGeWIbiKgFMloPdihqCz0F7V9RzFoC1wBQ0Z9uG+mPB29bkEA5DAzhMKhnIPSFRYImD5h1T5To+ZiPPURsk8izHCVn9aixkuipOxR9IVOrgjOqASgj+nwDIxEBWqVhk2iuV+i5OgL5RtOoLSdTi/JgwBtskWt9NzNigZNmp5t0tuNjtrtjd7wMAYWS3MAJvBkCEryRAEd7pqXCd/Sju6d7umrUy05qwq6G6NYigeObbPdbsGF4WBiQoc9DeB61cTt7xnywuQqWWhD+uUMA4vSXsY5fwNNzSLjz9vdTiUeX5kh3OA7a973TDjj3AN9j9vDn9v9tcQD4Dl8xWvzUTmIKwVWf4i2WaZgOyDUUcGiM4UoXAMGLIo3XrhhXiGgUcrI9/UbntCbggab2bzaQR+C85/+vjvgSblgB6++bEpHlICDFYjbzmQMPOCT4jbhCH2PH3X1FC6L9ba+F5MH9uYG4RrAbr5AIQL2R5psNE0902kzxHZua6nwHLS7673Dr9u7+gB73oIDkDnyo6wqmmVb1s+T+wLSu6HTo5PTs7vslhdh/7em/loqGrrdrz9bnibLnbm72gwNOvFGSR04KinA2VjzeL/z4g9k1R2rELwKsLiLzWScaL/xvhnjaBBi+BGRBdBcMr2gC3I2coXaI1ed6DmhPJqtrNmtrbut3L/LptnRlkHP0Sodht0d5r4rSdtrksmdzrurdGMqdV3+32SNzs4GhcdvoHPLxLE09TosTjI9/y0WMer2zh0vU3Yt6N1tstjQY15VHrP1+1+4K1xAENwY6fgtufxZ5Zk1veX13X3ANfp1o3XvQ23yIrzp43I9Mm4GpWp4u1uMmILQSaG8R/ERhCt/GwMqPtW9xhuzmQ33aB0wWhDA/OggPwlorAZwcAdWQcLzxt6/EXegnk2Kdodse2YiglBnypgKqQdJfEI1chG02A2nOeFmy+78A2WMMKPNQHc4x1JW3nWLp7z84KtEuSrP3hQUD41Z6WwkHVqkkToskmKSXILhXGD5KAjcw/ZGgulQDxw4yBeB6ICHjAtxIKTfX0IoBv6IZ9mzgbXj/QX7SB2+N4MZmoOE4Rth6PfZNv30OxpctgBgH4KIhIzXQjgrXIqJyCuAwh/UgzHtKiBdBvBMQnwHEIYFsGch1AhHRAG+yypSw6Am4TIDnmsGBCqgVQAAOw2AlADQWgDUBqB2VxgNgSkDYAYA2BJg8QhoKMDsoJCGg4wNIQ0BspoBxgnQBgHZQaAJD/BNgnYJACqA2UbKJASYKMAaACAEhpQhIXZXaEJC0AaASYJrDqA1CJgDQGwKMEpB1A0AJAUYAkMmD0gagTQ5oRAAhCyCQhYQwMBENoCbg9g+gIAA=== -->

<!-- internal state end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=ballerine-io/ballerine&utm_content=3246):

- 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](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@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](https://docs.coderabbit.ai/guides/configure-coderabbit) 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](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR