Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(ui): aggregate risk scenarios in risk matrix to avoid bloating #1407

Merged

Conversation

Axxiar
Copy link
Contributor

@Axxiar Axxiar commented Jan 22, 2025

Only numbers of risks scenarios are now displayed in bubbles inside each cell.
You can access the list of risks scenarios from a cell by clicking on it, it will show up in a tooltip

Summary by CodeRabbit

  • New Features

    • Introduced a new interactive Cell component for the risk matrix.
    • Enhanced risk matrix visualization with dynamic bubble sizing.
    • Added popup functionality for displaying detailed cell data.
  • Improvements

    • Modularized cell rendering logic for better reusability.
    • Implemented responsive design for cell representation.
    • Updated HTML structure for improved semantic representation in RiskScenarioItem.
    • Added useBubbles property to control bubble display in the risk matrix.

@Axxiar Axxiar linked an issue Jan 22, 2025 that may be closed by this pull request
Copy link

coderabbitai bot commented Jan 22, 2025

Walkthrough

A new Svelte component Cell.svelte has been introduced to render cells in a risk matrix. This component handles dynamic rendering of cell data with features such as popups and scalable bubbles. The RiskMatrix.svelte file has been updated to import and utilize this new Cell component, replacing the previous inline cell rendering logic. Additionally, minor structural changes were made in RiskScenarioItem.svelte to enhance semantic representation without altering the underlying logic.

Changes

File Change Summary
frontend/src/lib/components/RiskMatrix/Cell.svelte New component created with props for cell, cellData, and dataItemComponent; includes TypeScript support and bubble size logic.
frontend/src/lib/components/RiskMatrix/RiskMatrix.svelte Imported Cell component and modified rendering logic to utilize the new component for displaying cell data; added useBubbles prop.
frontend/src/lib/components/RiskMatrix/RiskScenarioItem.svelte Changed <sup> element to <span> for displaying strength_of_knowledge.symbol without affecting logic.
frontend/src/routes/(app)/(internal)/risk-assessments/[id=uuid]/+page.svelte Added constant useBubbles set to true to be passed to RiskMatrix components.

Possibly related PRs

  • feat(ui): Add matrix reference in ebios RM study #1411: The changes in this PR involve modifications to a Svelte component related to the risk matrix, which may share context with the new Cell component introduced in the main PR, although they do not directly alter the same functions or logic.

Suggested reviewers

  • eric-intuitem

Poem

🐰 In the matrix of risk, a cell takes flight
With bubbles that dance and data so bright
A Svelte component, clever and neat
Transforming numbers to a visual treat
Code hops and leaps with rabbit delight! 🎲


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
frontend/src/lib/components/RiskMatrix/Cell.svelte (5)

7-8: Improve type safety for props.

The cellData prop uses Array<any> which loses type safety. Consider creating an interface for the data items.

+interface CellDataItem {
+    ref_id: string;
+    // add other required properties
+}
-export let cellData: Array<any> = [];
+export let cellData: Array<CellDataItem> = [];

5-8: Add JSDoc comments for props.

Add documentation for the props to improve maintainability and developer experience.

+/** The cell configuration containing level and color information */
 export let cell;
+/** Scale factor for bubble size calculation */
 export let bubbleSizeScale: number = 0;
+/** Array of data items to be displayed in the cell */
 export let cellData: Array<any> = [];
+/** Component to render individual data items */
 export let dataItemComponent;

10-17: Add error handling for missing ref_id and improve readability.

The popup target generation assumes all items have a ref_id property and the line is quite long.

 let popupClick: PopupSettings;
 if (cellData.length) {
+    const targetId = cellData
+        .map(e => e.ref_id ?? 'unknown')
+        .join('-');
     popupClick = {
         event: 'click',
-        target: 'popup' + 'data' + '-' + cellData.map((e) => e.ref_id).join('-'),
+        target: `popup-data-${targetId}`,
         placement: 'top'
     };
 }

19-22: Extract magic numbers and add validation for bubble size calculation.

