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

Text cell with help text in grid #1286

Merged
merged 10 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions schemas/json/layout/layout.schema.v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -515,11 +515,27 @@
"title": "Text",
"description": "The text or text resource ID to be rendered in the cell",
"type": "string"
},
"help": {
"title": "Help text",
"description": "The help text or text resource ID to be rendered in the cell",
"type": "string"
}
},
"$ref": "#/definitions/tableColumnOptions",
"required": ["text"]
},
"gridLabelText": {
"properties": {
"labelFrom": {
"title": "Label from",
"description": "The ID of the component to be used to render text resources in the cell",
"type": "string"
}
},
"$ref": "#/definitions/tableColumnOptions",
"required": ["labelFrom"]
},
"gridCellComponent": {
"properties": {
"component": {
Expand Down
18 changes: 18 additions & 0 deletions src/layout/Grid/Grid.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,21 @@ tr > .fullWidthCellLast {
.tableCellFormatting:last-child {
width: calc(var(--cell-width) + 8.15%);
}

.textCell,
.textLabel,
.textLabel div {
display: flex;
}

.textLabel {
margin-top: 12px;
}

.textLabel div {
flex-wrap: nowrap;
}

.textLabel button {
align-self: flex-start;
}
115 changes: 92 additions & 23 deletions src/layout/Grid/GridComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import { Grid } from '@material-ui/core';
import cn from 'classnames';

import { ConditionalWrapper } from 'src/components/ConditionalWrapper';
import { Description } from 'src/components/form/Description';
import { FullWidthWrapper } from 'src/components/form/FullWidthWrapper';
import { HelpTextContainer } from 'src/components/form/HelpTextContainer';
import { Label } from 'src/components/form/Label';
import { useIsMobile } from 'src/hooks/useIsMobile';
import { useLanguage } from 'src/hooks/useLanguage';
import { GenericComponent } from 'src/layout/GenericComponent';
Expand All @@ -15,6 +18,7 @@ import { isGridRowHidden, nodesFromGrid } from 'src/layout/Grid/tools';
import { getColumnStyles } from 'src/utils/formComponentUtils';
import { LayoutNode } from 'src/utils/layout/LayoutNode';
import { LayoutPage } from 'src/utils/layout/LayoutPage';
import { getPlainTextFromNode } from 'src/utils/stringHelper';
import type { PropsFromGenericComponent } from 'src/layout';
import type { GridComponent, GridRow } from 'src/layout/Grid/types';
import type { ITableColumnFormatting, ITableColumnProperties } from 'src/layout/layout';
Expand Down Expand Up @@ -43,6 +47,7 @@ export function RenderGrid(props: PropsFromGenericComponent<'Grid'>) {
row={row}
isNested={isNested}
mutableColumnSettings={columnSettings}
node={node}
/>
))}
</Table>
Expand All @@ -54,9 +59,10 @@ interface GridRowProps {
row: GridRow<GridComponent>;
isNested: boolean;
mutableColumnSettings: ITableColumnFormatting;
node: LayoutNode;
}

export function GridRowRenderer({ row, isNested, mutableColumnSettings }: GridRowProps) {
export function GridRowRenderer({ row, isNested, mutableColumnSettings, node }: GridRowProps) {
const { lang } = useLanguage();

return isGridRowHidden(row) ? null : (
Expand All @@ -76,29 +82,45 @@ export function GridRowRenderer({ row, isNested, mutableColumnSettings }: GridRo
mutableColumnSettings[cellIdx] = cell.columnOptions;
}

if (cell && 'text' in cell && cell.text) {
if (cell && ('labelFrom' in cell || 'text' in cell)) {
let textCellSettings: ITableColumnProperties = mutableColumnSettings[cellIdx]
? structuredClone(mutableColumnSettings[cellIdx])
: {};
textCellSettings = { ...textCellSettings, ...cell };

return (
<CellWithText
key={`${cell.text}/${cellIdx}`}
className={className}
columnStyleOptions={textCellSettings}
>
{lang(cell.text)}
</CellWithText>
);
}
if ('text' in cell && cell.text) {
return (
<CellWithText
key={`${cell.text}/${cellIdx}`}
className={className}
help={cell?.help}
columnStyleOptions={textCellSettings}
>
{lang(cell.text)}
</CellWithText>
);
}

const node = cell && 'node' in cell && cell?.node;
const componentId = node && node.item.id;
if ('labelFrom' in cell && cell.labelFrom) {
const closestComponent = node
.flat(true)
.find((n) => n.item.id === cell.labelFrom || n.item.baseComponentId === cell.labelFrom);
return (
<CellWithLabel
key={`${cell.labelFrom}/${cellIdx}`}
className={className}
columnStyleOptions={textCellSettings}
referenceComponent={closestComponent}
/>
);
}
}
const componentNode = cell && 'node' in cell && cell?.node;
const componentId = componentNode && componentNode.item.id;
return (
<CellWithComponent
key={`${componentId}/${cellIdx}`}
node={node}
node={componentNode}
className={className}
columnStyleOptions={mutableColumnSettings[cellIdx]}
/>
Expand Down Expand Up @@ -137,6 +159,14 @@ interface CellWithComponentProps extends CellProps {
node?: LayoutNode;
}

interface CellWithTextProps extends PropsWithChildren, CellProps {
help?: string;
}

interface CellWithLabelProps extends CellProps {
referenceComponent?: LayoutNode;
}

function CellWithComponent({ node, className, columnStyleOptions }: CellWithComponentProps) {
if (node && !node.isHidden()) {
const columnStyles = columnStyleOptions && getColumnStyles(columnStyleOptions);
Expand All @@ -160,25 +190,64 @@ function CellWithComponent({ node, className, columnStyleOptions }: CellWithComp
return <TableCell className={className} />;
}

type CellWithTextProps = CellProps & PropsWithChildren;

function CellWithText({ children, className, columnStyleOptions }: CellWithTextProps) {
function CellWithText({ children, className, columnStyleOptions, help }: CellWithTextProps) {
const columnStyles = columnStyleOptions && getColumnStyles(columnStyleOptions);

return (
<TableCell
className={cn(css.tableCellFormatting, className)}
style={columnStyles}
>
<span
className={css.contentFormatting}
style={columnStyles}
>
{children}
<span className={help && css.textCell}>
<span
className={css.contentFormatting}
style={columnStyles}
>
{children}
</span>
{help && (
<HelpTextContainer
title={getPlainTextFromNode(children)}
helpText={help}
/>
)}
</span>
</TableCell>
);
}

function CellWithLabel({ className, columnStyleOptions, referenceComponent }: CellWithLabelProps) {
const columnStyles = columnStyleOptions && getColumnStyles(columnStyleOptions);
const { title, help, description } = referenceComponent?.item.textResourceBindings || {};
const { required } = referenceComponent?.item || {};
const componentId = referenceComponent?.item.id ?? referenceComponent?.item.baseComponentId;

return (
<TableCell
className={cn(css.tableCellFormatting, className)}
style={columnStyles}
>
{componentId && (
<>
<span className={css.textLabel}>
<Label
key={`label-${componentId}`}
labelText={title}
id={componentId}
required={required}
helpText={help}
/>
</span>
<Description
id={componentId}
description={description}
/>
</>
)}
</TableCell>
);
}

function MobileGrid({ node }: PropsFromGenericComponent<'Grid'>) {
return (
<Grid
Expand Down
1 change: 1 addition & 0 deletions src/layout/Grid/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type GridComponentType = GridComponentRef | GridComponent;

export interface GridText {
text: string;
help?: string;
alignText?: 'left' | 'center' | 'right';
textOverflow?: {
lineWrap?: boolean;
Expand Down
1 change: 1 addition & 0 deletions src/layout/Group/RepeatingGroupTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export function RepeatingGroupTable({
row={{ ...row, cells: [...row.cells, ...extraCells] }}
isNested={isNested}
mutableColumnSettings={columnSettings}
node={node}
/>
))}
</>
Expand Down
29 changes: 29 additions & 0 deletions test/e2e/integration/app-frontend/grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,33 @@ describe('Grid component', () => {
.find('table tr:last-child td:first-child')
.should('contain.text', 'Foreldreraden er prefill: true');
});

it("should allow adding help text to Grid's text cells or referencing a component", () => {
cy.interceptLayout('changename', (component) => {
if (component.type === 'Grid') {
if (component.rows[1].cells[0]) {
component.rows[1].cells[0].help = 'Help text';
}
if (component.rows[2].cells[0]) {
delete component.rows[2].cells[0].text;
component.rows[2].cells[0].labelFrom = 'fordeling-studie';
}
}
if (component.type === 'Input' && component.id === 'fordeling-studie') {
component.textResourceBindings.description = 'Dette er en beskrivende tekst';
component.textResourceBindings.help = 'Dette er en hjelpetekst';
}
});

cy.goto('changename');
cy.navPage('grid').click();

cy.get(appFrontend.grid.grid).find('tr:eq(1) td:eq(0)').find(appFrontend.helpText.open).click();
cy.get(appFrontend.helpText.alert).should('contain.text', 'Help text');

cy.get(appFrontend.grid.grid).find('tr:eq(2) td:eq(0)').should('contain.text', 'Dette er en beskrivende tekst');
cy.get(appFrontend.grid.grid).find('tr:eq(2) td:eq(0)').find(appFrontend.helpText.open).click();
cy.get(appFrontend.grid.grid).find('tr:eq(2) td:eq(0) label').click();
cy.focused().should('have.attr', 'id', 'fordeling-studie');
});
});