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

fix: 14718 add confirm when deleting row in codelist #14726

Closed
wants to merge 1 commit into from

Conversation

wrt95
Copy link
Contributor

@wrt95 wrt95 commented Feb 19, 2025

Description

  • Adding confirm for when deleting a row in a codelist
Skjermopptak.2025-02-19.kl.14.50.56.mov

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

  • New Features
    • Introduced comprehensive organization-level management, enabling users to create, update, delete, and upload code lists, and to manage localized text resources.
    • Enhanced dashboard navigation with a dedicated organization library view and dynamic routing that reflects organizational context.
  • UI Enhancements
    • Updated interface elements with clearer confirmation messages and localized prompts to improve user interaction.
  • Testing Improvements
    • Expanded end-to-end and unit test coverage to ensure reliable performance of organization-specific features.

Copy link
Contributor

coderabbitai bot commented Feb 19, 2025

📝 Walkthrough

Walkthrough

This PR introduces new backend controllers and services for managing organization-level code lists and text resources, including full CRUD operations and file upload support. Repository factories and Git repository methods are updated to support dynamic options folder paths. New interfaces and service registrations are provided for organization-specific functionalities. On the frontend, routing and dashboard components are restructured to handle dynamic subroutes, and new tests have been added across UI components, libraries, API mutations, and Playwright end-to-end tests. Enhancements in utility functions and type definitions further streamline code list and text resource management across the application.

Changes