The bubble size calculation uses magic numbers and lacks validation.

+const MIN_BUBBLE_SIZE = 7;
+const MAX_SCALE_FACTOR = 9;
+const SIZE_TO_REM_RATIO = 4;

 $: classesBubbleSize = (itemNumber: number) => {
-    itemNumber = (itemNumber / bubbleSizeScale) * 9 + 7; // rescaled to 16
+    if (itemNumber < 0 || bubbleSizeScale < 0) {
+        console.warn('Invalid bubble size parameters');
+        return '';
+    }
+    const scaledSize = (itemNumber / bubbleSizeScale) * MAX_SCALE_FACTOR + MIN_BUBBLE_SIZE;
-    return `width: ${itemNumber / 4}rem; height: ${itemNumber / 4}rem`;
+    return `width: ${scaledSize / SIZE_TO_REM_RATIO}rem; height: ${scaledSize / SIZE_TO_REM_RATIO}rem`;
 };

54-62: Maintain consistency with main cell and improve accessibility.

The fallback cell has inconsistent styling and lacks accessibility attributes.

 <div
     class="flex flex-wrap items-center space-x-1 justify-center h-full [&>*]:pointer-events-none whitespace-normal overflow-y-scroll hide-scrollbar {classesCellText(
         cell.level.hexcolor
     )}"
     style="background-color: {cell.level.hexcolor};"
     data-testid="cell"
+    role="cell"
+    aria-label="Empty risk matrix cell"
 >
-    <div class="mx-auto text-center">{cellData}</div>
+    <div class="mx-auto text-center" aria-hidden="true">{cellData}</div>
 </div>
frontend/src/lib/components/RiskMatrix/RiskMatrix.svelte (1)

44-49: Optimize array operations and add error handling.

