diff --git a/src/codegen/Common.ts b/src/codegen/Common.ts
index 2f5d53021d..09a3683c14 100644
--- a/src/codegen/Common.ts
+++ b/src/codegen/Common.ts
@@ -454,6 +454,29 @@ const common = {
),
ITableColumnFormatting: () => new CG.obj().additionalProperties(CG.common('ITableColumnProperties')),
ITableColumnProperties: () =>
+ new CG.obj(
+ new CG.prop(
+ 'width',
+ new CG.str()
+ .optional({ default: 'auto' })
+ .setTitle('Width')
+ .setDescription("Width of cell in % or 'auto'. Defaults to 'auto'")
+ .setPattern(/^([0-9]{1,2}%|100%|auto)$/),
+ ),
+ new CG.prop('alignText', CG.common('ITableColumnsAlignText').optional()),
+ new CG.prop('textOverflow', CG.common('ITableColumnsTextOverflow').optional()),
+ )
+ .setTitle('Column options')
+ .setDescription('Options for the row/column')
+ .addExample({
+ width: 'auto',
+ alignText: 'left',
+ textOverflow: {
+ lineWrap: true,
+ maxHeight: 2,
+ },
+ }),
+ ITableColumnPropertiesWithHidden: () =>
new CG.obj(
new CG.prop(
'width',
diff --git a/src/language/texts/en.ts b/src/language/texts/en.ts
index db7c020b72..e109ed92be 100644
--- a/src/language/texts/en.ts
+++ b/src/language/texts/en.ts
@@ -416,6 +416,10 @@ export function en() {
'config_error.group_no_deletion_strategy': 'When you have set group, you must also set deletionStrategy.',
'config_error.soft_delete_no_checked': 'When you have set deletionStrategy to soft, you must also set "checked".',
'config_error.hard_delete_with_checked': 'When you have set deletionStrategy to hard, you cannot set "checked".',
+ 'config_error.grid_diff_cell_columns':
+ 'There is a difference in number of cells({0}) on row {1} and the number of columns({2}). Make sure the rows have correct number of cells({2}).',
+ 'config_error.grid_column_option_cell':
+ 'You have a columnOption configuration on both cell and columns property. Please use the column property instead.',
'version_error.version_mismatch': 'Version mismatch',
'version_error.version_mismatch_message':
'This version of the app frontend is not compatible with the version of the backend libraries you are using. Update to the latest version of the packages and try again.',
diff --git a/src/language/texts/nb.ts b/src/language/texts/nb.ts
index 94fd17c1c9..65b2135374 100644
--- a/src/language/texts/nb.ts
+++ b/src/language/texts/nb.ts
@@ -420,6 +420,11 @@ export function nb() {
'config_error.group_no_deletion_strategy': 'Når du har satt group må du også sette deletionStrategy.',
'config_error.soft_delete_no_checked': 'Når du har satt deletionStrategy til soft må du også sette "checked".',
'config_error.hard_delete_with_checked': 'Når du har satt deletionStrategy til hard kan du ikke sette "checked".',
+ 'config_error.grid_diff_cell_columns':
+ 'Det er forskjell i antall celler({0}) på rad {1} og antall kolonner({2}). Sørg for at alle rader har korrekt antall celler({2}).',
+ 'config_error.grid_column_option_cell':
+ '"columnOption"-konfigurasjon er spesifisert både på "cell" og på "columns" egenskapene. Vennligst bruk "columns" egenskapen.',
+
'version_error.version_mismatch': 'Versjonsfeil',
'version_error.version_mismatch_message':
'Denne versjonen av app frontend er ikke kompatibel med den versjonen av backend-bibliotekene du bruker. Oppdater til nyeste versjon av pakkene og prøv igjen.',
diff --git a/src/language/texts/nn.ts b/src/language/texts/nn.ts
index a1e3e6f73a..a48eed90ae 100644
--- a/src/language/texts/nn.ts
+++ b/src/language/texts/nn.ts
@@ -417,6 +417,10 @@ export function nn() {
'config_error.group_no_deletion_strategy': 'Når du har sett group, må du også setje deletionStrategy.',
'config_error.soft_delete_no_checked': 'Når du har sett deletionStrategy til soft, må du også setje checked.',
'config_error.hard_delete_with_checked': 'Når du har sett deletionStrategy til hard, kan du ikkje setje checked.',
+ 'config_error.grid_diff_cell_columns':
+ 'Det er forskjell i talet på celler({0}) på rad {1} og talet på kolonnar({2}). Sørg for at alle rader har korrekt tal på celler({2}).',
+ 'config_error.grid_column_option_cell':
+ '"columnOption"-konfigurasjon er spesifisert både på "cell" og på "columns" eigenskapane. Ver vennleg og bruk "columns" eigenskapen.',
'version_error.version_mismatch': 'Versjonsfeil',
'version_error.version_mismatch_message':
'Denne versjonen av app frontend er ikkje kompatibel med den versjonen av backend-biblioteka du brukar. Oppdater til nyaste versjon av pakkane og prøv igjen.',
diff --git a/src/layout/Grid/GridComponent.tsx b/src/layout/Grid/GridComponent.tsx
index 9569cbd3dc..7502a3e12f 100644
--- a/src/layout/Grid/GridComponent.tsx
+++ b/src/layout/Grid/GridComponent.tsx
@@ -29,11 +29,17 @@ import { useIsHidden } from 'src/utils/layout/hidden';
import { useLabel } from 'src/utils/layout/useLabel';
import { useItemFor, useItemWhenType } from 'src/utils/layout/useNodeItem';
import type { PropsFromGenericComponent } from 'src/layout';
-import type { GridCell, GridRow, ITableColumnFormatting, ITableColumnProperties } from 'src/layout/common.generated';
+import type {
+ GridCell,
+ GridRow,
+ ITableColumnFormatting,
+ ITableColumnProperties,
+ ITableColumnPropertiesWithHidden,
+} from 'src/layout/common.generated';
export function RenderGrid(props: PropsFromGenericComponent<'Grid'>) {
const { baseComponentId } = props;
- const { rows, textResourceBindings, labelSettings } = useItemWhenType(baseComponentId, 'Grid');
+ const { rows, textResourceBindings, labelSettings, columns } = useItemWhenType(baseComponentId, 'Grid');
const { title, description, help } = textResourceBindings ?? {};
const columnSettings: ITableColumnFormatting = {};
const isMobile = useIsMobile();
@@ -68,6 +74,7 @@ export function RenderGrid(props: PropsFromGenericComponent<'Grid'>) {
)}
@@ -78,12 +85,13 @@ export function RenderGrid(props: PropsFromGenericComponent<'Grid'>) {
interface GridRowsProps {
rows: GridRow[];
+ columns?: ITableColumnProperties[] | undefined;
extraCells?: GridCell[];
isNested: boolean;
mutableColumnSettings: ITableColumnFormatting;
}
-export function GridRowsRenderer({ rows, extraCells = [], isNested, mutableColumnSettings }: GridRowsProps) {
+export function GridRowsRenderer({ rows, columns, extraCells = [], isNested, mutableColumnSettings }: GridRowsProps) {
const batches: { type: 'header' | 'body'; rows: GridRow[] }[] = [];
for (const row of rows) {
@@ -106,6 +114,7 @@ export function GridRowsRenderer({ rows, extraCells = [], isNested, mutableColum
{batch.rows.map((row, rowIdx) => (
{
row: GridRow;
+ columns?: ITableColumnProperties[] | undefined;
}
-function GridRowRenderer({ row, isNested, mutableColumnSettings }: GridRowProps) {
+function GridRowRenderer({ row, columns, isNested, mutableColumnSettings }: GridRowProps) {
const rowHidden = useIsGridRowHidden(row);
if (rowHidden) {
return null;
@@ -137,14 +147,17 @@ function GridRowRenderer({ row, isNested, mutableColumnSettings }: GridRowProps)
[css.fullWidthCellFirst]: isFirst && !isNested,
[css.fullWidthCellLast]: isLast && !isNested,
});
-
if (row.header && cell && 'columnOptions' in cell && cell.columnOptions) {
// eslint-disable-next-line react-compiler/react-compiler
mutableColumnSettings[cellIdx] = cell.columnOptions;
}
+ if (cell && columns && columns[cellIdx]) {
+ mutableColumnSettings[cellIdx] = { ...mutableColumnSettings[cellIdx], ...columns[cellIdx] }; //TODO: På sikt fjerne muligheten til å konfigurere på celle nivå.
+ }
+
if (isGridCellText(cell) || isGridCellLabelFrom(cell)) {
- let textCellSettings: ITableColumnProperties = mutableColumnSettings[cellIdx]
+ let textCellSettings: ITableColumnPropertiesWithHidden = mutableColumnSettings[cellIdx]
? structuredClone(mutableColumnSettings[cellIdx])
: {};
textCellSettings = { ...textCellSettings, ...cell };
@@ -202,7 +215,7 @@ function GridRowRenderer({ row, isNested, mutableColumnSettings }: GridRowProps)
interface CellProps {
className?: string;
- columnStyleOptions?: ITableColumnProperties;
+ columnStyleOptions?: ITableColumnPropertiesWithHidden;
isHeader?: boolean;
rowReadOnly?: boolean;
}
@@ -229,6 +242,10 @@ function CellWithComponent({
const isHidden = useIsHidden(baseComponentId);
const CellComponent = isHeader ? Table.HeaderCell : Table.Cell;
+ if (columnStyleOptions?.hidden === true) {
+ return;
+ }
+
if (!isHidden) {
const columnStyles = columnStyleOptions && getColumnStyles(columnStyleOptions);
return (
@@ -257,6 +274,10 @@ function CellWithText({ children, className, columnStyleOptions, help, isHeader
const { elementAsString } = useLanguage();
const CellComponent = isHeader ? Table.HeaderCell : Table.Cell;
+ if (columnStyleOptions?.hidden === true) {
+ return;
+ }
+
return (
): JSX.Element | null {
+ const { intermediateItem, externalItem } = props;
+ const rows = externalItem?.rows;
+ const columns = externalItem?.columns;
+
+ const { langAsString } = useLanguage();
+ const addError = NodesInternal.useAddError();
+
+ useEffect(() => {
+ let error: string | null = null;
+
+ if (Array.isArray(rows)) {
+ for (const [i, row] of rows.entries()) {
+ if (Array.isArray(row?.cells) && Array.isArray(columns) && row.cells.length !== columns?.length) {
+ error = langAsString(`config_error.grid_diff_cell_columns`, [row.cells.length, i + 1, columns?.length]);
+ }
+ for (const [_, cell] of row.cells.entries()) {
+ if (cell?.columnOptions && columns) {
+ error = langAsString('config_error.grid_column_option_cell');
+ }
+ }
+ }
+ }
+
+ if (error) {
+ addError(error, intermediateItem.id, 'node');
+ window.logErrorOnce(`Validation error for '${intermediateItem.id}': ${error}`);
+ }
+ }, [addError, columns, columns?.length, intermediateItem.id, langAsString, rows]);
+
+ return null;
+}
diff --git a/src/layout/Grid/config.ts b/src/layout/Grid/config.ts
index f9b82ff289..bbf2f60fcb 100644
--- a/src/layout/Grid/config.ts
+++ b/src/layout/Grid/config.ts
@@ -29,6 +29,7 @@ export const Config = new CG.component({
),
);
})
+ .addProperty(new CG.prop('columns', new CG.arr(CG.common('ITableColumnPropertiesWithHidden')).optional()))
.addProperty(new CG.prop('rows', CG.common('GridRows')))
.extends(CG.common('LabeledComponentProps'))
.extendTextResources(CG.common('TRBLabel'));
diff --git a/src/layout/Grid/index.tsx b/src/layout/Grid/index.tsx
index 3a4f29961c..63b14e738e 100644
--- a/src/layout/Grid/index.tsx
+++ b/src/layout/Grid/index.tsx
@@ -6,12 +6,13 @@ import type { ErrorObject } from 'ajv';
import { claimGridRowsChildren } from 'src/layout/Grid/claimGridRowsChildren';
import { GridDef } from 'src/layout/Grid/config.def.generated';
import { RenderGrid } from 'src/layout/Grid/GridComponent';
+import { GridLayoutValidator } from 'src/layout/Grid/GridLayoutValidator';
import { GridSummary } from 'src/layout/Grid/GridSummary';
import { GridSummaryComponent } from 'src/layout/Grid/GridSummaryComponent';
import { EmptyChildrenBoundary } from 'src/layout/Summary2/isEmpty/EmptyChildrenContext';
import type { PropsFromGenericComponent } from 'src/layout';
-import type { CompExternalExact } from 'src/layout/layout';
-import type { ChildClaimerProps, SummaryRendererProps } from 'src/layout/LayoutComponent';
+import type { CompExternalExact, NodeValidationProps } from 'src/layout/layout';
+import type { ChildClaimerProps, ExprResolver, SummaryRendererProps } from 'src/layout/LayoutComponent';
import type { Summary2Props } from 'src/layout/Summary2/SummaryComponent2/types';
export class Grid extends GridDef {
@@ -41,6 +42,25 @@ export class Grid extends GridDef {
claimGridRowsChildren(props, props.item.rows);
}
+ evalExpressions(props: ExprResolver<'Grid'>) {
+ const { item, evalBool } = props;
+
+ if (item.columns) {
+ for (const column in item.columns) {
+ item.columns[column].hidden = evalBool(item.columns[column].hidden, false);
+ }
+ }
+
+ return {
+ ...this.evalDefaultExpressions(props),
+ columns: item.columns ? item.columns : undefined,
+ };
+ }
+
+ renderLayoutValidators(props: NodeValidationProps<'Grid'>): JSX.Element | null {
+ return ;
+ }
+
/**
* Override layout validation to validate grid cells individually
*/
diff --git a/src/layout/RepeatingGroup/config.ts b/src/layout/RepeatingGroup/config.ts
index 16acbaf66f..8f0da3012b 100644
--- a/src/layout/RepeatingGroup/config.ts
+++ b/src/layout/RepeatingGroup/config.ts
@@ -288,7 +288,7 @@ export const Config = new CG.component({
),
),
)
- .extends(CG.common('ITableColumnProperties'))
+ .extends(CG.common('ITableColumnPropertiesWithHidden'))
.exportAs('IGroupColumnFormatting'),
)
.addExample({