Support merge/col span cells horizontal in grid and hide a column #4050
Support merge/col span cells horizontal in grid and hide a column #4050lassopicasso wants to merge 10 commits intomainfrom
Conversation
📝 WalkthroughWalkthroughThis change introduces support for Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/layout/Grid/tools.ts (1)
109-117: Consider reducing type casting by leveraging existing type guards.The function uses
astype casting which the coding guidelines recommend avoiding. Since all non-nullGridCellvariants (GridCellText,GridCellLabelFrom,GridComponentRef) have the same optionalcolumnOptionsandgridColumnOptionsproperties, you could use the existing type guards to narrow the type.♻️ Suggested refactor using type guards
export function getGridCellHiddenExpr(cell: GridCell) { if (!cell || typeof cell !== 'object') { return undefined; } - const options = - 'columnOptions' in cell ? (cell as { columnOptions?: { hidden?: unknown } }).columnOptions : undefined; - const gridOpts = - 'gridColumnOptions' in cell ? (cell as { gridColumnOptions?: { hidden?: unknown } }).gridColumnOptions : undefined; - return gridOpts?.hidden ?? options?.hidden; + if (isGridCellText(cell) || isGridCellLabelFrom(cell) || isGridCellNode(cell)) { + return cell.gridColumnOptions?.hidden ?? cell.columnOptions?.hidden; + } + return undefined; }As per coding guidelines: "Avoid using
anyor type casting (as type) in TypeScript; instead, improve typing by removing such casts andanys to maintain proper type safety."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/layout/Grid/tools.ts` around lines 109 - 117, getGridCellHiddenExpr currently uses 'as' casts to access columnOptions/gridColumnOptions; instead use the existing type guards to narrow GridCell (e.g., isGridCellText, isGridCellLabelFrom, isGridComponentRef or whatever project's guards are named) and then read cell.columnOptions and cell.gridColumnOptions directly without casting, returning gridColumnOptions?.hidden ?? columnOptions?.hidden; remove the two '(cell as {...})' casts and the initial typeof check since the type guards handle null/undefined checks.src/layout/Grid/GridComponent.tsx (2)
255-260: Apply the same optional chaining and type safety improvements here.This section has the same pattern as the text/label cell handling and should be refactored similarly.
♻️ Suggested refactor
- const cellColSpan = (cell as { colSpan?: number } | null)?.colSpan; - if (cellColSpan !== undefined) { + const cellColSpan = cell && 'colSpan' in cell ? cell.colSpan : undefined; + if (cellColSpan !== undefined) { componentCellSettings = componentCellSettings ? { ...componentCellSettings, colSpan: cellColSpan } : { colSpan: cellColSpan }; }As per coding guidelines: "Avoid using
anyor type casting (as type) in TypeScript."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/layout/Grid/GridComponent.tsx` around lines 255 - 260, The code uses a type cast and manual null checks for colSpan; change to use optional chaining and a proper narrow type or type guard instead of "as". Replace the current block in GridComponent (where cellColSpan and componentCellSettings are set) with a check using cell?.colSpan (e.g., if (cell?.colSpan !== undefined) { componentCellSettings = componentCellSettings ? { ...componentCellSettings, colSpan: cell.colSpan } : { colSpan: cell.colSpan }; }) or introduce a CellWithColSpan interface and a small type guard function to ensure type-safe access to colSpan, avoiding any casts and preserving the existing merge logic for componentCellSettings.
203-208: Use optional chaining and reduce type casting.The SonarCloud analysis correctly identifies that optional chaining would be cleaner. Additionally, the
astype casting could be avoided by using a more type-safe approach.♻️ Suggested refactor
- const cellWithColSpan = cell as { colSpan?: number } | null; - if (cellWithColSpan && cellWithColSpan.colSpan !== undefined) { - textCellSettings = textCellSettings - ? { ...textCellSettings, colSpan: cellWithColSpan.colSpan } - : { colSpan: cellWithColSpan.colSpan }; - } + const cellColSpan = 'colSpan' in cell ? cell.colSpan : undefined; + if (cellColSpan !== undefined) { + textCellSettings = textCellSettings + ? { ...textCellSettings, colSpan: cellColSpan } + : { colSpan: cellColSpan }; + }As per coding guidelines: "Avoid using
anyor type casting (as type) in TypeScript."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/layout/Grid/GridComponent.tsx` around lines 203 - 208, Replace the ad-hoc type cast and manual null check with a type-safe user-defined type guard and optional chaining: add a small type guard function (e.g., hasColSpan(obj: unknown): obj is { colSpan?: number }) that checks obj is non-null object and has the 'colSpan' property, then use if (hasColSpan(cell) && cell.colSpan !== undefined) { textCellSettings = textCellSettings ? { ...textCellSettings, colSpan: cell.colSpan } : { colSpan: cell.colSpan }; } so you remove the "as" cast and use optional access via the guard when updating textCellSettings in GridComponent (reference symbols: hasColSpan, textCellSettings, cell).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/layout/Grid/GridComponent.tsx`:
- Around line 255-260: The code uses a type cast and manual null checks for
colSpan; change to use optional chaining and a proper narrow type or type guard
instead of "as". Replace the current block in GridComponent (where cellColSpan
and componentCellSettings are set) with a check using cell?.colSpan (e.g., if
(cell?.colSpan !== undefined) { componentCellSettings = componentCellSettings ?
{ ...componentCellSettings, colSpan: cell.colSpan } : { colSpan: cell.colSpan };
}) or introduce a CellWithColSpan interface and a small type guard function to
ensure type-safe access to colSpan, avoiding any casts and preserving the
existing merge logic for componentCellSettings.
- Around line 203-208: Replace the ad-hoc type cast and manual null check with a
type-safe user-defined type guard and optional chaining: add a small type guard
function (e.g., hasColSpan(obj: unknown): obj is { colSpan?: number }) that
checks obj is non-null object and has the 'colSpan' property, then use if
(hasColSpan(cell) && cell.colSpan !== undefined) { textCellSettings =
textCellSettings ? { ...textCellSettings, colSpan: cell.colSpan } : { colSpan:
cell.colSpan }; } so you remove the "as" cast and use optional access via the
guard when updating textCellSettings in GridComponent (reference symbols:
hasColSpan, textCellSettings, cell).
In `@src/layout/Grid/tools.ts`:
- Around line 109-117: getGridCellHiddenExpr currently uses 'as' casts to access
columnOptions/gridColumnOptions; instead use the existing type guards to narrow
GridCell (e.g., isGridCellText, isGridCellLabelFrom, isGridComponentRef or
whatever project's guards are named) and then read cell.columnOptions and
cell.gridColumnOptions directly without casting, returning
gridColumnOptions?.hidden ?? columnOptions?.hidden; remove the two '(cell as
{...})' casts and the initial typeof check since the type guards handle
null/undefined checks.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 67925669-d359-425d-a239-078444973770
📒 Files selected for processing (5)
src/codegen/Common.tssrc/layout/Grid/GridComponent.test.tsxsrc/layout/Grid/GridComponent.tsxsrc/layout/Grid/tools.test.tssrc/layout/Grid/tools.ts
|
/publish |
PR release:
|
PR release:
|
PR release:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/scripts/release.sh:
- Line 55: The revert script fails validation for pre-release tags because it
doesn't lowercase APP_FULL like release.sh does; update revert.sh to normalize
APP_FULL to lowercase (e.g., APP_FULL=$(echo "$APP_FULL" | tr '[:upper:]'
'[:lower:]')) before the VERSION_REGEX check so pre-release identifiers (like
RC1 -> rc1) match the expected `[a-z0-9.\-]+` pattern and revert logic that uses
APP_FULL will behave identically to release.sh.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3b6945e3-6f8f-4875-9916-cbb56211666f
📒 Files selected for processing (1)
.github/scripts/release.sh
PR release:
|
|
I send a message to ssb to test it , så we wait until they test |
|
|
Just a thought: TL:DR; I think |
|
@Jondyr @olemartinorg Regarding our meeting today, I asked Stian to share with us the app he used and what he tried to solve with the config colSpan/hidden; |
|
Jeg fant ikke @StianVestli Kan du forklare use-caset her? Vi har diskutert litt hvordan vi skal få dette på plass og designe det riktig fra starten av. Vi er ikke egentlig ute etter å vite hvilken konfigurasjon man trenger, eller hvilke sider/filer man trenger dem i, men om vi hadde skjønt litt bedre hva som er behovet bak dette ønsket kunne vi nok klart å lage noe bra og sammenhengende? Vi er altså redd for å lage noe som passer delvis, men som f.eks. er i konflikt med skjulte kolonner og som ender opp med å ikke fungere i all mulig praktisk bruk. Siden det er mye her vi ikke kan endre på etter det har blitt tatt i bruk, er det jo viktig at vi lager riktig løsning fra starten av, og da er det viktig for oss å vite hva dere ønsker å løse med denne konfigurasjonen. |
|
@olemartinorg colspan? det er satt opp dynamikk på på hidden på en colonne i gridden. Eller snakker vi om forskjellig ting her ? :) |
|
Men enkelt forklart så trenger jeg dette til å skjule en kolonne som ikke skal vises i visse tilfeller i skjema, feks i noen perioder i løpet av at år så skal ikke alle kolonner vises i gridden. Dette er jo det samma på repeterende grupper at man i noen situasjoner ikke vil vise en kolonne for en type respondenter. |
|
@JamalAlabdullah @Jondyr Jeg fikk høre at |



