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: Update codelist endpoint return types #14622

Closed

Conversation

Konrad-Simso
Copy link
Contributor

@Konrad-Simso Konrad-Simso commented Feb 10, 2025

Description

All endpoints now return the current version of the options lists.
This will make it easier to use in our frontend as the cache can be set by a new copy after every sucessful update or creation and not updated/altered.

Related Issue

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

    • The dashboard now supports comprehensive organization-level code list management, enabling users to create, update, delete, and upload code lists.
    • A dedicated content library view (“Bibliotek”) has been introduced to streamline resource management.
  • Improvements

    • Dashboard navigation has been refined with dynamic routing and enhanced error handling, ensuring a smoother, more intuitive experience.

@Konrad-Simso Konrad-Simso added solution/studio/designer Issues related to the Altinn Studio Designer solution. backend area/content-library Area: Related to library for shared resources team/studio-domain1 labels Feb 10, 2025
Copy link
Contributor

coderabbitai bot commented Feb 10, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

This pull request introduces a new controller and supporting services for managing code lists at the organization level. It adds the CodeListController with endpoints for retrieval, creation, update, upload, and deletion of code lists. Associated changes update options and folder path handling in several controllers and repositories. New service implementations and interfaces (e.g., ICodeListService and CodeListService) have been added, and corresponding tests have been updated. Additionally, frontend components, hooks, routing logic, API mutations/queries, language files, and shared types have been modified or added to support enhanced organizational code list and text resource management.

Changes

File(s) Change Summary
backend/src/Designer/Controllers/Organisation/CodeListController.cs, .../Controllers/Preview/InstancesController.cs, .../Controllers/Preview/V3/OldInstancesController.cs, .../Controllers/PreviewController.cs Added new CodeListController with CRUD endpoints; introduced and used OptionsFolderPath constant; updated method signatures for options retrieval.
backend/src/Designer/Infrastructure/GitRepository/AltinnAppGitRepository.cs, .../Infrastructure/ServiceRegistration.cs, .../Services/Implementation/OptionsService.cs Updated repository methods to accept an optionsFolderPath parameter; added using directives and transient service registration for ICodeListService.
backend/src/Designer/Services/Implementation/Organisation/CodeListService.cs, .../Services/Interfaces/Organisation/ICodeListService.cs Introduced new CodeListService implementing ICodeListService with methods for managing code lists.
backend/tests/Designer.Tests/.../AltinnAppGitRepositoryTests.cs, .../Services/TextsServiceTest.cs Updated tests to accommodate new method signatures and parameters for options folder functionality.
frontend/dashboard/... (App, CreateService, OrgContentLibrary, DashboardHeader, hooks like useSubroute and useContextRedirectionGuard) Revised routing and navigation logic; added new subroute hook; updated URL constructions and header navigation; modified tests to include new parameters.
frontend/language/src/nb.json, frontend/libs/studio-content-library/..., frontend/libs/studio-pure-functions/... Added new language key for the dashboard; introduced new utility classes (FileUtils, StringUtils) and corresponding tests.
frontend/packages/shared/src/api/*, .../hooks/mutations/*, .../hooks/queries/*, .../constants.js, .../types/*, .../mocks/* Added new API paths, mutations, queries, shared types, and mocks for handling organizational code lists and text resources.

Possibly related PRs

Suggested labels

skip-releasenotes

Suggested reviewers

  • ErlingHauan
  • Konrad-Simso

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.

@Konrad-Simso Konrad-Simso changed the base branch from org-library-mvp to main February 10, 2025 14:35
@github-actions github-actions bot added 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. quality/testing Tests that are missing, needs to be created or could be improved. frontend labels Feb 10, 2025
@Konrad-Simso Konrad-Simso reopened this Feb 10, 2025
@Konrad-Simso Konrad-Simso changed the base branch from main to org-library-mvp February 10, 2025 14:46
@Konrad-Simso
Copy link
Contributor Author

Tried triggering automatic tests, it did not work. i'll run them manually from now on.

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 (2)
backend/src/Designer/Infrastructure/GitRepository/AltinnAppGitRepository.cs (2)

796-807: Enhance error handling and documentation.

The method could benefit from:

  1. XML documentation for the optionsFolderPath parameter
  2. Input validation for the path parameter
  3. More descriptive error messages
        /// <summary>
        /// Gets a list of file names from the Options folder representing the available options lists.
        /// </summary>
+       /// <param name="optionsFolderPath">The folder path where options lists are stored.</param>
        /// <returns>A list of option list names.</returns>
+       /// <exception cref="ArgumentException">Thrown when optionsFolderPath is null or empty.</exception>
        public string[] GetOptionsListIds(string optionsFolderPath)
        {
+           if (string.IsNullOrEmpty(optionsFolderPath))
+           {
+               throw new ArgumentException("Options folder path cannot be null or empty.", nameof(optionsFolderPath));
+           }
+
            string optionsFolder = Path.Combine(optionsFolderPath);
            if (!DirectoryExistsByRelativePath(optionsFolder))
            {
                return [];
            }

816-828: Enhance error handling and documentation.

The method could benefit from:

  1. XML documentation for the optionsFolderPath parameter
  2. Input validation for both parameters
  3. More descriptive error messages
        /// <summary>
        /// Gets a specific options list with the provided id.
        /// </summary>
        /// <param name="optionsListId">The name of the options list to fetch.</param>
+       /// <param name="optionsFolderPath">The folder path where options lists are stored.</param>
        /// <param name="cancellationToken">A <see cref="CancellationToken"/> that observes if operation is cancelled.</param>
        /// <returns>The options list as a string.</returns>
+       /// <exception cref="ArgumentException">Thrown when optionsListId or optionsFolderPath is null or empty.</exception>
+       /// <exception cref="NotFoundException">Thrown when the options list file is not found.</exception>
        public async Task<string> GetOptionsList(string optionsListId, string optionsFolderPath, CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

+           if (string.IsNullOrEmpty(optionsListId))
+           {
+               throw new ArgumentException("Options list ID cannot be null or empty.", nameof(optionsListId));
+           }
+
+           if (string.IsNullOrEmpty(optionsFolderPath))
+           {
+               throw new ArgumentException("Options folder path cannot be null or empty.", nameof(optionsFolderPath));
+           }
+
            string optionsFilePath = Path.Combine(optionsFolderPath, $"{optionsListId}.json");
            if (!FileExistsByRelativePath(optionsFilePath))
            {
-               throw new NotFoundException($"Options file {optionsListId}.json was not found.");
+               throw new NotFoundException($"Options file {optionsListId}.json was not found in folder {optionsFolderPath}.");
            }
🧹 Nitpick comments (50)
frontend/dashboard/app/App.tsx (2)

54-72: Error-handling logic is fine, but consider more detailed organization error checks
Currently, if userStatus === 'error', the user error is shown; otherwise, the organization error is shown. Consider also checking if organizations explicitly failed if you need more contextual error messages.


92-103: SubrouteGuard missing a default case
If the subroute doesn't match any known base, no fallback is provided. Consider adding a default to handle unknown subroutes with an error or redirect.

frontend/dashboard/hooks/guards/useContextRedirectionGuard.ts (1)

46-50: Using navigateToSelf if user lacks access
Consider whether a 403 or alert might be more appropriate for restricted contexts, instead of silently redirecting to Self.

backend/src/Designer/Services/Interfaces/Organisation/ICodeListService.cs (2)

21-30: GetCodeList needs clarity on missing code lists
If the code list is not found, decide whether to return an empty list or throw an exception. Consider doc comments to clarify.


42-52: CreateCodeList supports overwrite
Since creating existing code list overwrites data, an “upsert” naming could better reflect the behavior.

backend/src/Designer/Controllers/Organisation/CodeListController.cs (2)

79-81: Clarify or de-duplicate summary comments.

Lines 79–81 reuse the “Creates or overwrites” summary, which is nearly identical to lines 58–60 for the CreateCodeList method. Consider differentiating the summaries for clarity or removing duplication.


135-147: Return a more appropriate status code for non-existent code lists.

When the specified code list does not exist, the controller still returns a success (200 OK) message stating it "has been deleted." This can be confusing or misleading. Consider returning a 404 NotFound or a more accurate message if the resource was not previously present.

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

110-132: Reduce code duplication between create and update methods.

The CreateCodeList and UpdateCodeList methods both call CreateOrOverwriteOptionsList and then retrieve all code lists. If the logic is identical, consider consolidating them into a single method or factoring out the shared logic to improve maintainability.


110-153: Optimize by returning only the updated/created code list.

Each method that creates, updates, or uploads code lists calls GetCodeLists afterward and returns the entire set. If the consumer only needs the newly updated or created list, returning the full set may be inefficient, especially if the number of code lists grows large. Consider returning only the relevant code list data to optimize performance.


104-108: Consider performance implications of validating each option.

This row-by-row validation ensures correctness but might become costly for very large lists. If the volume of options is high, consider batched validation or partial checks to reduce overhead.

frontend/packages/shared/src/types/CodeListData.ts (1)

3-7: Add JSDoc documentation for better type clarity.

Consider adding JSDoc comments to document the purpose and usage of the CodeListData type and its properties.

+/**
+ * Represents a code list with its data and error state.
+ */
 export type CodeListData = {
+  /** The title of the code list */
   title: string;
+  /** Optional array of code list items */
   data?: CodeListItem[];
+  /** Indicates if there was an error loading the code list */
   hasError?: boolean;
 };