File(s) Change Summary
backend/src/Designer/Controllers/Organisation/OrgCodeListController.cs,
backend/src/Designer/Controllers/Organisation/OrgTextController.cs,
backend/src/Designer/Controllers/Preview/InstancesController.cs,
backend/src/Designer/Controllers/Preview/V3/OldInstancesController.cs,
backend/src/Designer/Controllers/PreviewController.cs
Introduced new controllers for managing organization-level code lists and text resources; added constant OptionsFolderPath and updated method signatures to include folder path.
backend/src/Designer/Factories/AltinnGitRepositoryFactory.cs,
backend/src/Designer/Infrastructure/GitRepository/AltinnAppGitRepository.cs,
backend/src/Designer/Infrastructure/GitRepository/AltinnOrgGitRepository.cs
Added new method to obtain an organization-specific Git repository; updated repository constructors and method signatures to accept dynamic options folder paths.
backend/src/Designer/Infrastructure/ServiceRegistration.cs,
backend/src/Designer/Services/Implementation/Organisation/OrgCodeListService.cs,
backend/src/Designer/Services/Implementation/Organisation/OrgTextsService.cs,
backend/src/Designer/Services/Interfaces/Organisation/IOrgCodeListService.cs,
backend/src/Designer/Services/Interfaces/Organisation/IOrgTextsService.cs
Registered and implemented new services and interfaces for organization code list and text resource management with comprehensive CRUD operations and error handling.
frontend/dashboard/app/App.tsx, frontend/dashboard/app/App.test.tsx,
frontend/dashboard/context/HeaderContext/*,
frontend/dashboard/hooks/*,
frontend/dashboard/pages/*
Restructured dashboard and routing components to use dynamic subroutes; updated navigation logic and tests for improved rendering and user interactions.
frontend/libs/studio-components/*,
frontend/libs/studio-content-library/*,
frontend/libs/studio-pure-functions/*
Enhanced UI components with delete confirmation dialogs and updated text prompts; introduced new utility methods such as FileUtils.convertToFormData and StringUtils.removeLeadingSlash along with corresponding tests.
frontend/packages/shared/src/api/*,
frontend/packages/shared/src/constants.js,
frontend/packages/shared/src/types/*,
frontend/packages/shared/src/hooks/mutations/*
Added new API endpoints, mutations, and type definitions to support organization-specific code lists and text resources; updated query keys and constants accordingly.
frontend/testing/playwright/* Added new Playwright test files and configuration for organization library pages; updated routes and navigation tests to reflect the new URL schema for OrgLibrary.

Possibly related PRs

Suggested labels

solution/studio/designer, quality/testing, skip-releasenotes, area/content-library, frontend, team/studio-domain1, skip-manual-testing

Suggested reviewers

  • ErlingHauan
  • Konrad-Simso

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.test.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.

frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.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.

frontend/libs/studio-components/src/components/StudioCodelistEditor/types/CodeListEditorTexts.ts

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.

  • 1 others
✨ 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.

@github-actions github-actions bot added area/ui-editor Area: Related to the designer tool for assembling app UI in Altinn Studio. area/text-editor Area: Related to creating, translating and editing texts. area/dashboard Area: Related to the dashboard application area/app-preview Area: Related to test and preview of apps that are developed in Altinn Studio. solution/studio/designer Issues related to the Altinn Studio Designer solution. quality/testing Tests that are missing, needs to be created or could be improved. backend frontend labels Feb 19, 2025
@wrt95 wrt95 marked this pull request as draft February 19, 2025 13:52
@wrt95 wrt95 changed the base branch from main to org-library-mvp February 19, 2025 13:57
@TomasEng
Copy link
Contributor

Jeg vet ikke om vi burde legge til bekreftelsesbokser på dette nivået. Det kan bli irriterende for brukerne hvis de vil slette mange koder på én gang. Kanskje vi bør vente på tilbakemeldinger fra brukerne før vi innfører dette?

Copy link

codecov bot commented Feb 19, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 95.79%. Comparing base (d5ea724) to head (48c3e81).

Additional details and impacted files
@@               Coverage Diff                @@
##           org-library-mvp   #14726   +/-   ##
================================================
  Coverage            95.78%   95.79%           
================================================
  Files                 1931     1931           
  Lines                25150    25157    +7     
  Branches              2857     2858    +1     
================================================
+ Hits                 24091    24098    +7     
  Misses                 799      799           
  Partials               260      260           

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

@wrt95 wrt95 closed this Feb 19, 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.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

Actionable comments posted: 11

🔭 Outside diff range comments (1)
frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage/CodeListPage.tsx (1)

32-32: ⚠️ Potential issue

Implement confirmation dialog for delete action.

The PR objectives mention adding a confirmation prompt when deleting a row, but the implementation is missing. Consider wrapping the onDeleteCodeList callback with a confirmation dialog.

Here's a suggested implementation:

- onDeleteCodeList: (codeListId: string) => void;
+ onDeleteCodeList: (codeListId: string) => {
+   if (window.confirm('Are you sure you want to delete this code list?')) {
+     // Call the actual delete function
+   }
+ };
🧹 Nitpick comments (44)
frontend/testing/playwright/pages/OrgLibraryPage/CodeLists.ts (1)

4-26: Add test coverage for delete row confirmation dialog.

The PR's main objective is to add a confirmation dialog when deleting a row in the codelist. However, there's no test coverage for this functionality. Please add methods to:

  1. Verify the presence of the confirmation dialog when deleting a row
  2. Test both confirmation and cancellation scenarios

Would you like me to help you implement these test methods? Here's a suggested structure:

public async deleteRow(rowIndex: number): Promise<void> {
  // Click delete button for the specified row
  await this.page.getByRole('button', { name: 'delete' }).nth(rowIndex).click();
  
  // Verify confirmation dialog
  const dialog = this.page.getByRole('dialog');
  await expect(dialog).toBeVisible();
  
  // Verify dialog content
  const confirmText = this.page.getByText(this.textMock('confirm_delete_row'));
  await expect(confirmText).toBeVisible();
}

public async confirmDelete(): Promise<void> {
  await this.page.getByRole('button', { name: this.textMock('confirm') }).click();
  // Add verification that row was deleted
}

public async cancelDelete(): Promise<void> {
  await this.page.getByRole('button', { name: this.textMock('cancel') }).click();
  // Add verification that row still exists
}
frontend/testing/playwright/tests/org-library/org-library.spec.ts (1)

38-47: Add test coverage for row deletion confirmation.

The current test only verifies navigation and empty state. Based on the PR objective to "add confirm when deleting row in codelist", we need additional test coverage for:

  • Creating a row in the codelist
  • Triggering row deletion
  • Verifying the confirmation dialog appears
  • Confirming/canceling the deletion

Would you like me to help generate the additional test cases?

frontend/packages/shared/src/hooks/mutations/useUpdateOrgCodeListMutation.test.ts (1)

29-58: Consider adding test cases for error handling and edge cases.

While the current tests cover the happy path well, consider adding tests for:

  • Error handling when the mutation fails
  • Edge cases with empty or invalid code list data
  • Validation of the title and data fields

Example test cases to add:

it('Handles mutation errors correctly', async () => {
  const error = new Error('Update failed');
  const updateCodeListForOrg = jest.fn(() => Promise.reject(error));
  const { result } = renderHookWithProviders(() => useUpdateOrgCodeListMutation(org), {
    queries: { updateCodeListForOrg },
  });

  await expect(result.current.mutateAsync(updatedCodeList)).rejects.toThrow(error);
});

it('Validates input data', async () => {
  const { result } = renderHookWithProviders(() => useUpdateOrgCodeListMutation(org));
  
  // @ts-expect-error Testing runtime validation
  await expect(result.current.mutateAsync({ title: '', data: [] }))
    .rejects.toThrow();
});
frontend/dashboard/pages/OrgContentLibrary/OrgContentLibrary.tsx (1)

41-48: Consider adding a default case in the switch statement

If codeListResponseStatus ever falls outside 'pending' | 'error' | 'success' (for example, 'idle'), the UI might break. Adding a default case protects against unexpected states and improves resilience.

backend/src/Designer/Services/Implementation/Organisation/OrgCodeListService.cs (3)

37-37: Pass the cancellation token to GetCodeListIds

To maintain consistency, consider updating GetCodeListIds to accept and leverage the existing cancellationToken—especially if fetching code list IDs can be canceled.


39-62: Consider parallelizing code list retrieval for performance

If there are many code lists, the sequential foreach loop could slow things down. Using parallel or batched retrieval (e.g. Task.WhenAll) might improve performance.


74-78: Review returning all code lists on create

Returning the entire set of code lists after creating a new one may be excessive for some use cases. If not strictly needed, returning only the newly created code list could be more efficient.

backend/src/Designer/Infrastructure/GitRepository/AltinnOrgGitRepository.cs (1)

165-172: Potential concurrency concern with file deletion

Concurrent code list edits or deletions might lead to races or file locks. Investigate locking or concurrency strategies if your application allows simultaneous edits.

frontend/dashboard/hooks/useSubRoute/useSubroute.ts (1)

5-8: Add JSDoc documentation for the hook.

Consider adding JSDoc documentation to describe the hook's purpose, parameters, and return value. This would improve maintainability and developer experience.

Example documentation:

+/**
+ * Custom hook to get the current subroute from URL parameters.
+ * Falls back to the default dashboard basename if no subroute is present.
+ * @returns {string} The current subroute
+ */
 export function useSubroute(): string {
   const { subroute = defaultSubroute } = useParams();
   return subroute;
 }