Description
In this PR we extended
GridComponent.tsxto support;colSpanon both text/label and component cells, so a cell can span multiple columns.What is implemented
colSpansupport for grid cellsWe added
colSpantoIGridColumnPropertiesinCommon.tsThis makes it possible to set
colSpandirectly on the cell:{ "text": "Header 1", "colSpan": 2 }or via "gridColumnOptions": { "colSpan": 2 }colSpan: We merge headercolumnOptions, per‑cellgridColumnOptions, and any cell‑levelcolSpanintocolumnStyleOptions, then evaluatecolumnStyleOptions.colSpanwithuseEvalExpressionand pass the result as the<th>/<td>colSpanso both text/label and component cells can span multiple columns.We added a
hiddenproperty toIGridColumnProperties, aligned withITableColumnProperties.hidden:This allows header cells to define visibility:
"text": "heading2","gridColumnOptions": { "hidden": false }Grid/tools.tscalledgetGridCellHiddenExprsmall helper that It returns the cell’s hidden expression, usinggridColumnOptions.hiddenif present, otherwise columnOptions.hidden.**After: colSpan/hidden in grid component **
Screen.Recording.2026-03-17.at.12.47.48.mov
**After:
colSpan/hiddeninrowsAfter/rowsBeforein repeating group in frontend-test app **rowsAfter.befor.mov
Related Issue(s)
Verification/QA
kind/*andbackport*label to this PR for proper release notes groupingSummary by CodeRabbit