frontend/libs/studio-pure-functions/src/FileUtils/FileUtils.ts (1)

1-7: Refactor to a standalone function.

Instead of using a class with only static members, consider refactoring to a standalone function for better simplicity and maintainability.

-export class FileUtils {
-  static convertToFormData = (file: File): FormData => {
-    const formData = new FormData();
-    formData.append('file', file);
-    return formData;
-  };
-}
+/**
+ * Converts a File object to FormData.
+ * @param file The file to convert
+ * @returns FormData containing the file
+ */
+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/dashboard/hooks/useSubRoute/useSubroute.ts (1)

10-10: Consider moving the constant declaration above the hook.

For better readability and to avoid using variables before they are declared, consider moving the defaultSubroute constant above the hook implementation.

-export function useSubroute(): string {
-  const { subroute = defaultSubroute } = useParams();
-  return subroute;
-}
-
-const defaultSubroute = StringUtils.removeLeadingSlash(APP_DASHBOARD_BASENAME);
+const defaultSubroute = StringUtils.removeLeadingSlash(APP_DASHBOARD_BASENAME);
+
+export function useSubroute(): string {
+  const { subroute = defaultSubroute } = useParams();
+  return subroute;
+}
frontend/libs/studio-pure-functions/src/FileUtils/FileUtils.test.ts (1)

3-17: Consider adding test cases for edge cases.

The current test suite only covers the happy path. Consider adding test cases for:

  • Empty files
  • Files with special characters in the name
  • Large files
  • Files with different MIME types
frontend/packages/shared/src/hooks/queries/useOrgCodeListsQuery.ts (1)

9-12: Consider adding error handling and retry options.

For better error handling and resilience, consider adding:

  • Retry options for transient failures
  • Error boundaries for handling query errors
  • Proper error typing
   return useQuery<CodeListsResponse>({
     queryKey: [QueryKey.OrgCodeLists, org],
     queryFn: () => getCodeListsForOrg(org),
+    retry: 3,
+    retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
+    onError: (error) => {
+      console.error('Failed to fetch code lists:', error);
+    },
   });
frontend/packages/shared/src/hooks/queries/useTextResourcesForOrgQuery.ts (1)

6-15: Add parameter validation and query configuration.

