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: StudioCodeListEditor - display Numberfield or Checkbox based on value type #14398

Open
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

ErlingHauan
Copy link
Contributor

@ErlingHauan ErlingHauan commented Jan 10, 2025

Description

  • Renders textfield, numberfield or checkbox depending on if the codelist item's value is a string, number or boolean.
  • Adapted addEmptyCodeListItem to return '', 0 or false, depending on the previous item's type.

bilde


bilde

Not in scope for this PR:

  • Choosing type when creating a new codelist.
  • Dropdown for switching types when editing an existing codelist.
  • Replacing checkboxes with a switch/tab.

Related Issue(s)

Verification

  • Your code builds clean without any errors or warnings
  • Manual testing done (required)
  • Relevant automated test added (if you find this hard, leave it and we'll help out)

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Enhanced code list editor to support multiple data types (string, number, boolean)
    • Improved input handling for different value types in code list items
  • Tests

    • Added comprehensive test cases for type-specific input handling
    • Expanded test coverage for the addNewCodeListItem function
  • Refactor

    • Updated input cell components to dynamically render based on value type
    • Improved type safety for code list item management
    • Enhanced logic for adding new code list items based on existing values

@github-actions github-actions bot added solution/studio/designer Issues related to the Altinn Studio Designer solution. frontend labels Jan 10, 2025
Copy link

codecov bot commented Jan 10, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 95.70%. Comparing base (f9ab025) to head (6c4ad49).
Report is 6 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #14398   +/-   ##
=======================================
  Coverage   95.69%   95.70%           
=======================================
  Files        1888     1890    +2     
  Lines       24558    24590   +32     
  Branches     2818     2822    +4     
=======================================
+ Hits        23500    23533   +33     
  Misses        799      799           
+ Partials      259      258    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

coderabbitai bot commented Jan 17, 2025

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditor.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-storybook".

(The package "eslint-plugin-storybook" was not found when loaded as a Node module from the directory "/frontend/libs/studio-components".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-storybook@latest --save-dev

The plugin "eslint-plugin-storybook" was referenced from the config file in "frontend/libs/studio-components/.eslintrc.js".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

📝 Walkthrough

Walkthrough

This pull request enhances the StudioCodeListEditor component by introducing comprehensive type handling for code list items. The changes span multiple files, focusing on supporting different data types (string, number, boolean) in the editor. Modifications include adding test cases for type handling, refactoring input cell components to dynamically render based on value types, and improving utility functions to handle empty items appropriately. The goal is to create a more flexible and type-safe code list editing experience.

Changes

File Change Summary
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditor.test.tsx Added new test cases for type handling, verifying rendering and saving of different data types.
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx Introduced TypedInputCell, NumberfieldCell, and CheckboxCell to support dynamic input types; updated handleValueChange to accept CodeListItemValue.
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/utils.ts Updated changeValue function to accept CodeListItemValue.
frontend/libs/studio-components/src/components/StudioCodelistEditor/test-data/codeListWithBooleanValues.ts Added test data for boolean values with CodeListItem instances.
frontend/libs/studio-components/src/components/StudioCodelistEditor/test-data/codeListWithNumberValues.ts Added test data for numerical values with CodeListItem instances.
frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.test.ts Enhanced test cases for addNewCodeListItem function to handle different last item types.
frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.ts Added constants for empty items and helper functions for determining appropriate empty items based on type.
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditor.tsx Renamed addEmptyCodeListItem to addNewCodeListItem in the component.
frontend/libs/studio-components/src/components/StudioCodelistEditor/types/TypeofResult.ts Introduced new type alias TypeofResult for structured type representation.

Possibly related PRs

Suggested labels

quality/testing, added-to-sprint, skip-documentation

Suggested reviewers

  • TomasEng
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 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.

@ErlingHauan ErlingHauan changed the title Add numberfield to code list editor Add type selector to code list editor Jan 20, 2025
@ErlingHauan ErlingHauan changed the title Add type selector to code list editor feat: StudioCodeListEditor - display Numberfield or Checkbox based on value type Jan 20, 2025
@ErlingHauan ErlingHauan marked this pull request as ready for review January 22, 2025 12:08
Copy link
Contributor

@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: 0

🧹 Nitpick comments (6)
frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.ts (1)

38-41: Consider adding explicit array bounds check.

The function assumes the array has elements when accessing the last item. While the current implementation is protected by the check in getEmptyItem, it would be more robust to add an explicit check here.

 function getTypeOfLastValue(codeList: CodeList) {
+  if (codeList.length === 0) return 'string';
   const lastCodeListItem = codeList[codeList.length - 1];
   return typeof lastCodeListItem.value as 'string' | 'number' | 'boolean';
 }
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (3)

128-129: Consider explicit undefined handling for numberfield.

The comment about empty numberfield producing undefined is implementation-specific. Consider making this behavior more explicit:

-const shouldRenderNumberfield = typeof value === 'number' || value === undefined; // Empty numberfield produces undefined
+const shouldRenderNumberfield = typeof value === 'number' || value === undefined;
+const isEmptyNumberfield = value === undefined;

166-189: Consider adding number validation constraints.

The NumberfieldCell could benefit from input validation to ensure data integrity:

 const NumberfieldCell = forwardRef<HTMLInputElement, InputCellProps>(
   ({ label, value, onChange, onFocus, autoComplete }, ref) => {
     const handleNumberChange = useCallback(
       (numberValue: number): void => {
+        // Add validation if needed
+        if (isNaN(numberValue)) return;
         onChange(numberValue);
       },
       [onChange],
     );

     return (
       <StudioInputTable.Cell.Numberfield
         ref={ref}
         aria-label={label}
         autoComplete={autoComplete}
         className={classes.textfieldCell}
+        min={0} // Add if applicable
+        max={100} // Add if applicable
         onChange={handleNumberChange}
         onFocus={onFocus}
         value={value as number}
       />
     );
   },
 );

191-215: Optimize checkbox value handling.

The CheckboxCell duplicates the string value. Consider simplifying:

 const CheckboxCell = forwardRef<HTMLInputElement, InputCellProps>(
   ({ label, value, onChange, onFocus }, ref) => {
     const handleBooleanChange = useCallback(
       (event: React.ChangeEvent<HTMLInputElement>): void => {
         onChange(event.target.checked);
       },
       [onChange],
     );

+    const stringValue = String(value);
     return (
       <StudioInputTable.Cell.Checkbox
         ref={ref}
         aria-label={label}
         onChange={handleBooleanChange}
         onFocus={onFocus}
         checked={value as boolean}
-        value={String(value)}
+        value={stringValue}
       >
-        {String(value)}
+        {stringValue}
       </StudioInputTable.Cell.Checkbox>
     );
   },
 );
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditor.test.tsx (1)

484-546: Consider adding edge case tests.

The type handling tests are comprehensive but could benefit from additional edge cases:

  • Test handling of invalid number inputs
  • Test handling of empty/null values
  • Test handling of type conversion edge cases (e.g., "true"/"false" strings vs booleans)

Example test case:

it('Handles invalid number input gracefully', async () => {
  const user = userEvent.setup();
  renderCodeListEditor({ codeList: codeListWithNumberValues });

  const valueInput = screen.getByRole('textbox', { name: texts.itemValue(1) });
  await user.type(valueInput, 'not-a-number');
  await user.tab();

  expect(onBlurAny).not.toHaveBeenCalled();
});
frontend/libs/studio-components/src/components/StudioCodelistEditor/test-data/codeListWithNumberValues.ts (1)

4-23: Enhance test data coverage with diverse scenarios.

While the current test items are well-structured, consider adding more diverse test cases to cover:

  • Edge cases (e.g., very large numbers, decimals, negative values)
  • More meaningful labels/descriptions that reflect the specific test scenarios
  • Comments explaining what each test case validates

Example enhancement:

 const item1: CodeListItem = {
-  description: 'Test 1 description',
-  helpText: 'Test 1 help text',
-  label: 'Test 1',
-  value: 1,
+  description: 'Basic positive integer',
+  helpText: 'Tests handling of simple positive numbers',
+  label: 'Positive Integer',
+  value: 42,
 };

 const item2: CodeListItem = {
-  description: 'Test 2 description',
-  helpText: 'Test 2 help text',
-  label: 'Test 2',
-  value: 2,
+  description: 'Decimal number',
+  helpText: 'Tests handling of decimal numbers',
+  label: 'Decimal',
+  value: 3.14,
 };

 const item3: CodeListItem = {
-  description: 'Test 3 description',
-  helpText: 'Test 3 help text',
-  label: 'Test 3',
-  value: 3,
+  description: 'Negative number',
+  helpText: 'Tests handling of negative numbers',
+  label: 'Negative',
+  value: -1,
 };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 941cd60 and 3f0cdc3.

📒 Files selected for processing (7)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditor.test.tsx (2 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (5 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/utils.ts (2 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/test-data/codeListWithBooleanValues.ts (1 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/test-data/codeListWithNumberValues.ts (1 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.test.ts (2 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Testing
  • GitHub Check: Build environment and run e2e test
🔇 Additional comments (8)
frontend/libs/studio-components/src/components/StudioCodelistEditor/test-data/codeListWithBooleanValues.ts (1)

4-16: LGTM! Well-structured test data.

The test data provides good coverage with both true and false boolean values, and includes all necessary fields (description, helpText, label, value) for comprehensive testing.

frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/utils.ts (1)

12-14: LGTM! Good type safety improvement.

The change from string to CodeListItemValue type enhances type safety while maintaining immutability. This aligns well with the PR's objective to support multiple value types.

frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.ts (1)

5-18: LGTM! Well-structured empty item templates.

The empty item templates are well-defined with appropriate default values for each type.

frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.test.ts (1)

30-60: LGTM! Excellent test coverage.

The test cases thoroughly cover all scenarios:

  • Empty code list handling
  • Type-specific empty item addition for string, number, and boolean
  • Mixed type sequences
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (2)

Line range hint 52-56: LGTM! Type-safe value handling implemented.

The function now correctly handles multiple value types (string, number, boolean) in a type-safe manner.


257-257: LGTM! Consistent use of TypedInputCell.

The TextResourceIdCell correctly uses the new TypedInputCell component, maintaining consistency across the codebase.

frontend/libs/studio-components/src/components/StudioCodelistEditor/test-data/codeListWithNumberValues.ts (2)

1-2: LGTM! Clean type imports.

The imports follow TypeScript best practices by using the 'type' keyword for better tree-shaking.


25-25: Verify CodeList type compatibility with number values.

The export is properly typed, but let's verify that the CodeList type definition supports number values for the value property.

✅ Verification successful

Number values are fully supported by CodeList type

The type system explicitly supports number values through CodeListItemValue = string | boolean | number union type. The implementation is type-safe.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check CodeList and CodeListItem type definitions for number value support

# Search for CodeList type definition
echo "Searching for CodeList type definition..."
ast-grep --pattern 'type CodeList = $_'

# Search for CodeListItem type definition
echo "Searching for CodeListItem type definition..."
ast-grep --pattern 'type CodeListItem = {
  $$$
  value: $_
  $$$
}'

Length of output: 3187


Script:

#!/bin/bash
# Search for CodeListItem definition with a simpler pattern
echo "Searching for CodeListItem definition..."
rg -A 10 "type CodeListItem" || rg -A 10 "interface CodeListItem"

# Also check the file where we found CodeList type
echo "Checking CodeList.ts file content..."
cat frontend/libs/studio-components/src/components/StudioCodelistEditor/types/CodeList.ts

Length of output: 1240

Copy link
Contributor

@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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3f0cdc3 and 4f1c8ba.

📒 Files selected for processing (3)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditor.test.tsx (2 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (5 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/test-data/codeListWithNumberValues.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/test-data/codeListWithNumberValues.ts
🧰 Additional context used
🪛 Biome (1.9.4)
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx

[error] 170-170: isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead.

See the MDN documentation for more details.
Unsafe fix: Use Number.isNaN instead.

(lint/suspicious/noGlobalIsNan)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Build environment and run e2e test
  • GitHub Check: Testing
  • GitHub Check: CodeQL
🔇 Additional comments (5)
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (4)

52-52: LGTM! Type-safe value handling.

The parameter type change from string to CodeListItemValue properly supports the new type-specific input handling.


Line range hint 69-76: LGTM! Proper component replacement.

The TypedInputCell is correctly integrated with appropriate props for error handling, accessibility, and value management.


117-163: LGTM! Well-structured type-based rendering.

The component elegantly handles different value types and maintains proper ref forwarding and error reporting.


192-241: LGTM! Well-implemented specialized input cells.

The CheckboxCell and TextfieldCell implementations follow consistent patterns with proper ref handling and type safety.

frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditor.test.tsx (1)

484-568: LGTM! Comprehensive test coverage for type handling.

The test suite thoroughly covers:

  • Rendering of appropriate input fields based on value types
  • Type preservation during value changes
  • Edge cases for number input validation
  • Boolean state toggling

Copy link
Contributor

@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: 0

🧹 Nitpick comments (2)
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (2)

166-190: Improve type safety in NumberfieldCell.

Consider the following improvements:

  1. The undefined check could be more explicit
  2. The type assertion could be replaced with runtime validation

Apply this diff:

-        if (numberValue === undefined) return;
+        if (typeof numberValue !== 'number') return;

-        value={value as number}
+        value={typeof value === 'number' ? value : 0}

Line range hint 1-300: Well-architected implementation with good separation of concerns.

The implementation effectively achieves the PR's objective of supporting different value types in the code list editor. The separation into specialized cell components (Number, Checkbox, Text) with a smart TypedInputCell coordinator follows good React patterns and maintains clean architecture.

A few architectural considerations for future iterations:

  1. Consider adding a type selector for new items
  2. Consider implementing a type switcher for existing items
  3. Consider replacing checkboxes with switches/tabs as mentioned in the PR objectives
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4f1c8ba and 6c4ad49.

📒 Files selected for processing (1)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Build environment and run e2e test
  • GitHub Check: Testing
  • GitHub Check: CodeQL
🔇 Additional comments (4)
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (4)

Line range hint 52-56: LGTM: Type-safe value handling implemented correctly.

The parameter type change from string to CodeListItemValue properly supports the new multi-type value handling capability.


Line range hint 69-76: LGTM: Clean integration of TypedInputCell.

The TypedInputCell is properly integrated with all necessary props, maintaining error handling and accessibility features.


117-163: LGTM: Well-structured type-based rendering logic.

The TypedInputCell component effectively determines and renders the appropriate input type based on the value's type. The implementation is clean and follows React best practices.


258-259: LGTM: Proper fallback handling in TextResourceIdCell.

The TypedInputCell integration handles the non-text-resource case appropriately with proper empty string fallback.

@ErlingHauan ErlingHauan added team/studio-domain1 area/ui-editor Area: Related to the designer tool for assembling app UI in Altinn Studio. area/content-library Area: Related to library for shared resources labels Jan 22, 2025
@standeren standeren self-assigned this Jan 23, 2025
Copy link
Contributor

@standeren standeren left a comment

Choose a reason for hiding this comment

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

Great work!
So clean PR, easy to spot the small "issues" 😉

Comment on lines +547 to +566
it('Numberfield does not change codelist when given string value', async () => {
const user = userEvent.setup();
renderCodeListEditor({ codeList: codeListWithNumberValues });

const valueInput = screen.getByRole('textbox', { name: texts.itemValue(1) });
await user.type(valueInput, 'not-a-number');
await user.tab();

expect(onBlurAny).toHaveBeenCalledWith([...codeListWithNumberValues]);
});

it('Numberfield does not change codelist when given empty input', async () => {
const user = userEvent.setup();
renderCodeListEditor({ codeList: codeListWithNumberValues });

const valueInput = screen.getByRole('textbox', { name: texts.itemValue(1) });
await user.clear(valueInput);
await user.tab();

expect(onBlurAny).toHaveBeenCalledWith([...codeListWithNumberValues]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should the onBlur be called at all in these cases? 🤔 Should not the isCodeListValid function catch tese issues?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like the validation only checks if there are duplicate items:
bilde

Copy link
Contributor

@standeren standeren Jan 27, 2025

Choose a reason for hiding this comment

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

Yes, agree, but I meant that we should adapt the validator, so it actually does the necessary checks so we wont need to call onBlur if there is no changes 🙈

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I will take a look into it!

const NumberfieldCell = forwardRef<HTMLInputElement, InputCellProps>(
({ label, value, onChange, onFocus, autoComplete }, ref) => {
const handleNumberChange = useCallback(
(numberValue: number): void => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
(numberValue: number): void => {
(numberValue: number | undefined): void => {

({ label, value, onChange, onFocus, autoComplete }, ref) => {
const handleNumberChange = useCallback(
(numberValue: number): void => {
if (numberValue === undefined) return;
Copy link
Contributor

Choose a reason for hiding this comment

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

When will this case happen, and why is the check not present in the others? Should we consider using the same pattern as in the StudioCodeListEditor root - isFieldValid(numberValue) && onChange(numberValue)?

checked={value as boolean}
value={String(value)}
>
{String(value)}
Copy link
Contributor

Choose a reason for hiding this comment

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

If we are displaying this value in the value-column, maybe it should be translated? 🙈

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you suggest using sann and usann instead?
I think most people are more familiar with true and false, and maybe they can be considered valid borrow words, at least in the context of computers 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

We are translating these in the expression-tool at least. So using the same translation would provide consistency 🤷
I think expressions uses sann and usann.

@@ -159,7 +255,7 @@ function TextResourceIdCell(props: TextResourceIdCellProps): ReactElement {
if (textResources) {
return <TextResourceSelectorCell {...props} textResources={textResources} />;
} else {
return <TextfieldCell label={label} onChange={onChangeCurrentId} value={currentId || ''} />;
return <TypedInputCell label={label} onChange={onChangeCurrentId} value={currentId || ''} />;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it correct that the value should default to an empty string if no currentId exists? Maybe not a part of the scope of this PR tho, since creating initial typed entries in the codeList is not in the scope 🙈

expect(updatedCodeList).toEqual([...codeList, emptyNumberItem]);
});

it("Adds an empty boolean item when the last item's value is a boolean", () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since there can only be two entries in a codeList when the values are boolean, this behaviour might not be relevant? 🤔 Maybe the Add item button should be disabled in this case 🤷

Not actually sure if it is a correct assumption that the boolean entries can not interact with other typed entries in a code list tho

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see your point about disabling the add button. Ideally a boolean code list should only have values true and false. But there are users who use a code list with a single true value, see example here. So maybe we should keep it flexible in case they want to add false later? 🤔

Regarding the test having a different value than boolean - I did write the test case with single initial value true at first, but i felt that did not really test how the function itself actually works (checking the last type of the list and adding a new item with the same type), therefore the number item was added to contrast with the boolean item 🙂

In theory it is also possible that people might upload a code list with mixed types, and then this case might come into action.

Copy link
Contributor

Choose a reason for hiding this comment

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

I just wonder if it is advantageous for Studio to provide full flexibility if it does not make sense to have different typed entries in the same list 🤔 But as mentioned, I am not sure what the real use cases are here.

But I guess it is okay keeping it like implemented to start with.

@standeren standeren assigned ErlingHauan and unassigned standeren Jan 23, 2025
Copy link
Contributor

@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 (7)
frontend/libs/studio-components/src/components/StudioCodelistEditor/types/TypeofResult.ts (1)

1-9: Consider clarifying null handling.
Because typeof null === 'object', code that relies on 'object' might inadvertently include null. If null values need distinct handling, consider adding a check or documenting the behavior.

frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditor.tsx (1)

113-113: Validate consistency with onAddOrDeleteItem usage.
In handleAddButtonClick, the code calls onAddOrDeleteItem without validating the updated code list (e.g., isCodeListValid). Other callbacks validate before calling onAddOrDeleteItem. For consistency, consider applying the same pattern here.

  const handleAddButtonClick = useCallback(() => {
    const updatedCodeList = addNewCodeListItem(codeList);
-   onChange(updatedCodeList);
-   onAddOrDeleteItem?.(updatedCodeList);
+   if (isCodeListValid(updatedCodeList)) {
+     onChange(updatedCodeList);
+     onAddOrDeleteItem?.(updatedCodeList);
+   } else {
+     onInvalid?.();
+   }
  }, [codeList, onChange, onAddOrDeleteItem, onInvalid]);
frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.ts (2)

6-19: Add optional default fields to empty items.
Each emptyXItem only sets value and label. If your business flow requires description or other fields, consider assigning them default values to ensure consistent shape.

 export const emptyStringItem: CodeListItem = {
   value: '',
   label: '',
+  description: '',
 };

 export const emptyNumberItem: CodeListItem = {
   value: 0,
   label: '',
+  description: '',
 };

 export const emptyBooleanItem: CodeListItem = {
   value: false,
   label: '',
+  description: '',
 };

21-24: Track item creation with additional logic or telemetry.
addNewCodeListItem straightforwardly adds a new item but lacks error handling or logging. If you anticipate usage analytics or debug logs, consider hooking into this function.

frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.test.ts (2)

3-7: Keep describe blocks in sync with function renames.
describe('addEmptyCodeListItem', ...) no longer matches the new function name. Renaming this test suite to 'addNewCodeListItem' promotes clarity.

-describe('addEmptyCodeListItem', () => {
+describe('addNewCodeListItem', () => {

65-65: Ensure valid code list check.
While verifying a “new instance” is returned is good, also confirm the overall code list remains valid after the item is added.

 it('Returns a new instance', () => {
   const codeList = createTestCodeList();
   const updatedCodeList = addNewCodeListItem(codeList);
   expect(updatedCodeList).not.toBe(codeList);
+  // Optionally check validity
+  // expect(isCodeListValid(updatedCodeList)).toBe(true);
 });
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (1)

208-208: Consider translating boolean values.

The raw boolean values might not be user-friendly. Consider using translated labels for better UX.

-        {String(value)}
+        {value ? texts.true : texts.false}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6c4ad49 and 267d8de.

📒 Files selected for processing (5)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditor.tsx (2 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (5 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/types/TypeofResult.ts (1 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.test.ts (2 hunks)
  • frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.ts (1 hunks)
🔇 Additional comments (7)
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditor.tsx (1)

9-9: Confirm renamed import usage.
Renaming from addEmptyCodeListItem to addNewCodeListItem aligns better with the function’s purpose. Ensure all references in the codebase reflect this change, including previously generated docs or code comments referencing addEmptyCodeListItem.

frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.ts (2)

26-37: Handle fallback for advanced types.
Suppose a code list item is 'bigint', 'undefined', 'function', etc. Then getNewEmptyItem falls back to emptyStringItem. If this is intentional, confirm with stakeholders or add a comment explaining the fallback.


39-41: Confirm behavior for null values.
getTypeOfLastValue returns 'object' for null. Confirm whether that scenario should be treated differently (for instance as a separate fallback, or gracefully converting it to 'string').

frontend/libs/studio-components/src/components/StudioCodelistEditor/utils.test.ts (1)

30-34: Excellent coverage of type-based additions.
The new tests confirm correct behavior for empty lists, string, number, and boolean last-item types. This is thorough and helps maintain confidence in expansions to item types in the future.

Also applies to: 36-43, 45-52, 54-60

frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (3)

Line range hint 52-56: LGTM! Type-safe value handling implementation.

The changes correctly implement type-safe value handling by updating the callback signature and using the new TypedInputCell component.

Also applies to: 69-76


108-115: Well-structured type-based input handling!

The implementation effectively:

  • Defines clear prop types with proper typing
  • Uses a switch statement for clean type-based rendering
  • Handles input validation through the browser's constraint validation API

Also applies to: 117-161


256-256: Verify type consistency for text resource IDs.

While the current implementation works, ensure that text resource IDs are always strings to maintain type consistency across the application.

✅ Verification successful

Type consistency for text resource IDs is properly maintained

The codebase consistently handles text resource IDs as strings throughout all components and interfaces. The empty string fallback in TypedInputCell is a standard TypeScript pattern for maintaining type safety.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for text resource ID usage to verify type consistency
ast-grep --pattern 'currentId: $_'

Length of output: 36


Script:

#!/bin/bash
# Search for currentId usage patterns
rg "currentId" -A 2 -B 2

# Search for TypedInputCell component definition and usage
ast-grep --pattern 'interface TypedInputCellProps {
  $$$
}'

# Search for value prop type in TypedInputCell
ast-grep --pattern 'value: $_'

Length of output: 39912

Comment on lines +167 to +170
(numberValue: number): void => {
if (numberValue === undefined) return;
onChange(numberValue);
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve number validation consistency.

The undefined check is inconsistent with other input types and might miss invalid cases. Consider using the same validation pattern as suggested in past reviews.

-      (numberValue: number): void => {
-        if (numberValue === undefined) return;
+      (numberValue: number | undefined): void => {
+        if (!Number.isFinite(numberValue)) return;
         onChange(numberValue);
📝 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
(numberValue: number): void => {
if (numberValue === undefined) return;
onChange(numberValue);
},
(numberValue: number | undefined): void => {
if (!Number.isFinite(numberValue)) return;
onChange(numberValue);
},

Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be named TypeOfResult? With upper case O.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/content-library Area: Related to library for shared resources area/ui-editor Area: Related to the designer tool for assembling app UI in Altinn Studio. frontend solution/studio/designer Issues related to the Altinn Studio Designer solution. team/studio-domain1
Projects
Status: 🔎 Review
Development

Successfully merging this pull request may close these issues.

3 participants