frontend/dashboard/pages/OrgContentLibrary/utils.test.ts (1)

4-17: Consider adding more edge cases to the test suite.

The current test coverage is good, but consider adding tests for edge cases such as:

  • Empty string
  • Undefined/null (with proper TypeScript handling)
  • Special characters or numbers in the context type

Example additional tests:

it('Returns true for empty string', () => {
  expect(isOrg('')).toBe(true);
});

it('Handles special characters correctly', () => {
  expect(isOrg('org@123')).toBe(true);
});
frontend/libs/studio-pure-functions/src/FileUtils/FileUtils.test.ts (1)

13-14: Enhance test reliability by using more appropriate assertions.

The current test uses toBe for object comparison, which might not reliably compare File objects. Consider using more specific assertions to verify the file properties.

-      const retrievedFile = formData.get('file');
-      expect(retrievedFile).toBe(file);
+      const retrievedFile = formData.get('file') as File;
+      expect(retrievedFile.name).toBe(fileName);
+      expect(retrievedFile.type).toBe(fileType);
+      expect(retrievedFile.size).toBe(file.size);
frontend/testing/playwright/components/DashboardHeader.ts (1)

8-10: Remove unnecessary constructor.

The constructor only calls super with the same parameters and can be safely removed.

-  constructor(page: Page, environment?: Environment) {
-    super(page, environment);
-  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 8-10: This constructor is unnecessary.

Unsafe fix: Remove the unnecessary constructor.

(lint/complexity/noUselessConstructor)

frontend/packages/shared/src/hooks/queries/useOrgCodeListsQuery.test.ts (1)

7-12: Add test cases for error and loading states.

The test suite should include additional test cases to verify the behavior of the hook in different states:

  • Loading state
  • Error state
  • Empty response

Example test cases to add:

it('handles loading state correctly', () => {
  const { result } = renderHookWithProviders(() => useOrgCodeListsQuery(org));
  expect(result.current.isLoading).toBe(true);
});

it('handles error state correctly', async () => {
  queriesMock.getCodeListsForOrg.mockRejectedValueOnce(new Error('Test error'));
  const { result } = renderHookWithProviders(() => useOrgCodeListsQuery(org));
  await waitFor(() => expect(result.current.isError).toBe(true));
  expect(result.current.error).toBeDefined();
});

it('handles empty response correctly', async () => {
  queriesMock.getCodeListsForOrg.mockResolvedValueOnce({ codeLists: [] });
  const { result } = renderHookWithProviders(() => useOrgCodeListsQuery(org));
  await waitFor(() => expect(result.current.isSuccess).toBe(true));
  expect(result.current.data?.codeLists).toHaveLength(0);
});
frontend/packages/shared/src/hooks/queries/useTextResourcesForOrgQuery.test.ts (1)

1-23: LGTM! Well-structured test implementation.

The test properly verifies the query behavior with correct parameters and mocks.

Consider adding these test cases to improve coverage:

  1. Test with different language values to ensure proper handling of language parameter
  2. Add error case tests to verify error handling behavior
frontend/packages/shared/src/mocks/codeListsResponse.ts (1)

15-31: Consider adding JSDoc comments for mock data.

The mock data is well-structured and includes various test scenarios. Consider adding JSDoc comments to explain the purpose of each mock code list for better maintainability.

+/** Mock code list with full data including description and help text */
 const codeList1: CodeListData = {
   // ...
 };

+/** Mock code list with minimal data (only label and value) */
 const codeList2: CodeListData = {
   // ...
 };

+/** Mock code list representing an error state */
 const codeListWithError: CodeListData = {
   // ...
 };

Also applies to: 33-40, 42-45

backend/src/Designer/Services/Interfaces/Organisation/IOrgTextsService.cs (1)

31-40: Document precondition for UpdateTextsForKeys method.

Based on retrieved learnings, this method requires the text resource to exist before it can be updated.

 /// <summary>
-/// Updates values for specified keys in the text resouce.
+/// Updates values for specified keys in the text resource.
+/// Precondition: The text resource must exist before calling this method.
 /// </summary>
frontend/packages/shared/src/hooks/mutations/useUploadOrgCodeListMutation.test.ts (1)

31-54: Add error case test scenario.

The tests cover successful scenarios well, but consider adding test cases for error handling:

  • File upload failure
  • Invalid file format
  • Network errors
it('Handles upload failure correctly', async () => {
  const error = new Error('Upload failed');
  const uploadCodeListForOrg = jest.fn(() => Promise.reject(error));
  const { result } = renderHookWithProviders(() => useUploadOrgCodeListMutation(org), {
    queryClient,
    queries: { uploadCodeListForOrg },
  });

  await expect(result.current.mutateAsync(file)).rejects.toThrow(error);
});
frontend/packages/shared/src/mocks/textResourcesMock.ts (1)

3-82: Consider refactoring to reduce code duplication.

The text resources follow a clear pattern and could be generated programmatically to improve maintainability.

Consider this approach:

-export const label1TextResource: ITextResource = {
-  id: 'label1',
-  value: 'Ledetekst 1',
-};
-// ... (similar declarations)

+const createTextResources = (
+  prefix: string,
+  valuePrefix: string,
+  count: number
+): ITextResource[] =>
+  Array.from({ length: count }, (_, i) => ({
+    id: `${prefix}${i + 1}`,
+    value: `${valuePrefix} ${i + 1}`,
+  }));
+
+export const labelTextResources = createTextResources('label', 'Ledetekst', 5);
+export const descriptionTextResources = createTextResources('description', 'Beskrivelse', 5);
+export const helpTextTextResources = createTextResources('helpText', 'Hjelpetekst', 5);
+
+const textResources: ITextResource[] = [
+  ...labelTextResources,
+  ...descriptionTextResources,
+  ...helpTextTextResources,
+];
frontend/dashboard/pages/CreateService/CreateService.tsx (2)

40-42: LGTM! Consider destructuring hook returns.

The routing changes improve maintainability. Consider destructuring the hook returns for better readability.

-const selectedContext = useSelectedContext();
-const subroute = useSubroute();
+const { selectedContext } = useSelectedContext();
+const { subroute } = useSubroute();

91-91: Consider using template literals consistently.

For better readability and consistency with modern JavaScript practices.

-href: `/${subroute}/${selectedContext}`,
+href: `${subroute}/${selectedContext}`,
frontend/libs/studio-pure-functions/src/StringUtils/StringUtils.ts (1)

89-89: Consider simplifying the regex pattern.

The global flag (g) in the regex pattern /^\//g is unnecessary since we're only matching at the start of the string. Consider one of these simpler alternatives:

-  static removeLeadingSlash = (str: string): string => str.replace(/^\//g, '');
+  static removeLeadingSlash = (str: string): string => str.replace(/^\//, '');

Or even more readable:

-  static removeLeadingSlash = (str: string): string => str.replace(/^\//g, '');
+  static removeLeadingSlash = (str: string): string => str.startsWith('/') ? str.slice(1) : str;
frontend/dashboard/hooks/guards/useContextRedirectionGuard.ts (2)

104-107: Consider moving type definition to a separate file.

The DashboardRoute type could be moved to a shared types file since it represents a core routing concept that might be used by other components.


86-86: Consider destructuring location.search for clarity.

The location.search usage could be more explicit by destructuring it from the window.location object:

-): void => navigate(subroute + '/' + selectedContextType + location.search, { replace: true });
+): void => {
+  const { search } = window.location;
+  navigate(`${subroute}/${selectedContextType}${search}`, { replace: true });
+};
backend/src/Designer/Services/Interfaces/Organisation/IOrgCodeListService.cs (2)

60-60: Consider returning void for DeleteCodeList.

The DeleteCodeList method returns List<OptionListData>, but a delete operation typically doesn't need to return the remaining items. Consider changing the return type to Task or Task<bool> to indicate success/failure.


21-24: Update documentation for CreateCodeList and UpdateCodeList.

The XML documentation for both methods is identical, stating "Creates a new code list". Please update the documentation for UpdateCodeList to accurately reflect its purpose of updating an existing code list.

Also applies to: 32-35

backend/src/Designer/Services/Implementation/Organisation/OrgTextsService.cs (2)

66-66: Remove misleading comment.

Based on retrieved learnings, the comment "handle if file not already exist" is incorrect as UpdateTextsForKeys can only be called for text resources that already exist.


77-86: Simplify variable handling logic.

The null check for variables can be simplified using the null-coalescing operator.

-                if (textResourceContainsKey.Variables == null)
-                {
-                    textResourceObject.Resources[indexTextResourceElementUpdateKey] = new TextResourceElement { Id = kvp.Key, Value = kvp.Value };
-                }
-                else
-                {
-                    List<TextResourceVariable> variables = textResourceContainsKey.Variables;
-                    textResourceObject.Resources[indexTextResourceElementUpdateKey] = new TextResourceElement { Id = kvp.Key, Value = kvp.Value, Variables = variables };
-                }
+                textResourceObject.Resources[indexTextResourceElementUpdateKey] = new TextResourceElement 
+                { 
+                    Id = kvp.Key, 
+                    Value = kvp.Value,
+                    Variables = textResourceContainsKey.Variables 
+                };
frontend/dashboard/app/App.test.tsx (3)

28-31: Consider adding cleanup after each test.

While jest.clearAllMocks() is called before each test, it's good practice to also clean up after each test to ensure a clean state.

 beforeEach(() => {
   jest.clearAllMocks();
   typedLocalStorage.setItem('featureFlags', [FeatureFlag.OrgLibrary]);
 });
+afterEach(() => {
+  jest.clearAllMocks();
+  typedLocalStorage.clear();
+});

58-63: Add timeout to waitForElementToBeRemoved.

The waitForElementToBeRemoved function should have a timeout to prevent infinite waiting in case of test failures.

-await waitForElementToBeRemoved(querySpinner());
+await waitForElementToBeRemoved(querySpinner(), { timeout: 5000 });

93-101: Consider adding error handling for render failures.

The renderApp function should handle potential render failures gracefully.

 function renderApp(args: RenderAppArgs = {}): RenderResult {
+  try {
     return render(<App />, {
       wrapper: ({ children }) => (
         <MockServicesContextWrapper {...args}>{children}</MockServicesContextWrapper>
       ),
     });
+  } catch (error) {
+    console.error('Failed to render App:', error);
+    throw error;
+  }
 }
backend/src/Designer/Controllers/Organisation/OrgTextController.cs (2)

17-20: Add API version attribute.

Consider adding API version attribute to support versioning of your API endpoints.

 [ApiController]
 [Authorize]
+[ApiVersion("1.0")]
 [Route("designer/api/{org}/text")]
 public class OrgTextController : ControllerBase

40-56: Add ProducesResponseType attributes.

Document the possible response types for better API documentation and client understanding.

 [HttpGet]
 [Route("language/{languageCode}")]
+[ProducesResponseType(typeof(TextResource), StatusCodes.Status200OK)]
+[ProducesResponseType(StatusCodes.Status404NotFound)]
+[ProducesResponseType(StatusCodes.Status401Unauthorized)]
 public async Task<ActionResult<TextResource>> GetResource(string org, string languageCode, CancellationToken cancellationToken = default)
frontend/dashboard/pages/PageLayout/DashboardHeader/DashboardHeader.tsx (1)

34-39: Consider extracting feature flag check to a hook.

The feature flag check could be extracted to a custom hook for better reusability and testing.

+function useOrgLibraryFeature() {
+  return shouldDisplayFeature(FeatureFlag.OrgLibrary);
+}

 <StudioPageHeader.Center>
-  {shouldDisplayFeature(FeatureFlag.OrgLibrary) &&
+  {useOrgLibraryFeature() &&
     dashboardHeaderMenuItems.map((menuItem: HeaderMenuItem) => (
       <TopNavigationMenuItem key={menuItem.name} menuItem={menuItem} />
     ))}
 </StudioPageHeader.Center>
backend/src/Designer/Infrastructure/ServiceRegistration.cs (1)

39-86: Consider grouping related services.

The service registrations could be organized better by grouping related services together.

 public static IServiceCollection RegisterServiceImplementations(this IServiceCollection services, IConfiguration configuration)
 {
+    // Repository and source control services
     services.AddTransient<IRepository, RepositorySI>();
     services.AddTransient<ISchemaModelService, SchemaModelService>();
     services.AddTransient<IAltinnGitRepositoryFactory, AltinnGitRepositoryFactory>();
     services.AddTransient<ISourceControl, SourceControlSI>();
     services.Decorate<ISourceControl, SourceControlLoggingDecorator>();

+    // Database context
     services.AddSingleton(configuration);
     services.AddDbContext<DesignerdbContext>(options =>
     {
         PostgreSQLSettings postgresSettings = configuration.GetSection(nameof(PostgreSQLSettings)).Get<PostgreSQLSettings>();
         options.UseNpgsql(postgresSettings.FormattedConnectionString());
     });

+    // Repository services
     services.AddScoped<IReleaseRepository, ReleaseRepository>();
     services.AddScoped<IDeploymentRepository, DeploymentRepository>();
     services.AddScoped<IAppScopesRepository, AppScopesRepository>();

+    // User and authentication services
     services.AddScoped<IUserService, UserService>();
     services.AddTransient<IAccessTokenGenerator, AccessTokenGenerator>();
     services.AddTransient<ISigningCredentialsResolver, SigningCredentialsResolver>();

+    // Organization services
     services.AddTransient<IOrgCodeListService, OrgCodeListService>();
     services.AddTransient<IOrgTextsService, OrgTextsService>();
     services.AddHttpClient<IOrgService, OrgService>();

     // ... rest of the registrations
backend/src/Designer/Controllers/Organisation/OrgCodeListController.cs (2)

81-83: Update XML documentation for UpdateCodeList method.

The XML documentation for UpdateCodeList is identical to CreateCodeList. Consider updating it to better reflect the update operation.

Apply this diff to improve the documentation:

-    /// Creates or overwrites an code-list.
+    /// Updates an existing code-list.

111-125: Add file size and type validation in UploadCodeList method.

The method should validate the file size and type before processing to prevent potential issues with large or invalid files.

Apply this diff to add validation:

     public async Task<ActionResult<List<OptionListData>>> UploadCodeList(string org, [FromForm] IFormFile file, CancellationToken cancellationToken)
     {
         cancellationToken.ThrowIfCancellationRequested();
         string developer = AuthenticationHelper.GetDeveloperUserName(HttpContext);
 
+        if (file.Length > 5 * 1024 * 1024) // 5MB limit
+        {
+            return BadRequest("File size exceeds the limit of 5MB");
+        }
+
+        if (!file.ContentType.Equals("application/json", StringComparison.OrdinalIgnoreCase))
+        {
+            return BadRequest("Only JSON files are supported");
+        }
+
         try
         {
backend/src/Designer/Services/Implementation/OptionsService.cs (1)

23-23: Consider moving OptionsFolderPath to configuration.

While using a constant improves maintainability, consider moving it to a configuration file for better flexibility across different environments.

  1. Add to appsettings.json:
{
  "RepositorySettings": {
    "OptionsFolderPath": "App/options/"
  }
}
  1. Inject through configuration:
-    private const string OptionsFolderPath = "App/options/";
+    private readonly string _optionsFolderPath;
+
+    public OptionsService(IAltinnGitRepositoryFactory altinnGitRepositoryFactory, IConfiguration configuration)
+    {
+        _altinnGitRepositoryFactory = altinnGitRepositoryFactory;
+        _optionsFolderPath = configuration.GetValue<string>("RepositorySettings:OptionsFolderPath") ?? "App/options/";
+    }
frontend/libs/studio-components/src/components/StudioCodelistEditor/StudioCodeListEditorRow/StudioCodeListEditorRow.tsx (1)

258-258: Fix typo in variable name.

The variable name delteConfirmationText contains a typo. It should be deleteConfirmationText.

-  const delteConfirmationText: string = texts.deleteItemConfirmation(number);
+  const deleteConfirmationText: string = texts.deleteItemConfirmation(number);
frontend/dashboard/pages/OrgContentLibrary/OrgContentLibrary.test.tsx (2)

19-26: Consider using a test constants file.

These mock values could be moved to a separate test constants file to improve maintainability and reusability across test files.

-const updateCodeListButtonTextMock: string = 'Update Code List';
-const uploadCodeListButtonTextMock: string = 'Upload Code List';
-const deleteCodeListButtonTextMock: string = 'Delete Code List';
-const codeListNameMock: string = 'codeListNameMock';
-const codeListMock: CodeList = [{ value: '', label: '' }];
-const codeListsDataMock: CodeListData[] = [{ title: codeListNameMock, data: codeListMock }];
-const mockOrgPath: string = '/testOrg';
+import { 
+  updateCodeListButtonTextMock,
+  uploadCodeListButtonTextMock,
+  deleteCodeListButtonTextMock,
+  codeListNameMock,
+  codeListMock,
+  codeListsDataMock,
+  mockOrgPath 
+} from '../../testing/constants';

159-175: Enhance error handling test coverage.

The error handling test only covers the generic error case. Consider adding tests for specific error codes and edge cases.

+it('renders error toast when onUploadCodeList is rejected with specific error code', async () => {
+  const user = userEvent.setup();
+  const uploadCodeListForOrg = jest
+    .fn()
+    .mockImplementation(() => Promise.reject({ response: { status: 413, data: 'File too large' } }));
+  renderOrgContentLibraryWithCodeLists({
+    initialEntries: [mockOrgPath],
+    queries: { uploadCodeListForOrg },
+  });
+  await goToLibraryPage(user, 'code_lists');
+  const uploadCodeListButton = screen.getByRole('button', { name: uploadCodeListButtonTextMock });
+  await user.click(uploadCodeListButton);
+  const errorToastMessage = screen.getByText(
+    textMock('dashboard.org_library.code_list_upload_size_error'),
+  );
+  expect(errorToastMessage).toBeInTheDocument();
+});
frontend/dashboard/pages/CreateService/CreateService.test.tsx (1)

12-13: Consider adding more routing test cases.

The test suite could benefit from additional test cases that verify different subroute combinations.

+it('should handle different subroute combinations', async () => {
+  const user = userEvent.setup();
+  const testCases = [
+    { selectedContext: SelectedContextType.Self, subroute: Subroute.AppDashboard },
+    { selectedContext: SelectedContextType.All, subroute: Subroute.ContentLibrary },
+    { selectedContext: 'ttd', subroute: Subroute.ResourceLibrary }
+  ];
+  
+  for (const { selectedContext, subroute } of testCases) {
+    (useParams as jest.Mock).mockReturnValue({ selectedContext, subroute });
+    renderWithMockServices();
+    const cancelLink = screen.getByRole('link', { name: textMock('general.cancel') });
+    expect(cancelLink.getAttribute('href')).toBe(`/${subroute}/${selectedContext}`);
+    cleanup();
+  }
+});

Also applies to: 74-76

frontend/packages/shared/src/api/queries.ts (1)

183-185: Track the TODO implementation for text resources API.

The getTextResourcesForOrg function currently uses a mock. Ensure to implement the real API call as mentioned in the TODO comment.

Would you like me to create an issue to track the implementation of the real API call for getTextResourcesForOrg?

backend/tests/Designer.Tests/Services/TextsServiceTest.cs (1)

167-180: Consider adding test cases for different options paths.

The test suite could benefit from additional test cases that verify the behavior with different options folder paths.

+[Theory]
+[InlineData("App/options")]
+[InlineData("App/custom/options")]
+[InlineData("Organization/options")]
+public async Task UpdateRelatedFiles_Options_ShouldUpdateOptionsListWithDifferentPaths(string optionsPath)
+{
+    (var targetRepository, var altinnGitRepositoryFactory, var textsService) = await SetupRepository();
+
+    List<TextIdMutation> keyMutations = new() { new() { OldId = "label1", NewId = "label1new" } };
+    await textsService.UpdateRelatedFiles(org, targetRepository, developer, keyMutations);
+    AltinnAppGitRepository altinnAppGitRepository = altinnGitRepositoryFactory.GetAltinnAppGitRepository(org, targetRepository, developer);
+    string raw = await altinnAppGitRepository.GetOptionsList("test-options", optionsPath);
+    JsonNode optionsList = JsonNode.Parse(raw);
+
+    Assert.NotNull(optionsList);
+    Assert.Equal("label1new", (optionsList as JsonArray)[0]["label"].ToString());
+    Assert.Equal("label2", (optionsList as JsonArray)[1]["label"].ToString());
+}
frontend/dashboard/app/App.tsx (1)

50-51: Refine error specificity if both queries fail.
Currently, if both user and organizations are in error state, the code only checks userStatus === 'error'. This is a sensible default. However, if a scenario arises where both might fail, consider showing or logging both failures.

Also applies to: 54-55, 57-57, 60-61, 64-64, 66-69, 72-72

🛑 Comments failed to post (11)
frontend/dashboard/pages/OrgContentLibrary/OrgContentLibrary.tsx (1)

74-74: ⚠️ Potential issue

Add a confirmation prompt before deletion

The PR objective (#14718) mentions adding a confirm dialog to prevent accidental code list deletions. Consider wrapping the deleteCodeList call in a confirmation step to align with the PR's scope.

frontend/libs/studio-pure-functions/src/FileUtils/FileUtils.ts (1)

1-7: 🛠️ Refactor suggestion

Refactor class to a simple function.

The class contains only static members, which is a code smell. Consider refactoring it to a simple function for better maintainability and adherence to functional programming principles.

Apply this diff to refactor the class into a function:

-export class FileUtils {
-  static convertToFormData = (file: File): FormData => {
-    const formData = new FormData();
-    formData.append('file', file);
-    return formData;
-  };
-}
+export const convertToFormData = (file: File): FormData => {
+  const formData = new FormData();
+  formData.append('file', file);
+  return formData;
+};
📝 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.

export const convertToFormData = (file: File): FormData => {
  const formData = new FormData();
  formData.append('file', file);
  return formData;
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 1-7: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

frontend/packages/shared/src/hooks/queries/useTextResourcesForOrgQuery.ts (1)

12-12: 🛠️ Refactor suggestion

Include dynamic parameters in the query key.

The query key should include the dynamic parameters (org and language) to ensure proper caching and invalidation.

Apply this diff to update the query key:

-    queryKey: [QueryKey.TextResourcesForOrg],
+    queryKey: [QueryKey.TextResourcesForOrg, org, language],
📝 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.

    queryKey: [QueryKey.TextResourcesForOrg, org, language],
frontend/packages/shared/src/hooks/mutations/useDeleteOrgCodeListMutation.ts (1)

6-18: 🛠️ Refactor suggestion

⚠️ Potential issue

Add confirmation dialog before deletion.

According to the PR objectives, a confirmation dialog should be implemented when deleting a row in the codelist. However, the current implementation directly deletes without confirmation.

Do you want me to generate a solution that implements the confirmation dialog using a modal or dialog component?

Add error handling and loading state.

Consider handling error states and providing loading feedback to improve user experience.

Apply this diff to add error handling:

 return useMutation({
   mutationFn,
   onSuccess: (newData: CodeListsResponse) => {
     queryClient.setQueryData([QueryKey.OrgCodeLists, org], newData);
   },
+  onError: (error) => {
+    console.error('Failed to delete code list:', error);
+    // TODO: Add error notification or toast
+  },
 });
📝 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.

export const useDeleteOrgCodeListMutation = (org: string) => {
  const queryClient = useQueryClient();
  const { deleteCodeListForOrg } = useServicesContext();

  const mutationFn = (title: string) => deleteCodeListForOrg(org, title);

  return useMutation({
    mutationFn,
    onSuccess: (newData: CodeListsResponse) => {
      queryClient.setQueryData([QueryKey.OrgCodeLists, org], newData);
    },
    onError: (error) => {
      console.error('Failed to delete code list:', error);
      // TODO: Add error notification or toast
    },
  });
};
frontend/packages/shared/src/hooks/mutations/useDeleteOrgCodeListMutation.test.ts (1)

42-56: ⚠️ Potential issue

Fix incorrect hook usage in cache update test.

The test case for cache updates incorrectly uses useCreateOrgCodeListMutation instead of useDeleteOrgCodeListMutation. This mismatch could lead to incorrect test coverage.

Apply this diff to fix the test:

-    const createCodeListForOrg = jest.fn(() => Promise.resolve([otherCodeList]));
-    const { result } = renderHookWithProviders(() => useCreateOrgCodeListMutation(org), {
+    const deleteCodeListForOrg = jest.fn(() => Promise.resolve([otherCodeList]));
+    const { result } = renderHookWithProviders(() => useDeleteOrgCodeListMutation(org), {
       queryClient,
-      queries: { createCodeListForOrg },
+      queries: { deleteCodeListForOrg },
     });
📝 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.

  it('Replaces cache with api response', async () => {
    const queryClient = createQueryClientMock();
    queryClient.setQueryData([QueryKey.OrgCodeLists, org], [codeListToDelete, otherCodeList]);
    const deleteCodeListForOrg = jest.fn(() => Promise.resolve([otherCodeList]));
    const { result } = renderHookWithProviders(() => useDeleteOrgCodeListMutation(org), {
      queryClient,
      queries: { deleteCodeListForOrg },
    });

    await result.current.mutateAsync({ title: codeListToDelete.title });

    const expectedUpdatedData: CodeListsResponse = [otherCodeList];
    const updatedData = queryClient.getQueryData([QueryKey.OrgCodeLists, org]);
    expect(updatedData).toEqual(expectedUpdatedData);
  });
backend/src/Designer/Controllers/Organisation/OrgTextController.cs (2)

95-116: ⚠️ Potential issue

Handle NotFoundException consistently.

Based on the retrieved learning about UpdateTextsForKeys requiring existing resources, the NotFoundException should return NotFound instead of BadRequest.

     catch (NotFoundException)
     {
-        return BadRequest($"The text resource, resource.{languageCode}.json, could not be updated.");
+        return NotFound($"The text resource, resource.{languageCode}.json, could not be found.");
     }
📝 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.

    [HttpPut]
    [Route("language/{languageCode}")]
    public async Task<ActionResult<TextResource>> UpdateResource(string org, [FromBody] Dictionary<string, string> keysTexts, string languageCode, CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();
        string developer = AuthenticationHelper.GetDeveloperUserName(HttpContext);

        try
        {
            await _orgTextsService.UpdateTextsForKeys(org, developer, keysTexts, languageCode, cancellationToken);
            TextResource textResource = await _orgTextsService.GetText(org, developer, languageCode, cancellationToken);
            return Ok(textResource);
        }
        catch (ArgumentException exception)
        {
            return BadRequest(exception.Message);
        }
        catch (NotFoundException)
        {
            return NotFound($"The text resource, resource.{languageCode}.json, could not be found.");
        }
    }

66-83: 🛠️ Refactor suggestion

Add input validation.

The CreateResource method should validate the input parameters before processing.

 [HttpPost]
 [Route("language/{languageCode}")]
 public async Task<ActionResult<TextResource>> CreateResource([FromBody] TextResource jsonData, string languageCode, string org, CancellationToken cancellationToken = default)
 {
     cancellationToken.ThrowIfCancellationRequested();
+    if (string.IsNullOrEmpty(languageCode))
+    {
+        return BadRequest("Language code is required");
+    }
+    if (string.IsNullOrEmpty(org))
+    {
+        return BadRequest("Organization identifier is required");
+    }
+    if (jsonData == null)
+    {
+        return BadRequest("Text resource data is required");
+    }
     string developer = AuthenticationHelper.GetDeveloperUserName(HttpContext);
📝 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.

    [HttpPost]
    [Route("language/{languageCode}")]
    public async Task<ActionResult<TextResource>> CreateResource([FromBody] TextResource jsonData, string languageCode, string org, CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();
        if (string.IsNullOrEmpty(languageCode))
        {
            return BadRequest("Language code is required");
        }
        if (string.IsNullOrEmpty(org))
        {
            return BadRequest("Organization identifier is required");
        }
        if (jsonData == null)
        {
            return BadRequest("Text resource data is required");
        }
        string developer = AuthenticationHelper.GetDeveloperUserName(HttpContext);

        try
        {
            await _orgTextsService.SaveText(org, developer, jsonData, languageCode, cancellationToken);
            TextResource textResource = await _orgTextsService.GetText(org, developer, languageCode, cancellationToken);
            return Ok(textResource);
        }
        catch (ArgumentException e)
        {
            return BadRequest(e.Message);
        }
    }
frontend/dashboard/pages/PageLayout/DashboardHeader/DashboardHeader.tsx (1)

77-80: 🛠️ Refactor suggestion

Add input validation to extractSecondLastRouterParam.

The utility function should handle edge cases for pathname.

 function extractSecondLastRouterParam(pathname: string): string {
+  if (!pathname) {
+    return '';
+  }
   const pathnameArray = pathname.split('/');
+  if (pathnameArray.length < 2) {
+    return '';
+  }
   return pathnameArray[pathnameArray.length - 2];
 }
📝 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.

function extractSecondLastRouterParam(pathname: string): string {
  if (!pathname) {
    return '';
  }
  const pathnameArray = pathname.split('/');
  if (pathnameArray.length < 2) {
    return '';
  }
  return pathnameArray[pathnameArray.length - 2];
}
backend/src/Designer/Controllers/Organisation/OrgCodeListController.cs (1)

137-149: 🛠️ Refactor suggestion

Standardize response type in DeleteCodeList method.

The method returns either a list of OptionListData or a string message, which is inconsistent. Consider standardizing the response type to always return the updated list of code lists.

Apply this diff to standardize the response:

-        return Ok($"The code-list file {codeListId}.json has been deleted.");
+        return Ok(codeLists);

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

frontend/dashboard/app/App.tsx (2)

92-94: 🛠️ Refactor suggestion

Add a default return path to avoid undefined rendering.
SubrouteGuard lacks a default case; an unknown subrouteWithLeadingSlash would return undefined, violating the React.ReactElement return type. Provide a fallback.

function SubrouteGuard(props: AppWithDataProps): React.ReactElement {
  const subroute = useSubroute();
  const subrouteWithLeadingSlash = '/' + subroute;

  switch (subrouteWithLeadingSlash) {
    case APP_DASHBOARD_BASENAME:
      return <Dashboard {...props} />;
    case ORG_LIBRARY_BASENAME:
      return <OrgContentLibrary />;
+   default:
+     // e.g., route back to the main dashboard or show an error message
+     return <Dashboard {...props} />;
  }
}

Also applies to: 96-102


31-39: 🛠️ Refactor suggestion

Consider a fallback case in the switch statement.
The switch covers 'pending', 'error', and 'success', but if mergeQueryStatuses can yield other statuses (e.g., 'idle'), the function may inadvertently return undefined.

 switch (queryStatus) {
   case 'pending':
     return <PendingPage />;
   case 'error':
     return <ErrorMessage userStatus={userStatus} />;
   case 'success':
     return <AppWithData user={user} organizations={organizations} />;
+  default:
+    // Provide a fallback or safe default
+    return <PendingPage />;
 }
📝 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.

  switch (queryStatus) {
    case 'pending':
      return <PendingPage />;
    case 'error':
      return <ErrorMessage userStatus={userStatus} />;
    case 'success':
      return <AppWithData user={user} organizations={organizations} />;
    default:
      // Provide a fallback or safe default
      return <PendingPage />;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/app-preview Area: Related to test and preview of apps that are developed in Altinn Studio. area/dashboard Area: Related to the dashboard application area/text-editor Area: Related to creating, translating and editing texts. area/ui-editor Area: Related to the designer tool for assembling app UI in Altinn Studio. backend frontend quality/testing Tests that are missing, needs to be created or could be improved. solution/studio/designer Issues related to the Altinn Studio Designer solution. team/studio-domain1
Projects
Status: Documentation
Development

Successfully merging this pull request may close these issues.

2 participants