Consider adding parameter validation and configuring stale/cache time for optimal performance.

 export const useTextResourcesForOrgQuery = (
   org: string,
   language: string,
 ): UseQueryResult<ITextResourcesWithLanguage> => {
+  if (!org || !language) {
+    throw new Error('org and language parameters are required');
+  }
+
   const { getTextResourcesForOrg } = useServicesContext();
   return useQuery<ITextResourcesWithLanguage>({
     queryKey: [QueryKey.TextResourcesForOrg, org, language],
     queryFn: () => getTextResourcesForOrg(org, language),
+    staleTime: 5 * 60 * 1000, // 5 minutes
+    cacheTime: 30 * 60 * 1000, // 30 minutes
   });
 };
frontend/dashboard/context/HeaderContext/HeaderContext.tsx (1)

12-15: Add documentation and type safety.

Consider adding JSDoc documentation and type assertions for the basename constants.

+/**
+ * Represents the available subroutes in the application.
+ * Used for navigation and routing purposes.
+ */
 export enum Subroute {
-  AppDashboard = APP_DASHBOARD_BASENAME,
-  OrgLibrary = ORG_LIBRARY_BASENAME,
+  AppDashboard = APP_DASHBOARD_BASENAME as string,
+  OrgLibrary = ORG_LIBRARY_BASENAME as string,
 }
frontend/packages/shared/src/hooks/queries/useOrgCodeListsQuery.test.ts (1)

14-18: Add cleanup and improve test helper.

The test helper should clean up after each test and handle errors gracefully.

+import { cleanup } from '@testing-library/react';
+
+afterEach(() => {
+  cleanup();
+  jest.clearAllMocks();
+});
+
 const render = async () => {
   const { result } = renderHookWithProviders(() => useOrgCodeListsQuery(org));
-  await waitFor(() => expect(result.current.isSuccess).toBe(true));
+  try {
+    await waitFor(() => expect(result.current.isSuccess).toBe(true));
+  } catch (error) {
+    console.error('Error waiting for hook to succeed:', error);
+  }
   return result;
 };
frontend/packages/shared/src/hooks/mutations/useCreateTextResourcesForOrgMutation.ts (1)

6-19: LGTM! Consider adding error handling.

The implementation correctly manages the mutation lifecycle and cache updates. However, consider adding error handling to manage failed mutations gracefully.

Add error handling by including an onError callback:

 return useMutation({
   mutationFn: async () => {
     const textResourcesWithLanguage: ITextResourcesWithLanguage[] =
       await createTextResourcesForOrg(org, language);

     return textResourcesWithLanguage;
   },
   onSuccess: (textResourcesWithLanguage) =>
     q.setQueryData([QueryKey.TextResourcesForOrg, org], textResourcesWithLanguage),
+  onError: (error) => {
+    // Handle error (e.g., show toast notification)
+    console.error('Failed to create text resources:', error);
+  },
 });
frontend/packages/shared/src/hooks/mutations/useUploadOrgCodeListMutation.ts (2)

11-14: Add file type validation.

Consider validating the file type before uploading to prevent invalid file uploads.

Add file type validation:

 const mutationFn = (file: File) => {
+  const allowedTypes = ['text/csv', 'application/json'];
+  if (!allowedTypes.includes(file.type)) {
+    throw new Error('Invalid file type. Only CSV and JSON files are allowed.');
+  }
   const formData = FileUtils.convertToFormData(file);
   return uploadCodeListForOrg(org, formData);
 };

16-21: Add error handling for failed uploads.

The implementation correctly manages the mutation lifecycle and cache updates. However, consider adding error handling to manage failed uploads gracefully.

Add error handling:

 return useMutation({
   mutationFn,
   onSuccess: (newData: CodeListsResponse) => {
     queryClient.setQueryData([QueryKey.OrgCodeLists, org], newData);
   },
+  onError: (error) => {
+    // Handle error (e.g., show toast notification)
+    console.error('Failed to upload code list:', error);
+  },
 });
frontend/packages/shared/src/hooks/mutations/useDeleteOrgCodeListMutation.ts (2)

13-13: Consider adding a confirmation check before deletion.

Since deletion is a destructive operation, consider adding a confirmation check before proceeding.

Add confirmation check:

-const mutationFn = ({ title }: DeleteOrgCodeListMutationArgs) => deleteCodeListForOrg(org, title);
+const mutationFn = ({ title }: DeleteOrgCodeListMutationArgs) => {
+  const confirmed = window.confirm(`Are you sure you want to delete the code list "${title}"?`);
+  if (!confirmed) {
+    throw new Error('Operation cancelled by user');
+  }
+  return deleteCodeListForOrg(org, title);
+};

15-20: Add error handling for failed deletions.

The implementation correctly manages the mutation lifecycle and cache updates. However, consider adding error handling to manage failed deletions gracefully.

Add error handling:

 return useMutation({
   mutationFn,
   onSuccess: (newData: CodeListsResponse) => {
     queryClient.setQueryData([QueryKey.OrgCodeLists, org], newData);
   },
+  onError: (error) => {
+    // Handle error (e.g., show toast notification)
+    console.error('Failed to delete code list:', error);
+  },
 });
frontend/packages/shared/src/hooks/mutations/useUpdateTextResourcesForOrgMutation.ts (2)

10-15: Add payload validation.

Consider validating the payload before updating to prevent invalid text resources.

Add payload validation:

 mutationFn: async (payload: ITextResource[]) => {
+  if (!Array.isArray(payload) || payload.length === 0) {
+    throw new Error('Payload must be a non-empty array of text resources');
+  }
+  if (!payload.every(resource => resource.id && resource.value)) {
+    throw new Error('Each text resource must have an id and value');
+  }
   const textResourcesWithLanguage: ITextResourcesWithLanguage[] =
     await updateTextResourcesForOrg(org, language, payload);

   return textResourcesWithLanguage;
 },

16-18: Add error handling for failed updates.

The implementation correctly manages the mutation lifecycle and cache updates. However, consider adding error handling to manage failed updates gracefully.