The calculation of biggestCelldataLength could be optimized and needs error handling.

 let biggestCelldataLength: number;
 if (displayedData) {
-    biggestCelldataLength = displayedData
-        .flat(1)
-        .reduce((max, e) => (e.length > max.length ? e : max), []).length;
+    try {
+        const flatData = displayedData.flat(1);
+        if (flatData.length === 0) {
+            biggestCelldataLength = 0;
+        } else {
+            biggestCelldataLength = Math.max(...flatData.map(e => e.length));
+        }
+    } catch (error) {
+        console.error('Error calculating cell data length:', error);
+        biggestCelldataLength = 0;
+    }
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2f1badb and 070ca19.

📒 Files selected for processing (2)
  • frontend/src/lib/components/RiskMatrix/Cell.svelte (1 hunks)
  • frontend/src/lib/components/RiskMatrix/RiskMatrix.svelte (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: startup-functional-test (3.12)
  • GitHub Check: enterprise-startup-functional-test (3.12)
  • GitHub Check: enterprise-startup-docker-compose-test
  • GitHub Check: functional-tests (3.12, chromium)
  • GitHub Check: migrations-check (3.12)
  • GitHub Check: enterprise-functional-tests (3.12, chromium)
  • GitHub Check: startup-docker-compose-test
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
frontend/src/lib/components/RiskMatrix/RiskMatrix.svelte (1)

90-99: 🛠️ Refactor suggestion

Add key prop and make props passing more explicit.

The Cell component iteration needs a key prop and props passing could be more explicit.

 {#if displayedData}
     <Cell
+        key={`cell-${i}-${j}`}
         {cell}
         cellData={displayedData[i][j]}
         bubbleSizeScale={biggestCelldataLength}
         {dataItemComponent}
     />
 {:else}
-    <Cell {cell} {dataItemComponent} />
+    <Cell
+        key={`cell-${i}-${j}`}
+        {cell}
+        cellData={[]}
+        bubbleSizeScale={0}
+        {dataItemComponent}
+    />
 {/if}

Likely invalid or redundant comment.

Comment on lines 28 to 52
{#if cellData.length && dataItemComponent}
<div
class="flex flex-wrap items-center space-x-1 justify-center h-full cursor-pointer whitespace-normal overflow-y-scroll hide-scrollbar {classesCellText(
cell.level.hexcolor
)}"
style="background-color: {cell.level.hexcolor};"
data-testid="cell"
use:popup={popupClick}
>
<div
class="bg-surface-900/80 rounded-full flex justify-center items-center text-center text-white"
style="{classesBubbleSize(cellData.length)};"
>
{cellData.length}
</div>
<div
class="card bg-black text-gray-200 p-4 z-20"
data-popup={'popup' + 'data' + '-' + cellData.map((e) => e.ref_id).join('-')}
>
{#each cellData as item}
<svelte:component this={dataItemComponent} data={item} />
{/each}
<div class="arrow bg-black" />
</div>
</div>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve accessibility and overflow handling.

The cell needs accessibility improvements and better overflow handling.

 <div
     class="flex flex-wrap items-center space-x-1 justify-center h-full cursor-pointer whitespace-normal overflow-y-scroll hide-scrollbar {classesCellText(
         cell.level.hexcolor
     )}"
     style="background-color: {cell.level.hexcolor};"
     data-testid="cell"
+    role="button"
+    aria-label="Click to view {cellData.length} risk scenarios"
+    tabindex="0"
     use:popup={popupClick}
 >
     <div
         class="bg-surface-900/80 rounded-full flex justify-center items-center text-center text-white"
         style="{classesBubbleSize(cellData.length)};"
+        aria-hidden="true"
     >
         {cellData.length}
     </div>
     <div
-        class="card bg-black text-gray-200 p-4 z-20"
+        class="card bg-black text-gray-200 p-4 z-20 max-h-[80vh] overflow-y-auto"
         data-popup={'popup' + 'data' + '-' + cellData.map((e) => e.ref_id).join('-')}
+        role="dialog"
+        aria-label="Risk scenarios details"
     >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{#if cellData.length && dataItemComponent}
<div
class="flex flex-wrap items-center space-x-1 justify-center h-full cursor-pointer whitespace-normal overflow-y-scroll hide-scrollbar {classesCellText(
cell.level.hexcolor
)}"
style="background-color: {cell.level.hexcolor};"
data-testid="cell"
use:popup={popupClick}
>
<div
class="bg-surface-900/80 rounded-full flex justify-center items-center text-center text-white"
style="{classesBubbleSize(cellData.length)};"
>
{cellData.length}
</div>
<div
class="card bg-black text-gray-200 p-4 z-20"
data-popup={'popup' + 'data' + '-' + cellData.map((e) => e.ref_id).join('-')}
>
{#each cellData as item}
<svelte:component this={dataItemComponent} data={item} />
{/each}
<div class="arrow bg-black" />
</div>
</div>
{#if cellData.length && dataItemComponent}
<div
class="flex flex-wrap items-center space-x-1 justify-center h-full cursor-pointer whitespace-normal overflow-y-scroll hide-scrollbar {classesCellText(
cell.level.hexcolor
)}"
style="background-color: {cell.level.hexcolor};"
data-testid="cell"
role="button"
aria-label="Click to view {cellData.length} risk scenarios"
tabindex="0"
use:popup={popupClick}
>
<div
class="bg-surface-900/80 rounded-full flex justify-center items-center text-center text-white"
style="{classesBubbleSize(cellData.length)};"
aria-hidden="true"
>
{cellData.length}
</div>
<div
class="card bg-black text-gray-200 p-4 z-20 max-h-[80vh] overflow-y-auto"
data-popup={'popup' + 'data' + '-' + cellData.map((e) => e.ref_id).join('-')}
role="dialog"
aria-label="Risk scenarios details"
>
{#each cellData as item}
<svelte:component this={dataItemComponent} data={item} />
{/each}
<div class="arrow bg-black" />
</div>
</div>
{/if}

@Axxiar
Copy link
Contributor Author

Axxiar commented Jan 22, 2025

Bubbles are currently sized according to the cell presenting most risk scenarios. This should be changed to a fixed scale to avoid confusion.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
frontend/src/lib/components/RiskMatrix/Cell.svelte (1)

5-7: Add TypeScript interfaces and JSDoc comments for props.

The props would benefit from stronger typing and documentation:

  • Replace Array<any> with a specific interface
  • Add JSDoc comments describing the purpose and shape of each prop
+interface CellData {
+    ref_id: string;
+    // Add other required properties
+}
+
+/** The cell configuration containing level and color information */
 export let cell;
+/** Array of risk scenarios to be displayed in this cell */
-export let cellData: Array<any> = [];
+export let cellData: CellData[] = [];
+/** The component to render for each risk scenario */
 export let dataItemComponent;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 070ca19 and b563fe9.

📒 Files selected for processing (2)
  • frontend/src/lib/components/RiskMatrix/Cell.svelte (1 hunks)
  • frontend/src/lib/components/RiskMatrix/RiskMatrix.svelte (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: startup-functional-test (3.12)
  • GitHub Check: enterprise-startup-functional-test (3.12)
  • GitHub Check: functional-tests (3.12, chromium)
  • GitHub Check: enterprise-startup-docker-compose-test
  • GitHub Check: enterprise-functional-tests (3.12, chromium)
  • GitHub Check: startup-docker-compose-test
  • GitHub Check: Analyze (python)
🔇 Additional comments (3)
frontend/src/lib/components/RiskMatrix/Cell.svelte (2)

41-82: Previous accessibility suggestions still need to be implemented.

The accessibility improvements suggested in the previous review remain relevant.


10-18: Revise bubble size calculation as per PR comments.

As noted in the PR comments, the current implementation sizes bubbles relative to the cell with most scenarios. Consider using a fixed scale instead to avoid user confusion.

Suggested approach:

  • Define a minimum and maximum bubble size
  • Use a linear scale between these sizes
  • Cap the size at the maximum even for larger counts
-const bubbleSizeRanges = [
-    { max: 3, value: 1.5 },
-    { max: 5, value: 2 },
-    { max: 8, value: 2.5 },
-    { max: 13, value: 3 },
-    { max: 21, value: 3.5 },
-    { max: 34, value: 4 },
-    { max: 55, value: 4.25 }
-];
+const MIN_BUBBLE_SIZE = 1.5;
+const MAX_BUBBLE_SIZE = 3;
+const MAX_COUNT_FOR_SCALING = 20;
frontend/src/lib/components/RiskMatrix/RiskMatrix.svelte (1)

83-87: LGTM! Clean implementation of the Cell component.

The changes effectively modularize the cell rendering logic by using the new Cell component.

Comment on lines 21 to 27
if (cellData.length) {
popupClick = {
event: 'click',
target: 'popup' + 'data' + '-' + cellData.map((e) => e.ref_id).join('-'),
placement: 'top'
};
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve popup target generation and add validation.

The current implementation has potential issues:

  • Long concatenated strings of ref_ids could exceed length limits
  • No validation of ref_ids existence
 if (cellData.length) {
+    const validRefIds = cellData
+        .filter(item => item.ref_id)
+        .map(item => item.ref_id);
+    if (validRefIds.length !== cellData.length) {
+        console.warn('Some items are missing ref_id');
+    }
     popupClick = {
         event: 'click',
-        target: 'popup' + 'data' + '-' + cellData.map((e) => e.ref_id).join('-'),
+        target: `popup-${validRefIds.slice(0, 3).join('-')}`,
         placement: 'top'
     };
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (cellData.length) {
popupClick = {
event: 'click',
target: 'popup' + 'data' + '-' + cellData.map((e) => e.ref_id).join('-'),
placement: 'top'
};
}
if (cellData.length) {
const validRefIds = cellData
.filter(item => item.ref_id)
.map(item => item.ref_id);
if (validRefIds.length !== cellData.length) {
console.warn('Some items are missing ref_id');
}
popupClick = {
event: 'click',
target: `popup-${validRefIds.slice(0, 3).join('-')}`,
placement: 'top'
};
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
frontend/src/lib/components/RiskMatrix/Cell.svelte (2)

29-35: Improve bubble size calculation logic.

The bubble size calculation function has the following issues:

  • No default case for values exceeding the maximum range (55)
  • Could be simplified using Array.find
-$: classesBubbleSize = (itemCount: number) => {
-    for (const range of bubbleSizeRanges) {
-        if (itemCount <= range.max) {
-            return `width: ${range.value}rem; height: ${range.value}rem`;
-        }
-    }
-};
+$: classesBubbleSize = (itemCount: number) => {
+    const range = bubbleSizeRanges.find(range => itemCount <= range.max) 
+        ?? bubbleSizeRanges[bubbleSizeRanges.length - 1];
+    return `width: ${range.value}rem; height: ${range.value}rem`;
+};

56-65: Fix popup arrow visibility.

The popup arrow might be hidden due to overflow-y-scroll on the parent div. Consider moving the arrow outside the scrollable area.

-<div
-    class="card bg-surface-300 text-black p-4 z-20 max-h-56 overflow-y-scroll"
-    data-popup={'popup' + 'data' + '-' + cellData.map((e) => e.ref_id).join('-')}
->
-    {#each cellData as item}
-        <svelte:component this={dataItemComponent} data={item} />
-    {/each}
-    <!-- not displayed because of overflow-y-scroll on parent -->
-    <div class="arrow bg-surface-300" />
-</div>
+<div class="card bg-surface-300 text-black z-20 relative">
+    <div class="p-4 max-h-56 overflow-y-auto">
+        {#each cellData as item}
+            <svelte:component this={dataItemComponent} data={item} />
+        {/each}
+    </div>
+    <div class="arrow bg-surface-300 absolute" />
+</div>
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b563fe9 and c385993.

📒 Files selected for processing (2)
  • frontend/src/lib/components/RiskMatrix/Cell.svelte (1 hunks)
  • frontend/src/lib/components/RiskMatrix/RiskScenarioItem.svelte (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/lib/components/RiskMatrix/RiskScenarioItem.svelte
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: startup-functional-test (3.12)
  • GitHub Check: startup-docker-compose-test
  • GitHub Check: functional-tests (3.12, chromium)
  • GitHub Check: enterprise-startup-functional-test (3.12)
  • GitHub Check: enterprise-startup-docker-compose-test
  • GitHub Check: enterprise-functional-tests (3.12, chromium)
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
frontend/src/lib/components/RiskMatrix/Cell.svelte (2)

21-27: Improve popup target generation and add validation.

The current implementation has potential issues:

  • Long concatenated strings of ref_ids could exceed length limits
  • No validation of ref_ids existence

41-66: Improve accessibility and overflow handling.

The cell needs accessibility improvements and better overflow handling.

Comment on lines +5 to +7
export let cell;
export let cellData: Array<any> = [];
export let dataItemComponent;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add proper TypeScript types for props.

The current prop declarations lack proper typing, which reduces type safety. Consider adding proper TypeScript interfaces and type validation.

+interface CellLevel {
+    hexcolor: string;
+}
+
+interface Cell {
+    level: CellLevel;
+}
+
+interface RiskScenario {
+    ref_id: string;
+    // Add other required properties
+}
+
+interface SvelteComponent {
+    // Add required component properties
+}
+
-export let cell;
-export let cellData: Array<any> = [];
-export let dataItemComponent;
+export let cell: Cell;
+export let cellData: RiskScenario[] = [];
+export let dataItemComponent: typeof SvelteComponent;

Committable suggestion skipped: line range outside the PR's diff.

@Axxiar
Copy link
Contributor Author

Axxiar commented Jan 24, 2025

I've set the minimum risk scenario to 3 in a cell to dislay a bubble (was 2). So now, cells with one or two risk scenarios are displayed it as plain text

@Mohamed-Hacene Mohamed-Hacene marked this pull request as draft January 24, 2025 14:32
@ab-smith ab-smith marked this pull request as ready for review January 24, 2025 18:12
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
frontend/src/lib/components/RiskMatrix/Cell.svelte (1)

21-29: 🛠️ Refactor suggestion

Validate concatenated popup target strings.
Concatenating ref_id arrays could get overly long or fail if items lack ref_id. This issue was flagged in a previous review. Consider sanitizing or truncating.

🧹 Nitpick comments (1)
frontend/src/routes/(app)/(internal)/risk-assessments/[id=uuid]/+page.svelte (1)

24-24: Consider a threshold alignment for bubbles.
You set useBubbles = true; here, but your stated intention in the PR was to display a bubble only if risk scenarios ≥ 3. If that’s still valid, consider passing an explicit threshold or adjusting the logic in the Cell.svelte file to ensure consistency.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ff91fb4 and 78ee9f5.

📒 Files selected for processing (3)
  • frontend/src/lib/components/RiskMatrix/Cell.svelte (1 hunks)
  • frontend/src/lib/components/RiskMatrix/RiskMatrix.svelte (3 hunks)
  • frontend/src/routes/(app)/(internal)/risk-assessments/[id=uuid]/+page.svelte (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: enterprise-functional-tests (3.12, chromium)
  • GitHub Check: functional-tests (3.12, chromium)
🔇 Additional comments (9)
frontend/src/routes/(app)/(internal)/risk-assessments/[id=uuid]/+page.svelte (2)

271-271: Confirm consistent usage of the bubble feature.
You’re passing useBubbles as a prop, which is good for modularity. Verify that all risk matrix cells are intended to show bubbles in this particular risk assessment context.


282-282: Same bubble activation logic.
Similarly, ensure that the residual risk matrix’s cells should also display bubbles at the same threshold as the current risk matrix. This preserves a consistent user experience.

frontend/src/lib/components/RiskMatrix/Cell.svelte (4)

5-9: Add stronger typing for props.
Exporting cellData: Array<any> reduces type safety. Previously, a similar suggestion was made to define detailed interfaces for these props (e.g., an interface for RiskScenario).


30-41: Efficient reactive styling.
The functions classesBubbleSize and classesCellText are clear and straightforward. If performance becomes a concern, memoize these to avoid repeated computations.


43-69: Add basic accessibility enhancements.
To improve keyboard navigation and screen reader support, consider adding role="button" and aria-label attributes. This is functionally the same request as a prior accessibility suggestion.


70-85: Fallback behavior matches new bubble logic.
When useBubbles is false or item count is under the threshold, you correctly show the fallback content. Just ensure you update bubbleMinCount (currently 1) if you truly intend to hide bubbles for fewer than 3 risk scenarios.

frontend/src/lib/components/RiskMatrix/RiskMatrix.svelte (3)

3-3: Good modular design with Cell import.
Importing the Cell component keeps the matrix logic cleaner and more maintainable.


17-17: Defaulting useBubbles to false.
This default ensures backward compatibility. Just confirm that all consuming code explicitly opts in to the new bubble behavior if desired.


84-87: Effective conditional cell rendering.
Using <Cell> with or without displayedData clarifies the matrix logic. This separation keeps the codebase organized and flexible for future changes.

Comment on lines +10 to +20
const bubbleMinCount = 1;
const maxBubbleSize = 4.5;
const bubbleSizeRanges = [
{ max: 3, value: 1.5 },
{ max: 5, value: 2 },
{ max: 8, value: 2.5 },
{ max: 13, value: 3 },
{ max: 21, value: 3.5 },
{ max: 34, value: 4 }
];

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Revisit bubble size thresholds.
Your code dynamically grows bubble sizes but might conflict with user feedback requesting a uniform/fixed scale. Also, bubbleMinCount is set to 1, but your PR notes a threshold of 3. Consider aligning this logic with the agreed bubble sizing policy.

-const bubbleMinCount = 1;
+const bubbleMinCount = 3; 
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const bubbleMinCount = 1;
const maxBubbleSize = 4.5;
const bubbleSizeRanges = [
{ max: 3, value: 1.5 },
{ max: 5, value: 2 },
{ max: 8, value: 2.5 },
{ max: 13, value: 3 },
{ max: 21, value: 3.5 },
{ max: 34, value: 4 }
];
const bubbleMinCount = 3;
const maxBubbleSize = 4.5;
const bubbleSizeRanges = [
{ max: 3, value: 1.5 },
{ max: 5, value: 2 },
{ max: 8, value: 2.5 },
{ max: 13, value: 3 },
{ max: 21, value: 3.5 },
{ max: 34, value: 4 }
];

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

🧹 Nitpick comments (1)
frontend/src/lib/components/RiskMatrix/Cell.svelte (1)

69-83: Improve plain display accessibility and error handling.

The plain display needs accessibility improvements and better error handling.

 <div
     class="flex flex-wrap flex-col items-center justify-center h-full [&>*]:pointer-events-none whitespace-normal overflow-y-scroll hide-scrollbar {classesCellText(
         cell.level.hexcolor
     )}"
     style="background-color: {cell.level.hexcolor};"
     data-testid="cell"
+    role="region"
+    aria-label="Risk scenarios"
 >
     {#if dataItemComponent}
-        {#each cellData as item}
+        {#each cellData as item, i (item?.id)}
             <svelte:component this={dataItemComponent} data={item} />
         {/each}
     {:else}
-        <div class="mx-auto text-center">{cellData}</div>
+        <div class="mx-auto text-center">
+            {#if Array.isArray(cellData) && cellData.length}
+                {cellData}
+            {:else}
+                <span aria-label="No risk scenarios">-</span>
+            {/if}
+        </div>
     {/if}
 </div>
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 78ee9f5 and dcbbf36.

📒 Files selected for processing (2)
  • frontend/src/lib/components/RiskMatrix/Cell.svelte (1 hunks)
  • frontend/src/lib/components/RiskMatrix/RiskMatrix.svelte (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/lib/components/RiskMatrix/RiskMatrix.svelte
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: startup-functional-test (3.12)
  • GitHub Check: startup-docker-compose-test
  • GitHub Check: enterprise-startup-functional-test (3.12)
  • GitHub Check: functional-tests (3.12, chromium)
  • GitHub Check: Analyze (python)
  • GitHub Check: enterprise-startup-docker-compose-test
  • GitHub Check: enterprise-functional-tests (3.12, chromium)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
frontend/src/lib/components/RiskMatrix/Cell.svelte (3)

5-9: Add proper TypeScript types for props.

The props lack proper typing, which reduces type safety. This is particularly concerning for cellData: Array<any>.


11-20: ⚠️ Potential issue

Update bubble configuration to match requirements.

The current implementation has two issues that conflict with the PR objectives:

  1. bubbleMinCount is set to 1, but should be 3 per PR notes
  2. Dynamic bubble sizing via ranges conflicts with the request for a fixed scale

Apply this diff to align with requirements:

-const bubbleMinCount = 1;
-const maxBubbleSize = 4.5;
-const bubbleSizeRanges = [
-    { max: 3, value: 1.5 },
-    { max: 5, value: 2 },
-    { max: 8, value: 2.5 },
-    { max: 13, value: 3 },
-    { max: 21, value: 3.5 },
-    { max: 34, value: 4 }
-];
+const bubbleMinCount = 3;
+const bubbleSize = 3; // Fixed size as requested

Likely invalid or redundant comment.


44-67: 🛠️ Refactor suggestion

Enhance accessibility and user experience.

The bubble view needs accessibility and UX improvements:

  1. Missing keyboard navigation
  2. Scroll behavior could be improved
  3. Missing ARIA attributes

Apply these improvements:

 {#if useBubbles && cellData.length >= bubbleMinCount && dataItemComponent}
     <div
         class="flex flex-wrap items-center space-x-1 justify-center h-full cursor-pointer whitespace-normal overflow-y-scroll hide-scrollbar group {classesCellText(
             cell.level.hexcolor
         )}"
         style="background-color: {cell.level.hexcolor};"
         data-testid="cell"
+        role="button"
+        tabindex="0"
+        on:keydown={(e) => e.key === 'Enter' && e.target.click()}
+        aria-label="{cellData.length} risk scenarios"
         use:popup={popupClick}
     >
         <div
             class="bg-surface-900/70 rounded-full flex justify-center items-center text-center text-white transition-colors group-hover:bg-surface-900/100 duration-300"
-            style="{classesBubbleSize(cellData.length)};"
+            style="{classesBubbleSize()};"
+            aria-hidden="true"
         >
             {cellData.length}
         </div>
-        <div class="card bg-surface-300 text-black z-20" data-popup={popupTarget}>
-            <div class="max-h-56 overflow-y-scroll p-4">
+        <div 
+            class="card bg-surface-300 text-black z-20" 
+            data-popup={popupTarget}
+            role="dialog"
+            aria-label="Risk scenarios details"
+        >
+            <div class="max-h-56 overflow-y-auto p-4 focus:outline-none">
                 {#each cellData as item}
                     <svelte:component this={dataItemComponent} data={item} />
                 {/each}
                 <div class="arrow bg-surface-300" />
             </div>
         </div>
     </div>

Likely invalid or redundant comment.

Comment on lines +31 to +38
$: classesBubbleSize = (itemCount: number) => {
for (const range of bubbleSizeRanges) {
if (itemCount <= range.max) {
return `width: ${range.value}rem; height: ${range.value}rem`;
}
}
return `width: ${maxBubbleSize}rem; height: ${maxBubbleSize}rem`;
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Simplify bubble sizing logic for fixed scale.

Since we're moving to a fixed bubble size as per requirements, this reactive statement can be simplified.

-$: classesBubbleSize = (itemCount: number) => {
-    for (const range of bubbleSizeRanges) {
-        if (itemCount <= range.max) {
-            return `width: ${range.value}rem; height: ${range.value}rem`;
-        }
-    }
-    return `width: ${maxBubbleSize}rem; height: ${maxBubbleSize}rem`;
-};
+$: classesBubbleSize = () => `width: ${bubbleSize}rem; height: ${bubbleSize}rem`;

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +22 to +29
let popupClick: PopupSettings;
if (cellData.length && popupTarget) {
popupClick = {
event: 'click',
target: popupTarget,
placement: 'top'
};
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation and accessibility for popup.

The popup configuration needs validation and accessibility improvements:

  1. No validation of popupTarget
  2. Missing ARIA attributes for accessibility

Apply these improvements:

 let popupClick: PopupSettings;
-if (cellData.length && popupTarget) {
+if (cellData.length && typeof popupTarget === 'string' && popupTarget.trim()) {
     popupClick = {
         event: 'click',
         target: popupTarget,
-        placement: 'top'
+        placement: 'top',
+        // Add ARIA attributes
+        ariaLabel: `${cellData.length} risk scenarios`,
+        ariaExpanded: false
     };
+} else if (cellData.length) {
+    console.warn('Invalid popupTarget provided for cell with data');
 }

Committable suggestion skipped: line range outside the PR's diff.

@ab-smith ab-smith self-requested a review January 24, 2025 20:27
Copy link
Contributor

@ab-smith ab-smith left a comment

Choose a reason for hiding this comment

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

functional ok, next step is to make this parametric, either on the risk assessment page or a general setting

@ab-smith ab-smith merged commit 0babd1b into main Jan 24, 2025
18 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Jan 24, 2025
@ab-smith ab-smith deleted the CA-819-aggregate-risk-scenarios-in-risk-matrix-to-avoid-bloating branch January 24, 2025 23:11
@ab-smith
Copy link
Contributor

relates to #1434

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enhance matrix readability for large risk assessment
2 participants