Skip to content

Conversation

sshveta
Copy link
Contributor

@sshveta sshveta commented Aug 10, 2025

Resolves: https://issues.redhat.com/browse/MTA-2783

image

Summary by CodeRabbit

  • New Features

    • Import now blocks duplicate questionnaire names and validates YAML content before submission; submit button is disabled while questionnaire data is being fetched.
    • Shows a success notification when a questionnaire is created.
  • Bug Fixes

    • File-read and validation errors are surfaced to users via localized messages instead of console logs.
  • Documentation

    • Added user-facing translation keys for file-read and invalid-YAML errors.

Copy link

coderabbitai bot commented Aug 10, 2025

Walkthrough

Fetches existing questionnaires and strengthens YAML import validation: parses YAML to JSON, enforces Questionnaire shape, rejects duplicate names (trimmed, lowercased), surfaces errors via form setError and translations, prevents submit while fetching, and shows success notifications on creation.

Changes

Cohort / File(s) Change Summary
Import form — validation & submission
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx
Added useFetchQuestionnaires and useMemo to derive existingNames. convertYamlToJson now returns `unknown
Queries — new hook
@app/queries/questionnaires (export)
Added exported useFetchQuestionnaires() hook to fetch existing questionnaires used by the import form.
Translations — additions
client/public/locales/en/translation.json
Added translation keys message.errorReadingFile ("Error reading file") and validation.invalidQuestionnaireYAML ("Invalid questionnaire YAML").

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ImportForm
    participant QuestionnairesService
    participant Notification
    Note over ImportForm,QuestionnairesService: Import flow (high-level)

    User->>ImportForm: Select / drop YAML file
    ImportForm->>QuestionnairesService: fetch existing questionnaires (useFetchQuestionnaires)
    QuestionnairesService-->>ImportForm: existing questionnaires
    ImportForm->>ImportForm: derive existingNames (useMemo: trim().toLowerCase())
    ImportForm->>ImportForm: convertYamlToJson(file) -> JSON | null
    alt YAML invalid or parse error
        ImportForm->>ImportForm: setError("yamlFile", t("validation.invalidQuestionnaireYAML") / t("message.errorReadingFile"))
        ImportForm-->>User: show validation error
    else YAML parsed
        ImportForm->>ImportForm: validate JSON is Questionnaire
        alt Not a Questionnaire
            ImportForm->>ImportForm: setError("yamlFile", t("validation.invalidQuestionnaireYAML"))
            ImportForm-->>User: show validation error
        else Valid Questionnaire
            ImportForm->>ImportForm: check name ∉ existingNames
            alt Duplicate name
                ImportForm->>ImportForm: setError("yamlFile", t("validation.duplicateName"))
                ImportForm-->>User: abort creation
            else Unique name
                ImportForm->>QuestionnairesService: createQuestionnaire(JSON)
                QuestionnairesService-->>ImportForm: success
                ImportForm->>Notification: pushNotification(success)
                ImportForm-->>User: show success
            end
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I nibbled YAML lines so neat,
Trimmed each name until complete.
If echoes found a twin in sight,
I thumped my paw and held it tight.
Then I cheered as new forms hopped in bright. 🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🔭 Outside diff range comments (2)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (2)

75-80: Handle 409 conflict to cover server-enforced uniqueness and client race conditions

Even with client-side checks, two users can race to create the same name. Handle a 409 Conflict with a friendly duplicate message; retain the generic fallback otherwise.

Apply this diff:

   const onHandleFailedQuestionnaireCreation = (error: AxiosError) => {
-    pushNotification({
-      title: getAxiosErrorMessage(error),
-      variant: "danger",
-    });
+    if (error?.response?.status === 409) {
+      pushNotification({
+        title: "Duplicate questionnaire",
+        message: "A questionnaire with this name already exists.",
+        variant: "danger",
+        timeout: 30000,
+      });
+      return;
+    }
+    pushNotification({
+      title: getAxiosErrorMessage(error),
+      variant: "danger",
+    });
   };

And ensure the backend enforces a unique constraint on questionnaire name to guarantee consistency.


63-73: Bug: onSaved is invoked twice on success

onSaved(response) is followed by onSaved(), causing duplicate callbacks.

Apply this diff:

   const onHandleSuccessfulQuestionnaireCreation = (response: Questionnaire) => {
-    onSaved(response);
+    onSaved(response);
     pushNotification({
       title: t("toastr.success.createWhat", {
         type: t("terms.questionnaire"),
         what: response.name,
       }),
       variant: "success",
     });
-    onSaved();
   };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8c375b6 and 8e46789.

📒 Files selected for processing (1)
  • client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (1)
client/src/app/queries/questionnaires.ts (1)
  • useFetchQuestionnaires (36-54)
🔇 Additional comments (1)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (1)

21-24: LGTM: Added questionnaire query hook import

Importing useFetchQuestionnaires here is appropriate.

@sjd78 sjd78 changed the title 🐞 Duplicate entry validation for questionnaire 🐛 Duplicate entry validation for questionnaire Aug 11, 2025
@sshveta sshveta added this to Planning Aug 20, 2025
@github-project-automation github-project-automation bot moved this to 🆕 New in Planning Aug 20, 2025
@sshveta sshveta moved this from 🆕 New to ✅ Done in Planning Aug 20, 2025
@sshveta sshveta self-assigned this Aug 20, 2025
@sjd78 sjd78 changed the title 🐛 Duplicate entry validation for questionnaire 🐛 Duplicate name validation for questionnaire Aug 21, 2025
Copy link
Member

@sjd78 sjd78 left a comment

Choose a reason for hiding this comment

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

  1. Block the Import button until the checks can run (i.e. after data to check against has been loaded)
  2. Simplify the check logic a bit

@sshveta
Copy link
Contributor Author

sshveta commented Aug 22, 2025

  1. Block the Import button until the checks can run (i.e. after data to check against has been loaded)

    1. Simplify the check logic a bit

Done

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (1)

68-78: onSaved is called twice (duplicate callback)

onSaved(response) is invoked, then onSaved() is called again. This can cause double state updates, duplicate navigation, or duplicated notifications downstream.

Apply this diff:

   const onHandleSuccessfulQuestionnaireCreation = (response: Questionnaire) => {
     onSaved(response);
     pushNotification({
       title: t("toastr.success.createWhat", {
         type: t("terms.questionnaire"),
         what: response.name,
       }),
       variant: "success",
     });
-    onSaved();
   };
♻️ Duplicate comments (2)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (2)

43-44: Blocking submit while questionnaires load — addressed prior feedback

Destructuring isFetching from useFetchQuestionnaires fixes the race where duplicates could slip through before data loads. Nice.


245-247: Submit disabled during fetch — nice UX safeguard

Adding isFetching into the disabled condition prevents premature submission before the duplicate check can be trusted.

🧹 Nitpick comments (5)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (5)

45-47: Use a Set and remove unnecessary optional chaining

  • questionnaires already defaults to [], so questionnaires? and the || [] fallback are redundant.
  • Using a Set of normalized names makes membership checks O(1) and avoids duplicate entries.
  • Consider Unicode normalization (NFKC) to avoid confusables.

Apply this diff:

-  const existingNames = useMemo(() => {
-    return questionnaires?.map(({ name }) => name.trim().toLowerCase()) || [];
-  }, [questionnaires]);
+  const existingNames = useMemo(() => {
+    return new Set(
+      questionnaires
+        .map(({ name }) =>
+          typeof name === "string"
+            ? name.normalize("NFKC").trim().toLowerCase()
+            : ""
+        )
+        .filter(Boolean)
+    );
+  }, [questionnaires]);

And below (Line 127), switch includes(...) to has(...).


125-137: Harden duplicate validation: guard name type and normalize once

If questionnaireData.name isn’t a string or is whitespace, .trim() will throw or pass a blank name through. Add a type check and normalize once. If you adopt the Set change above, also use .has(...).

Apply this diff:

-          // Duplicate validation
-          const normalizedName = questionnaireData.name.trim().toLowerCase();
-          const isDuplicate = existingNames.includes(normalizedName);
-
-          if (isDuplicate) {
+          // Duplicate validation
+          const candidateName = questionnaireData.name;
+          if (typeof candidateName !== "string" || !candidateName.trim()) {
+            pushNotification({
+              title: "Failed",
+              message: "Invalid questionnaire name.",
+              variant: "danger",
+              timeout: 30000,
+            });
+            return;
+          }
+          const normalizedName = candidateName
+            .normalize("NFKC")
+            .trim()
+            .toLowerCase();
+          const isDuplicate =
+            // If existingNames is a Set<string> (preferred), use has(); otherwise, fallback to includes().
+            (existingNames as unknown as Set<string>).has
+              ? (existingNames as unknown as Set<string>).has(normalizedName)
+              : (existingNames as unknown as string[]).includes(normalizedName);
+
+          if (isDuplicate) {
             pushNotification({
               title: "Duplicate questionnaire",
               message: "A questionnaire with this name already exists.",
               variant: "danger",
               timeout: 30000,
             });
             return;
           }

Note: Replace hardcoded strings with t(...) for localization when convenient.


108-115: Tighten the Questionnaire type guard

The current guard only checks key presence. Ensure name/description are strings to avoid runtime errors when trimming/lowercasing.

Apply this diff:

-  function isQuestionnaire(data: any): data is Questionnaire {
-    return (
-      typeof data === "object" &&
-      data !== null &&
-      "name" in data &&
-      "description" in data
-    );
-  }
+  function isQuestionnaire(data: unknown): data is Pick<Questionnaire, "name" | "description"> {
+    if (!data || typeof data !== "object" || Array.isArray(data)) return false;
+    const maybe: any = data;
+    return typeof maybe.name === "string" && typeof maybe.description === "string";
+  }

94-106: Don’t cast YAML parse errors as AxiosError; handle generically

jsYaml.load throws generic Error, not AxiosError. Casting can hide useful messages. Prefer generic error handling and localize the title/message.

Apply this diff:

   const convertYamlToJson = (yamlString: string) => {
     try {
       const jsonData = jsYaml.load(yamlString);
       return jsonData;
     } catch (error) {
-      pushNotification({
-        title: "Failed",
-        message: getAxiosErrorMessage(error as AxiosError),
-        variant: "danger",
-        timeout: 30000,
-      });
+      const message =
+        error instanceof Error ? error.message : String(error);
+      pushNotification({
+        title: t("toastr.error.generic", { defaultValue: "Failed" }),
+        message,
+        variant: "danger",
+        timeout: 30000,
+      });
     }
   };

100-105: Localize user-visible strings

Several strings are hardcoded. For consistency with the rest of the file (and i18n), wrap them with t(...). Examples: “Failed”, “Duplicate questionnaire”, “Invalid JSON data.”, “You should select a YAML file.”, and the “Upload” label.

Example diff (apply similarly to other occurrences):

-              title: "Duplicate questionnaire",
-              message: "A questionnaire with this name already exists.",
+              title: t("toastr.error.duplicateQuestionnaireTitle", { defaultValue: "Duplicate questionnaire" }),
+              message: t("toastr.error.duplicateQuestionnaireMessage", { defaultValue: "A questionnaire with this name already exists." }),
-            browseButtonText="Upload"
+            browseButtonText={t("actions.upload", { defaultValue: "Upload" })}
-              You should select a YAML file.
+              {t("dialog.message.mustSelectYaml", { defaultValue: "You should select a YAML file." })}

Also applies to: 129-135, 141-146, 214-218, 230-236, 225-225

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8e46789 and aebbfc8.

📒 Files selected for processing (1)
  • client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (1)
client/src/app/queries/questionnaires.ts (1)
  • useFetchQuestionnaires (36-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: unit-test
  • GitHub Check: build-and-upload-for-global-ci
🔇 Additional comments (2)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (2)

1-1: Importing useMemo to precompute names is appropriate

Good call adding useMemo; it avoids recomputing the normalized names on every render.


21-24: Correct query imports

Bringing in useFetchQuestionnaires and the create mutation here makes sense and keeps the form self-contained.

Copy link
Member

@sjd78 sjd78 left a comment

Choose a reason for hiding this comment

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

The test code is good and the existingNames is good, but there is a better place to put the tests.

@sjd78 sjd78 moved this from ✅ Done to 🏗 In progress in Planning Aug 25, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (3)

98-108: Fix: onSaved() is invoked twice on success

onHandleSuccessfulQuestionnaireCreation calls onSaved(response) and then onSaved() again. This can double-trigger parent effects (e.g., close dialog twice, extra refetch).

Apply this diff:

   const onHandleSuccessfulQuestionnaireCreation = (response: Questionnaire) => {
     onSaved(response);
     pushNotification({
       title: t("toastr.success.createWhat", {
         type: t("terms.questionnaire"),
         what: response.name,
       }),
       variant: "success",
     });
-    onSaved();
   };

191-216: Reset rejection state after a valid selection/clear

isFileRejected is set to true on rejection but never reset, keeping the file field in error state even after a valid file is chosen or cleared.

Apply this diff:

             onFileInputChange={async (_, file) => {
               try {
                 if (!file) {
                   return;
                 }
+                setIsFileRejected(false);

                 const reader = new FileReader();

@@
             onClearClick={() => {
               onChange("");
               setFilename("");
+              setIsFileRejected(false);
             }}

Also applies to: 225-228


182-186: Fix i18n key mismatch in file import-questionnaire-form.tsx

I confirmed that the only definition in client/public/locales/en/translation.json is

"dialog": {
  "message": {
    "maxfileSize": "Max file size of 1MB exceeded. Upload a smaller file."
  }
}

and the code in client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx still uses the incorrect key dialog.message.maxFileSize. This will prevent the error message from resolving.

Please apply this diff at lines 182–186:

-                  setError(name, {
-                    type: "custom",
-                    message: t("dialog.message.maxFileSize"),
-                  });
+                  setError(name, {
+                    type: "custom",
+                    message: t("dialog.message.maxfileSize"),
+                  });

No other occurrences of either key were found in the codebase.
Let me know if any other locale files or code paths need verification.

🧹 Nitpick comments (8)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (8)

234-241: Localize hard-coded helper text

Replace the hard-coded string with a translation key for consistency.

Apply this diff:

-            <HelperTextItem variant="error">
-              You should select a YAML file.
-            </HelperTextItem>
+            <HelperTextItem variant="error">
+              {t("validation.invalidFormat")}
+            </HelperTextItem>

68-71: i18n: use translated entity name in duplicate message

Pass the localized “questionnaire” string instead of a raw English literal.

Apply this diff:

-          t("validation.duplicateName", { type: "questionnaire" }),
+          t("validation.duplicateName", { type: t("terms.questionnaire") }),

175-179: Accept additional YAML MIME types

Some browsers/os report YAML as application/x-yaml or text/x-yaml. Widen accept to reduce false rejections.

Apply this diff:

               dropzoneProps={{
                 accept: {
-                  "text/yaml": [".yml", ".yaml"],
+                  "text/yaml": [".yml", ".yaml"],
+                  "application/x-yaml": [".yml", ".yaml"],
+                  "text/x-yaml": [".yml", ".yaml"],
                 },
                 maxSize: 1000000,

217-223: Prefer field error over toast for file read failures here

This catch isn’t Axios-related; getAxiosErrorMessage will likely produce “Network error”. Surface the issue inline next to the field using the same translation as elsewhere.

Apply this diff:

-                pushNotification({
-                  title: "Failed",
-                  message: getAxiosErrorMessage(err as AxiosError),
-                  variant: "danger",
-                  timeout: 30000,
-                });
+                setError(name, {
+                  type: "custom",
+                  message: t("message.errorReadingFile"),
+                });

46-49: Minor: questionnaires is always an array; drop optional chaining

useFetchQuestionnaires returns questionnaires: data || [], so the optional chain and fallback are redundant.

Apply this diff:

   const existingNames = useMemo(() => {
-    return questionnaires?.map(({ name }) => name.trim().toLowerCase()) || [];
+    return questionnaires.map(({ name }) => name.trim().toLowerCase());
   }, [questionnaires]);

53-82: Reduce double YAML parsing and tailor error messages in one test

The schema parses YAML twice (once per test). You can consolidate to a single test and still keep specific messages by using createError with function() syntax.

Apply this diff:

-      yamlFile: yup
-        .string()
-        .required(t("validation.invalidQuestionnaireYAML"))
-        .test(
-          "Valid Questionnaire YAML",
-          t("validation.invalidQuestionnaireYAML"),
-          (yamlFile) => {
-            if (!yamlFile) {
-              return true;
-            }
-            const jsonData = convertYamlToJson(yamlFile);
-            return isQuestionnaire(jsonData);
-          }
-        )
-        .test(
-          "Duplicate name",
-          t("validation.duplicateName", { type: t("terms.questionnaire") }),
-          (yamlFile) => {
-            if (!yamlFile) {
-              return true;
-            }
-            const jsonData = convertYamlToJson(yamlFile);
-            if (isQuestionnaire(jsonData)) {
-              const normalizedName = jsonData.name.trim().toLowerCase();
-              const isDuplicate = existingNames.includes(normalizedName);
-              return !isDuplicate;
-            }
-            return true;
-          }
-        ),
+      yamlFile: yup
+        .string()
+        .required(t("validation.invalidQuestionnaireYAML"))
+        .test("validate-questionnaire", t("validation.invalidQuestionnaireYAML"), function (yamlFile) {
+          if (!yamlFile) return true;
+          const jsonData = convertYamlToJson(yamlFile);
+          if (!isQuestionnaire(jsonData)) {
+            return this.createError({ message: t("validation.invalidQuestionnaireYAML") });
+          }
+          const normalizedName = jsonData.name.trim().toLowerCase();
+          if (existingNames.includes(normalizedName)) {
+            return this.createError({
+              message: t("validation.duplicateName", { type: t("terms.questionnaire") }),
+            });
+          }
+          return true;
+        }),

131-138: Optional: strengthen the Questionnaire type guard

Ensure name/description are non-empty strings; prevents passing structurally invalid objects to createQuestionnaire.

Apply this diff:

 function isQuestionnaire(data: unknown): data is Questionnaire {
   return (
-    typeof data === "object" &&
-    data !== null &&
-    "name" in data &&
-    "description" in data
+    typeof data === "object" &&
+    data !== null &&
+    "name" in data &&
+    "description" in data &&
+    typeof (data as any).name === "string" &&
+    typeof (data as any).description === "string" &&
+    (data as any).name.trim().length > 0 &&
+    (data as any).description.trim().length > 0
   );
 }

140-159: Optional: simplify onSubmit; rely on schema guarantees

With validation ensuring a well-formed Questionnaire, convert and submit without try/catch; mutation callbacks already handle errors. Keeps concerns separated.

Apply this diff:

-  const onSubmit = ({ yamlFile }: ImportQuestionnaireFormValues) => {
-    if (yamlFile) {
-      try {
-        createQuestionnaire(convertYamlToJson(yamlFile) as Questionnaire);
-      } catch (error) {
-        pushNotification({
-          title: "Failed",
-          message:
-            error instanceof AxiosError
-              ? getAxiosErrorMessage(error as AxiosError)
-              : error instanceof Error
-                ? error.message
-                : "Error",
-          variant: "danger",
-          timeout: 30000,
-        });
-      }
-    }
-  };
+  const onSubmit = ({ yamlFile }: ImportQuestionnaireFormValues) => {
+    // At this point, schema has validated yamlFile and uniqueness.
+    const data = convertYamlToJson(yamlFile) as Questionnaire;
+    createQuestionnaire(data);
+  };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between aebbfc8 and 9dddbe0.

📒 Files selected for processing (2)
  • client/public/locales/en/translation.json (2 hunks)
  • client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (8 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx (5)
client/src/app/components/NotificationsContext.tsx (1)
  • NotificationsContext (31-33)
client/src/app/queries/questionnaires.ts (1)
  • useFetchQuestionnaires (36-54)
client/src/app/api/models.ts (1)
  • Questionnaire (817-833)
client/src/app/api/rest.ts (1)
  • createQuestionnaire (672-675)
client/src/app/utils/utils.ts (1)
  • getAxiosErrorMessage (10-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: unit-test
  • GitHub Check: build-and-upload-for-global-ci
🔇 Additional comments (2)
client/public/locales/en/translation.json (2)

231-231: LGTM: new translation key "message.errorReadingFile"

Key is clear and used by the import form to surface file-read errors.


625-625: LGTM: new translation key "validation.invalidQuestionnaireYAML"

Fits the validation flow moved into the Yup schema for the YAML import.

Copy link
Member

@sjd78 sjd78 left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
client/public/locales/en/translation.json (1)

628-628: Added validation.invalidQuestionnaireYAML: precise and aligned with the new YAML import validation.

Sentence-casing and “YAML” capitalization are consistent with nearby keys (e.g., “Invalid format”). Optional: if you plan to surface parse specifics, consider a second key that accepts a reason (e.g., “Invalid questionnaire YAML: {{reason}}”) and fall back to the generic one when details aren’t available.

As a quick check, ensure the validation path shows this message (not the generic invalidFormat) when YAML parsing or schema validation fails for questionnaires. The script above already searches for usages; re-run after wiring the validation to confirm.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9dddbe0 and ee0c2bd.

📒 Files selected for processing (1)
  • client/public/locales/en/translation.json (2 hunks)
🔇 Additional comments (1)
client/public/locales/en/translation.json (1)

231-231: message.errorReadingFile key verified and translations in place

  • Usage confirmed in client/src/app/pages/assessment-management/import-questionnaire-form/import-questionnaire-form.tsx
    • Line 55 & 58: t("validation.invalidQuestionnaireYAML")
    • Line 207: message: t("message.errorReadingFile")
  • All non-English translation.json files include both
    message.errorReadingFile
    validation.invalidQuestionnaireYAML

Looks good to merge—no further changes needed. Let me know if you’d like assistance adding or updating other locales in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: ✅ Done
Development

Successfully merging this pull request may close these issues.

2 participants