Add error handling:

 return useMutation({
   mutationFn: async (payload: ITextResource[]) => {
     const textResourcesWithLanguage: ITextResourcesWithLanguage[] =
       await updateTextResourcesForOrg(org, language, payload);

     return textResourcesWithLanguage;
   },
   onSuccess: (textResourcesWithLanguage) =>
     q.setQueryData([QueryKey.TextResourcesForOrg, org], textResourcesWithLanguage),
+  onError: (error) => {
+    // Handle error (e.g., show toast notification)
+    console.error('Failed to update text resources:', error);
+  },
 });
frontend/packages/shared/src/hooks/mutations/useCreateOrgCodeListMutation.ts (1)

16-21: Consider adding error handling.

The mutation is missing error handling. Consider adding an onError callback to handle API errors gracefully.

 return useMutation({
   mutationFn,
   onSuccess: (newData: CodeListsResponse) => {
     queryClient.setQueryData([QueryKey.OrgCodeLists, org], newData);
   },
+  onError: (error) => {
+    // Handle error appropriately
+    console.error('Failed to create code list:', error);
+  },
 });
frontend/packages/shared/src/hooks/mutations/useUpdateOrgCodeListMutation.ts (1)

7-22: Consider extracting shared mutation logic.

This hook shares significant code with useCreateOrgCodeListMutation. Consider extracting the common mutation configuration into a shared utility function.

+const createCodeListMutation = (
+  mutationFn: (args: Pick<CodeListData, 'title' | 'data'>) => Promise<CodeListsResponse>,
+  org: string,
+  queryClient: QueryClient
+) => ({
+  mutationFn,
+  onSuccess: (newData: CodeListsResponse) => {
+    queryClient.setQueryData([QueryKey.OrgCodeLists, org], newData);
+  },
+  onError: (error) => {
+    console.error('Failed to update code list:', error);
+  },
+});

 export const useUpdateOrgCodeListMutation = (org: string) => {
   const queryClient = useQueryClient();
   const { updateCodeListForOrg } = useServicesContext();

   const mutationFn = ({ title, data }: UpdateOrgCodeListMutationArgs) =>
     updateCodeListForOrg(org, title, data);

-  return useMutation({
-    mutationFn,
-    onSuccess: (newData: CodeListsResponse) => {
-      queryClient.setQueryData([QueryKey.OrgCodeLists, org], newData);
-    },
-  });
+  return useMutation(createCodeListMutation(mutationFn, org, queryClient));
 };
frontend/packages/shared/src/hooks/mutations/useAddOptionListMutation.ts (1)

18-21: Consider handling Promise rejections from cache invalidation.

The void operator is used to ignore Promises from invalidateQueries. Consider handling potential rejections.

-    onSuccess: () => {
-      void queryClient.invalidateQueries({ queryKey: [QueryKey.OptionListIds, org, app] });
-      void queryClient.invalidateQueries({ queryKey: [QueryKey.OptionLists, org, app] });
+    onSuccess: async () => {
+      try {
+        await Promise.all([
+          queryClient.invalidateQueries({ queryKey: [QueryKey.OptionListIds, org, app] }),
+          queryClient.invalidateQueries({ queryKey: [QueryKey.OptionLists, org, app] })
+        ]);
+      } catch (error) {
+        console.error('Failed to invalidate queries:', error);
+      }
     },
frontend/packages/shared/src/hooks/mutations/useAddOptionListMutation.test.ts (1)

11-22: Enhance test coverage.

The test suite only covers the happy path. Consider adding tests for:

  • Error cases
  • Cache invalidation
  • Different file types
 describe('useAddOptionsMutation', () => {
   afterEach(jest.clearAllMocks);

   it('Calls useAddOptionsMutation with correct arguments and payload', async () => {
     const optionsResult = renderHookWithProviders(() => useAddOptionListMutation(org, app)).result;

     await optionsResult.current.mutateAsync(file);

     expect(queriesMock.uploadOptionList).toHaveBeenCalledTimes(1);
     expect(queriesMock.uploadOptionList).toHaveBeenCalledWith(org, app, formData);
   });
+
+  it('Invalidates queries on success', async () => {
+    const queryClient = createQueryClient();
+    const optionsResult = renderHookWithProviders(
+      () => useAddOptionListMutation(org, app),
+      { queryClient }
+    ).result;
+
+    await optionsResult.current.mutateAsync(file);
+
+    expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
+      queryKey: [QueryKey.OptionListIds, org, app]
+    });
+    expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
+      queryKey: [QueryKey.OptionLists, org, app]
+    });
+  });
+
+  it('Handles API errors', async () => {
+    const error = new Error('API Error');
+    queriesMock.uploadOptionList.mockRejectedValueOnce(error);
+    const optionsResult = renderHookWithProviders(() => useAddOptionListMutation(org, app)).result;
+
+    await expect(optionsResult.current.mutateAsync(file)).rejects.toThrow(error);
+  });
 });
frontend/packages/shared/src/hooks/queries/useTextResourcesForOrgQuery.test.ts (2)

9-17: Consider adding more test cases for error scenarios and loading states.

The test suite currently only verifies the success path. Consider adding test cases for:

  • Error handling when the query fails
  • Loading state behavior
  • Empty response handling

19-22: Consider extracting test data setup to a separate file.

The renderAndWaitForResult helper function is well-structured, but consider moving test data like languageMock to a separate test data file for better reusability across test suites.

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

12-22: Enhance test coverage for mutation scenarios.

The test suite should include additional test cases:

  • Error handling when mutation fails
  • Validation of mutation payload structure
  • Loading state during mutation
  • Edge cases with empty/invalid payload
frontend/packages/shared/src/hooks/mutations/useUpdateTextResourcesForOrgMutation.test.ts (1)

9-10: Consider extracting test data setup.

Move mock data setup to a separate test data file for better reusability across test suites.

frontend/packages/shared/src/mocks/codeListsResponse.ts (1)

1-48: Consider adding tests for the mock data.

While the mock data is well-structured, consider adding unit tests to verify that the mock data matches the expected types and formats.

frontend/dashboard/pages/OrgContentLibrary/OrgContentLibrary.test.tsx (1)

7-35: Consider adding tests for user interactions and error states.

The current tests cover basic rendering. Consider adding tests for:

  • User interactions with the code list menu
  • Error states and loading states
  • Edge cases like empty code lists
frontend/packages/shared/src/hooks/mutations/useUploadOrgCodeListMutation.test.ts (1)

31-55: Consider adding tests for error cases and validation.

The current tests cover the happy path. Consider adding tests for:

  • Failed uploads
  • Invalid file formats
  • Network errors
  • Cache invalidation on error
frontend/packages/shared/src/hooks/mutations/useUpdateOrgCodeListMutation.test.ts (1)

29-58: Consider adding error case test.

While the happy path tests are well implemented, consider adding a test case for error scenarios to ensure proper error handling in the mutation hook.

 describe('useUpdateOrgCodeListMutation', () => {
   beforeEach(jest.clearAllMocks);

   // ... existing tests ...

+  it('Handles API errors correctly', async () => {
+    const error = new Error('API Error');
+    const updateCodeListForOrg = jest.fn(() => Promise.reject(error));
+    const { result } = renderHookWithProviders(() => useUpdateOrgCodeListMutation(org), {
+      queries: { updateCodeListForOrg },
+    });
+
+    await expect(result.current.mutateAsync(updatedCodeList)).rejects.toThrow(error);
+  });
 });
frontend/packages/shared/src/hooks/mutations/useCreateOrgCodeListMutation.test.ts (1)

29-60: Consider adding validation test.

While the basic functionality is well tested, consider adding a test case to verify that the mutation validates the input data before making the API call.

 describe('useCreateOrgCodeListMutation', () => {
   beforeEach(jest.clearAllMocks);

   // ... existing tests ...

+  it('Validates input data before API call', async () => {
+    const invalidCodeList = { title: '', data: [] };
+    const { result } = renderHookWithProviders(() => useCreateOrgCodeListMutation(org));
+
+    await expect(result.current.mutateAsync(invalidCodeList)).rejects.toThrow();
+    expect(queriesMock.createCodeListForOrg).not.toHaveBeenCalled();
+  });
 });
frontend/packages/shared/src/mocks/textResourcesMock.ts (1)

3-87: Consider using a factory function for mock data generation.

The current implementation has a lot of repetitive code. Consider using a factory function to generate mock data more efficiently and make it easier to maintain.

 import type { ITextResource, ITextResourcesWithLanguage } from 'app-shared/types/global';

+const createTextResource = (type: string, index: number): ITextResource => ({
+  id: `${type}${index}`,
+  value: `${type === 'label' ? 'Ledetekst' : type === 'description' ? 'Beskrivelse' : 'Hjelpetekst'} ${index}`,
+});
+
+const createTextResources = (type: string, count: number): ITextResource[] =>
+  Array.from({ length: count }, (_, i) => createTextResource(type, i + 1));
+
+const textResources: ITextResource[] = [
+  ...createTextResources('label', 5),
+  ...createTextResources('description', 5),
+  ...createTextResources('helpText', 5),
+];
+
 export const textResourcesMock: ITextResourcesWithLanguage = {
   language: 'nb',
   resources: textResources,
 };
frontend/libs/studio-pure-functions/src/StringUtils/StringUtils.ts (1)

89-89: Improve the implementation of removeLeadingSlash.

  1. Remove the unnecessary global flag 'g' from the regex since we're only matching the start of the string
  2. Add JSDoc documentation to maintain consistency with other methods
+  /**
+   * Removes leading slash from the given string.
+   * @param str The string to process.
+   * @returns The string with leading slash removed.
+   */
-  static removeLeadingSlash = (str: string): string => str.replace(/^\//g, '');
+  static removeLeadingSlash = (str: string): string => str.replace(/^\//, '');
frontend/dashboard/app/App.test.tsx (1)

83-89: Consider using test.each for repetitive test cases.

The helper functions improve readability, but consider using test.each for similar test cases that only differ in their input data.

-  const getFavouriteAppListHeading = (): HTMLElement =>
-    screen.getByRole('heading', { name: textMock('dashboard.favourites') });
-
-  const getLibraryHeading = (): HTMLElement =>
-    screen.getByRole('heading', { name: textMock('app_content_library.library_heading') });

+  const getHeading = (key: 'dashboard.favourites' | 'app_content_library.library_heading'): HTMLElement =>
+    screen.getByRole('heading', { name: textMock(key) });

Also applies to: 91-96

frontend/dashboard/pages/PageLayout/DashboardHeader/DashboardHeader.tsx (1)

43-45: Consider extending TopNavigationMenuProps interface.

The props interface could be extended to include optional styling or behavior customization.

 type TopNavigationMenuProps = {
   menuItem: HeaderMenuItem;
+  className?: string;
+  onClick?: (event: React.MouseEvent) => void;
 };
frontend/dashboard/pages/PageLayout/DashboardHeader/DashboardHeader.test.tsx (1)

44-44: Consider using a function for cleanup.

While jest.clearAllMocks works, wrapping it in a function is more consistent with Jest's cleanup patterns.

-  afterEach(jest.clearAllMocks);
+  afterEach(() => {
+    jest.clearAllMocks();
+  });
backend/src/Designer/Services/Implementation/OptionsService.cs (1)

23-23: Consider making the folder path configurable.

While using a constant is good, consider making this path configurable through dependency injection or configuration for better flexibility.

-    private const string OptionsFolderPath = "App/options/";
+    private readonly string _optionsFolderPath;
+
+    public OptionsService(
+        IAltinnGitRepositoryFactory altinnGitRepositoryFactory,
+        IConfiguration configuration)
+    {
+        _altinnGitRepositoryFactory = altinnGitRepositoryFactory;
+        _optionsFolderPath = configuration.GetValue<string>("OptionsFolderPath") ?? "App/options/";
+    }
backend/src/Designer/Controllers/PreviewController.cs (1)

65-65: Remove the trailing slash from the folder path.

The trailing slash in OptionsFolderPath is unnecessary and might cause issues with Path.Combine. Consider removing it to maintain consistency with other folder path constants in the file.

-private const string OptionsFolderPath = "App/options/";
+private const string OptionsFolderPath = "App/options";
backend/src/Designer/Infrastructure/GitRepository/AltinnAppGitRepository.cs (2)

813-816: Add XML documentation for the optionsFolderPath parameter.

The XML documentation for the new optionsFolderPath parameter is missing a description. Consider adding one to maintain consistency with the documentation style.

        /// <summary>
        /// Gets a specific options list with the provided id.
        /// </summary>
        /// <param name="optionsListId">The name of the options list to fetch.</param>
-       /// <param name="optionsFolderPath"></param>
+       /// <param name="optionsFolderPath">The folder path where options lists are stored.</param>
        /// <param name="cancellationToken">A <see cref="CancellationToken"/> that observes if operation is cancelled.</param>
        /// <returns>The options list as a string.</returns>

813-813: Add XML documentation for the new parameter.

The XML documentation for the optionsFolderPath parameter is missing. Add a description to maintain consistency with the rest of the codebase.

        /// <summary>
        /// Gets a specific options list with the provided id.
        /// </summary>
        /// <param name="optionsListId">The name of the options list to fetch.</param>
-       /// <param name="optionsFolderPath"></param>
+       /// <param name="optionsFolderPath">The folder path where options lists are stored.</param>
        /// <param name="cancellationToken">A <see cref="CancellationToken"/> that observes if operation is cancelled.</param>
        /// <returns>The options list as a string.</returns>
backend/tests/Designer.Tests/Infrastructure/GitRepository/AltinnAppGitRepositoryTests.cs (3)

267-267: Consider extracting the options folder path as a constant.

The string "App/options" is duplicated across multiple test methods. Consider extracting it as a private constant at the class level to improve maintainability and reduce duplication.

public class AltinnAppGitRepositoryTests
{
+    private const string TestOptionsFolderPath = "App/options";

Also applies to: 286-286, 298-298, 314-314


267-268: Extract hardcoded path to a constant.

The hardcoded path "App/options" is used in multiple test methods. Consider extracting it to a private constant at the class level to improve maintainability and ensure consistency.

public class AltinnAppGitRepositoryTests
{
+    private const string TestOptionsFolderPath = "App/options";

    [Fact]
    public async Task GetOptions_WithAppThatHasOptions_ShouldReturnSpecificOptionsList()
    {
        string org = "ttd";
        string repository = "app-with-options";
        string developer = "testUser";
        string optionsId = "test-options";
-        string optionsFolderPath = "App/options";
+        string optionsFolderPath = TestOptionsFolderPath;

292-306: Add test cases for edge cases and error scenarios.

The current test only verifies the happy path. Consider adding test cases for:

  1. Empty options list
  2. Invalid folder path
  3. Folder path with special characters
  4. Folder path with trailing slashes
🛑 Comments failed to post (11)
backend/src/Designer/Controllers/Organisation/CodeListController.cs (1)

70-77: ⚠️ Potential issue

Fix mismatched return type.

Your service call at line 75 returns a List<OptionListData> object, yet the method signature declares Task<ActionResult<List<Option>>>. This is inconsistent and will result in runtime type mismatches.

Consider updating the method signature to match the underlying data type:

- public async Task<ActionResult<List<Option>>> CreateCodeList(string org, [FromRoute] string optionsListId, [FromBody] List<Option> payload, CancellationToken cancellationToken = default)
+ public async Task<ActionResult<List<OptionListData>>> CreateCodeList(string org, [FromRoute] string optionsListId, [FromBody] List<Option> payload, CancellationToken cancellationToken = default)
📝 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.

    public async Task<ActionResult<List<OptionListData>>> CreateCodeList(string org, [FromRoute] string optionsListId, [FromBody] List<Option> payload, CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();
        string developer = AuthenticationHelper.GetDeveloperUserName(HttpContext);

        var newOptionsList = await _codeListService.CreateCodeList(org, Repo, developer, optionsListId, payload, cancellationToken);
        return Ok(newOptionsList);
    }
frontend/libs/studio-pure-functions/src/FileUtils/FileUtils.test.ts (1)

13-14: ⚠️ Potential issue

Fix the assertion to properly compare File objects.

Using toBe for File objects might not work as expected since it checks for reference equality. Consider using more specific assertions to verify the file properties.

-      expect(retrievedFile).toBe(file);
+      expect(retrievedFile instanceof File).toBe(true);
+      expect((retrievedFile as File).name).toBe(fileName);
+      expect((retrievedFile as File).type).toBe(fileType);
+      expect((retrievedFile as File).size).toBe(file.size);
📝 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.

      const retrievedFile = formData.get('file');
-      expect(retrievedFile).toBe(file);
+      expect(retrievedFile instanceof File).toBe(true);
+      expect((retrievedFile as File).name).toBe(fileName);
+      expect((retrievedFile as File).type).toBe(fileType);
+      expect((retrievedFile as File).size).toBe(file.size);
frontend/dashboard/pages/OrgContentLibrary/OrgContentLibrary.tsx (2)

20-20: 🛠️ Refactor suggestion

Add error boundary and loading state.

The component should handle loading and error states gracefully.

-  return <div>{getContentResourceLibrary()}</div>;
+  return (
+    <ErrorBoundary fallback={<ErrorMessage />}>
+      <div>
+        {isLoading ? (
+          <Spinner />
+        ) : (
+          getContentResourceLibrary()
+        )}
+      </div>
+    </ErrorBoundary>
+  );
📝 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.

  return (
    <ErrorBoundary fallback={<ErrorMessage />}>
      <div>
        {isLoading ? (
          <Spinner />
        ) : (
          getContentResourceLibrary()
        )}
      </div>
    </ErrorBoundary>
  );

10-14: ⚠️ Potential issue

Implement callback functions and data fetching.

The empty callback functions and codeListsData array don't fulfill the PR's objective of updating codelist endpoint return types. Consider:

  1. Implementing the callback functions using the appropriate API mutations.
  2. Using useOrgCodeListsQuery hook to fetch and populate codeListsData.
  3. Adding error handling and loading states.

Here's a suggested implementation:

+import { useOrgCodeListsQuery } from '@studio/shared/hooks/queries/useOrgCodeListsQuery';
+import { useCreateCodeListForOrgMutation, useUpdateCodeListForOrgMutation, useDeleteCodeListForOrgMutation, useUploadCodeListForOrgMutation } from '@studio/shared/hooks/mutations';
+
 export function OrgContentLibrary(): ReactElement {
+  const { data: codeListsData = [], isLoading, error } = useOrgCodeListsQuery(org);
+  const { mutate: createCodeList } = useCreateCodeListForOrgMutation();
+  const { mutate: updateCodeList } = useUpdateCodeListForOrgMutation();
+  const { mutate: deleteCodeList } = useDeleteCodeListForOrgMutation();
+  const { mutate: uploadCodeList } = useUploadCodeListForOrgMutation();
+
   const { getContentResourceLibrary } = new ResourceContentLibraryImpl({
     pages: {
       codeList: {
         props: {
-          codeListsData: [],
-          onDeleteCodeList: () => {},
-          onUpdateCodeListId: () => {},
-          onUpdateCodeList: () => {},
-          onUploadCodeList: () => {},
+          codeListsData,
+          onDeleteCodeList: deleteCodeList,
+          onUpdateCodeListId: updateCodeList,
+          onUpdateCodeList: updateCodeList,
+          onUploadCodeList: uploadCodeList,
+          isLoading,
+          error,
         },
       },
     },
   });
📝 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.

import { useOrgCodeListsQuery } from '@studio/shared/hooks/queries/useOrgCodeListsQuery';
import { useCreateCodeListForOrgMutation, useUpdateCodeListForOrgMutation, useDeleteCodeListForOrgMutation, useUploadCodeListForOrgMutation } from '@studio/shared/hooks/mutations';

export function OrgContentLibrary(): ReactElement {
  const { data: codeListsData = [], isLoading, error } = useOrgCodeListsQuery(org);
  const { mutate: createCodeList } = useCreateCodeListForOrgMutation();
  const { mutate: updateCodeList } = useUpdateCodeListForOrgMutation();
  const { mutate: deleteCodeList } = useDeleteCodeListForOrgMutation();
  const { mutate: uploadCodeList } = useUploadCodeListForOrgMutation();

  const { getContentResourceLibrary } = new ResourceContentLibraryImpl({
    pages: {
      codeList: {
        props: {
          codeListsData,
          onDeleteCodeList: deleteCodeList,
          onUpdateCodeListId: updateCodeList,
          onUpdateCodeList: updateCodeList,
          onUploadCodeList: uploadCodeList,
          isLoading,
          error,
        },
      },
    },
  });

  // ... rest of your component logic
}
frontend/packages/shared/src/hooks/queries/useTextResourcesForOrgQuery.ts (1)

12-13: ⚠️ Potential issue

Include dynamic parameters in query key.

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

   return useQuery<ITextResourcesWithLanguage>({
-    queryKey: [QueryKey.TextResourcesForOrg],
+    queryKey: [QueryKey.TextResourcesForOrg, org, language],
     queryFn: () => getTextResourcesForOrg(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],
    queryFn: () => getTextResourcesForOrg(org, language),
frontend/packages/shared/src/hooks/queries/useOrgCodeListsQuery.test.ts (1)

7-12: 🛠️ Refactor suggestion

Add test cases for error and loading states.

The test suite should cover error scenarios and loading states.

 describe('useOrgCodeListsQuery', () => {
   it('calls getCodeListsForOrg with the correct parameters', () => {
     render();
     expect(queriesMock.getCodeListsForOrg).toHaveBeenCalledWith(org);
   });
+
+  it('handles loading state correctly', async () => {
+    const { result } = renderHookWithProviders(() => useOrgCodeListsQuery(org));
+    expect(result.current.isLoading).toBe(true);
+  });
+
+  it('handles error state correctly', async () => {
+    queriesMock.getCodeListsForOrg.mockRejectedValueOnce(new Error('Failed to fetch'));
+    const { result } = renderHookWithProviders(() => useOrgCodeListsQuery(org));
+    await waitFor(() => expect(result.current.isError).toBe(true));
+    expect(result.current.error).toBeDefined();
+  });
 });
📝 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.

describe('useOrgCodeListsQuery', () => {
  it('calls getCodeListsForOrg with the correct parameters', () => {
    render();
    expect(queriesMock.getCodeListsForOrg).toHaveBeenCalledWith(org);
  });

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

  it('handles error state correctly', async () => {
    queriesMock.getCodeListsForOrg.mockRejectedValueOnce(new Error('Failed to fetch'));
    const { result } = renderHookWithProviders(() => useOrgCodeListsQuery(org));
    await waitFor(() => expect(result.current.isError).toBe(true));
    expect(result.current.error).toBeDefined();
  });
});
frontend/dashboard/dashboardTestUtils.tsx (1)

32-34: ⚠️ Potential issue

Reconsider using BrowserRouter in tests.

Using BrowserRouter in tests might lead to issues as it manipulates the actual browser history. Consider using MemoryRouter instead, which is designed for testing and provides a self-contained environment.

-    <BrowserRouter>
+    <MemoryRouter>
       <ServicesContextProvider {...queries}>{children}</ServicesContextProvider>
-    </BrowserRouter>
+    </MemoryRouter>
📝 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.

    <MemoryRouter>
      <ServicesContextProvider {...queries}>{children}</ServicesContextProvider>
    </MemoryRouter>
frontend/packages/shared/src/hooks/mutations/useUpdateTextResourcesForOrgMutation.test.ts (1)

12-28: 🛠️ Refactor suggestion

Add cleanup and enhance test coverage.

Consider the following improvements:

  1. Add beforeEach(jest.clearAllMocks) for consistent test state
  2. Add test cases for:
    • Error handling
    • Invalid text resources
    • Empty text resources array
    • Network failures

Example addition:

 describe('useUpdateTextResourcesForOrgMutation', () => {
+  beforeEach(jest.clearAllMocks);
+
   it('Calls updateTextResourcesForOrg with correct arguments and payload', async () => {
     // ... existing test
   });
+
+  it('Handles error cases appropriately', async () => {
+    // Add error case test
+  });
+
+  it('Validates text resources before update', async () => {
+    // Add validation test
+  });
 });
📝 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.

describe('useUpdateTextResourcesForOrgMutation', () => {
  beforeEach(jest.clearAllMocks);
  
  it('Calls updateTextResourcesForOrg with correct arguments and payload', async () => {
    const { result } = renderHookWithProviders(() =>
      useUpdateTextResourcesForOrgMutation(org, languageMock),
    );

    result.current.mutate(textResourcesMock);
    await waitFor(() => expect(result.current.isSuccess).toBe(true));

    expect(queriesMock.updateTextResourcesForOrg).toHaveBeenCalledTimes(1);
    expect(queriesMock.updateTextResourcesForOrg).toHaveBeenCalledWith(
      org,
      languageMock,
      textResourcesMock,
    );
  });

  it('Handles error cases appropriately', async () => {
    // Add error case test
  });

  it('Validates text resources before update', async () => {
    // Add validation test
  });
});
frontend/packages/shared/src/hooks/mutations/useDeleteOrgCodeListMutation.test.ts (1)

45-49: ⚠️ Potential issue

Fix incorrect hook usage in cache update test.

The test is using useCreateOrgCodeListMutation instead of useDeleteOrgCodeListMutation. This is likely a copy-paste error and needs to be fixed.

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

    const deleteCodeListForOrg = jest.fn(() => Promise.resolve([otherCodeList]));
    const { result } = renderHookWithProviders(() => useDeleteOrgCodeListMutation(org), {
      queryClient,
      queries: { deleteCodeListForOrg },
    });
frontend/packages/shared/src/api/queries.ts (1)

183-185: 💡 Verification agent

🧩 Analysis chain

Mock implementation with clear TODO reference.

The implementation returns mock data with a clear reference to the future API endpoint (issue #14505).

Please track the TODO comment and ensure the implementation is updated when the API endpoint is ready:


🌐 Web query:

Is GitHub issue #14505 still open?

💡 Result:

GitHub issue #14505 exists in multiple repositories with different statuses:

  1. Podman (containers/podman)
    Closed on September 28, 2022, after healthcheck restart capability was added[1][9].

  2. Tailscale
    Open as of January 16, 2025 (feature request for CentOS Stream 10 support)[7].

  3. Bun (oven-sh/bun)
    Open as of February 10, 2025 (opened ~5 hours ago)[9].

  4. Snipe-IT
    Open since March 27, 2024 (feature request for shipping labels)[10].

Other notable mentions:

  • Notepad++: Closed after a fix in December 2023[4].
  • FilamentPHP: Closed after reproduction steps were provided[3].
  • OpenZFS: Open as a feature request since February 2023[5].

To determine if a specific #14505 is open, the repository name must be specified.

Citations:


I'll do a refined web query targeting the Altinn Studio repository to determine if issue #14505 is still open.


🌐 Web query:

Is the GitHub issue https://github.com/Altinn/altinn-studio/issues/14505 still open?

💡 Result:

The GitHub issue #14505 in the Altinn/altinn-studio repository is not listed in the current open issues from the provided search results[5]. The latest visible issues range from #14623 to #14582 (as of February 10, 2025), and there is no mention of #14505 in any of the active or closed issue lists provided[1][2][3][4][5][6][7][8][9].

Given GitHub’s sequential issue numbering and the absence of this specific issue ID in recent activity logs, it likely has been resolved or closed. For absolute certainty, you should verify directly on GitHub.

Citations:


Action Required: Replace Mock API Implementation with Real Call

The web query indicates that GitHub issue #14505 in the Altinn/altinn-studio repository is no longer open. This suggests that the API endpoint intended to replace the mock may now be available. Accordingly, update the implementation in:

  • File: frontend/packages/shared/src/api/queries.ts (lines 183-185)

to replace the Promise.resolve mocks with the real API calls and remove or update the now-outdated TODO comments.

backend/src/Designer/Controllers/PreviewController.cs (1)

65-65: ⚠️ Potential issue

Standardize path format across codebase.

The path format "App/options/" includes a trailing slash, while in tests it's "App/options". This inconsistency could lead to path resolution issues. Consider standardizing the path format across the codebase.

-    private const string OptionsFolderPath = "App/options/";
+    private const string OptionsFolderPath = "App/options";
📝 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.

        private const string OptionsFolderPath = "App/options";

@Konrad-Simso Konrad-Simso removed 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. quality/testing Tests that are missing, needs to be created or could be improved. frontend labels Feb 10, 2025
Copy link

codecov bot commented Feb 12, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 95.73%. Comparing base (fcc0f52) to head (bf3d4c5).
Report is 1 commits behind head on org-library-mvp.

Additional details and impacted files
@@               Coverage Diff                @@
##           org-library-mvp   #14622   +/-   ##
================================================
  Coverage            95.73%   95.73%           
================================================
  Files                 1919     1919           
  Lines                24948    24948           
  Branches              2838     2838           
================================================
  Hits                 23885    23885           
  Misses                 802      802           
  Partials               261      261           

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

@Konrad-Simso
Copy link
Contributor Author

Closing this PR as it's covered by #14650

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

1 participant