Skip to content

Fix form client validation - #175

Closed
VitalyyP wants to merge 19 commits into
mainfrom
679-fix/form-client-validation
Closed

Fix form client validation#175
VitalyyP wants to merge 19 commits into
mainfrom
679-fix/form-client-validation

Conversation

@VitalyyP

@VitalyyP VitalyyP commented Jun 15, 2025

Copy link
Copy Markdown
Contributor
  • Improved form validation messages to be more user-friendly and descriptive
  • Added focus/blur validation for immediate user feedback
  • Improved scroll behavior for form errors and success messages
  • Implemented CSRF token protection for secure form submissions

@VitalyyP
VitalyyP requested a review from killev as a code owner June 15, 2025 09:49
@coderabbitai

coderabbitai Bot commented Jun 15, 2025

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This change introduces a new POST route for form submission, refactors client-side form validation to support asynchronous submission, and updates form templates to use static attributes and remove inline event handlers. Checkbox field handling is enhanced in both validation and template rendering, and form-related assets and styles are reorganized for clarity and modularity.

Changes

File(s) Change Summary
website/app.js Adds CSRF config to express options; updates shared constants import path.
website/modules/@apostrophecms/form-widget/index.js Adds assets property with client script to form-widget module options.
website/modules/@apostrophecms/form-widget/views/widget.html Simplifies form markup: removes dynamic data attributes and event handlers, uses static action/method, disables native validation.
website/modules/@apostrophecms/form/index.js Fixes context in submitForm; adds routes method with POST handler for form submission.
website/modules/@apostrophecms/form-checkboxes-field-widget/views/widget.html Adds new template for rendering form checkboxes field with unique IDs and required handling.
website/modules/asset/ui/index.js New entry point file importing src/index.js.
website/modules/asset/ui/src/js/formValidation.js Refactors form validation and submission to async flow; adds helpers for form data collection, error handling, and async POST.
website/modules/asset/ui/src/js/formValidation.test.js Mocks fetch globally for tests; removes assertion on defaultPrevented.
website/modules/asset/ui/src/js/domHelpers.js Updates error element handling for checkboxes; adds showError and clearError helpers for form-level errors.
website/modules/asset/ui/src/js/formValidator.js Refactors field value extraction and schema selection; improves required/checkbox logic.
website/modules/asset/ui/src/js/formValidator.test.js Adds hasAttribute mock to test utility.
website/modules/asset/ui/src/js/validationSchemas.js Adds fallback schema for checkboxes with required logic.
website/modules/asset/ui/src/scss/_form.scss Extracts .sf-input height styling from combined selector; separates input and textarea height rules.
website/scripts/generate_constants.js Changes export of STANDARD_FORM_FIELD_NAMES to a JavaScript object literal format.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Browser
  participant ClientJS
  participant Server
  participant FormModule

  User->>Browser: Submits form
  Browser->>ClientJS: Triggers async submit handler
  ClientJS->>ClientJS: Validate fields (including checkboxes)
  alt Validation fails
    ClientJS->>Browser: Scroll/focus first invalid field, show error
  else Validation passes
    ClientJS->>Server: POST /api/v1/@apostrophecms/form/submit (JSON)
    Server->>FormModule: Handle POST, parse and validate data
    alt Data invalid
      FormModule->>Server: Respond 400 error
      Server->>ClientJS: Return error response
      ClientJS->>Browser: Show error message
    else Submission succeeds
      FormModule->>Server: Respond with success JSON
      Server->>ClientJS: Return success response
      ClientJS->>Browser: Reset form, show thank you message
    end
  end
Loading

Possibly related PRs

  • speedandfunction/website#164: Introduces and implements the @apostrophecms/shared-constants module, directly related to the shared constants import update.
  • speedandfunction/website#11: Modifies the form-widget template, related by changes to form markup though differing in scope and intent.
  • speedandfunction/website#155: Refactors the form module extensively including form submission handling, related to the new POST route and submission fixes.

Suggested reviewers

  • yuramax
  • IhorMasechko
  • Anton-88
  • killev
✨ Finishing Touches
  • 📝 Generate Docstrings

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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

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

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @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 commented Jun 15, 2025

Copy link
Copy Markdown

🔍 Vulnerabilities of apostrophe-cms:test

📦 Image Reference apostrophe-cms:test
digestsha256:a723c34a49605ea0f39241cbadef4ebb7968781b0452cab84428caa0a5765ecf
vulnerabilitiescritical: 0 high: 3 medium: 0 low: 0
platformlinux/amd64
size290 MB
packages976
📦 Base Image node:23-alpine
also known as
  • 23-alpine3.22
  • 23.11-alpine
  • 23.11-alpine3.22
  • 23.11.1-alpine
  • 23.11.1-alpine3.22
digestsha256:b9d38d589853406ff0d4364f21969840c3e0397087643aef8eede40edbb6c7cd
vulnerabilitiescritical: 0 high: 0 medium: 0 low: 1
critical: 0 high: 1 medium: 0 low: 0 connect-multiparty 2.2.0 (npm)

pkg:npm/connect-multiparty@2.2.0

high 7.8: CVE--2022--29623 Unrestricted Upload of File with Dangerous Type

Affected range<=2.2.0
Fixed versionNot Fixed
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.334%
EPSS Percentile56th percentile
Description

An arbitrary file upload vulnerability in the file upload module of Express Connect-Multiparty 2.2.0 allows attackers to execute arbitrary code via a crafted PDF file. NOTE: the Supplier has not verified this vulnerability report.

critical: 0 high: 1 medium: 0 low: 0 async 0.9.2 (npm)

pkg:npm/async@0.9.2

high 7.8: CVE--2021--43138 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range<2.6.4
Fixed version2.6.4, 3.2.2
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score1.061%
EPSS Percentile77th percentile
Description

A vulnerability exists in Async through 3.2.1 (fixed in 3.2.2), which could let a malicious user obtain privileges via the mapValues() method.

critical: 0 high: 1 medium: 0 low: 0 async 1.5.2 (npm)

pkg:npm/async@1.5.2

high 7.8: CVE--2021--43138 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range<2.6.4
Fixed version2.6.4, 3.2.2
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score1.061%
EPSS Percentile77th percentile
Description

A vulnerability exists in Async through 3.2.1 (fixed in 3.2.2), which could let a malicious user obtain privileges via the mapValues() method.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🔭 Outside diff range comments (2)
website/scripts/generate_constants.js.rej (1)

1-21: ⚠️ Potential issue

Remove stray patch-reject file from the repository

*.rej files are created by a failed git apply / patch and should never be committed.
Please delete the file and add it to .gitignore (see prior comment).

-website/scripts/generate_constants.js.rej
website/modules/@apostrophecms/form/index.js (1)

83-90: 🛠️ Refactor suggestion

Duplicate submission handling – risk of divergence
self.submitForm now calls this.handleFormSubmission, while the new API route talks to self.formSubmissionHandler directly. Any future change to validation/side-effects added to handleFormSubmission will not run for API calls. Consider delegating both call-sites to a single shared helper.

🧹 Nitpick comments (6)
website/.gitignore (1)

18-20: Add pattern for patch-reject artefacts

A .rej file slipped into the PR (see scripts/generate_constants.js.rej).
Adding a catch-all ignore will prevent this in future.

 # Generated files
 modules/@apostrophecms/shared-constants/ui/src/index.js
+*.rej
website/scripts/generate_constants.js (1)

47-51: String-interpolation can break on single quotes / edge cases

Building the object literal via template concatenation risks producing invalid JS if any value contains a single quote or backslash. A safer (and slightly shorter) approach is:

-export const STANDARD_FORM_FIELD_NAMES = {
-  ${Object.entries(STANDARD_FORM_FIELD_NAMES)
-    .map(([key, value]) => `${key}: '${value}'`)
-    .join(',\n  ')},
-};
+export const STANDARD_FORM_FIELD_NAMES = ${JSON.stringify(
+  STANDARD_FORM_FIELD_NAMES,
+  null,
+  2
+)};

The output is still a readable object literal and requires no manual escaping.

website/modules/asset/ui/src/js/formValidation.test.js (1)

3-10: Mock fetch more completely
Down-stream code often checks response.ok or response.status. The current stub only exposes json(). A simple addition avoids fragile tests:

 global.fetch = jest.fn(() =>
   Promise.resolve({
+    ok: true,
+    status: 200,
     json: () => Promise.resolve({ success: true }),
   }),
 );
website/modules/@apostrophecms/form-widget/views/widget.html (1)

79-80: Inline alert violates strict CSP
Hard-coded inline JS may be blocked if a Content-Security-Policy with script-src 'self' is enforced. Consider moving this callback to the bundled client script and reference it via a data attribute.

website/modules/asset/ui/src/js/formValidation.js (2)

121-129: Tighten optional-chaining & readability

error && error.textContent can be collapsed:

-if (error && error.textContent && error.textContent.trim() !== '') {
+if (error?.textContent?.trim()) {

Minor, but shortens the guard and matches the optional-chain pattern flagged by the linter.

🧰 Tools
🪛 Biome (1.9.4)

[error] 125-125: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


154-162: thankYou selector is global – restrict to current form container

document.querySelector('[data-apos-form-thank-you]') will only work for a single form. Scope the search to form.closest('[data-form-wrapper]') or similar to avoid clobbering parallel forms.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a2de723 and b2feba8.

📒 Files selected for processing (12)
  • eslint-form-fields-solution.patch (1 hunks)
  • website/.gitignore (1 hunks)
  • website/app.js (1 hunks)
  • website/modules/@apostrophecms/form-widget/index.js (1 hunks)
  • website/modules/@apostrophecms/form-widget/views/widget.html (3 hunks)
  • website/modules/@apostrophecms/form/index.js (1 hunks)
  • website/modules/@apostrophecms/shared-constants/ui/src/index.js (0 hunks)
  • website/modules/asset/ui/index.js (1 hunks)
  • website/modules/asset/ui/src/js/formValidation.js (1 hunks)
  • website/modules/asset/ui/src/js/formValidation.test.js (1 hunks)
  • website/scripts/generate_constants.js (1 hunks)
  • website/scripts/generate_constants.js.rej (1 hunks)
💤 Files with no reviewable changes (1)
  • website/modules/@apostrophecms/shared-constants/ui/src/index.js
🧰 Additional context used
🧬 Code Graph Analysis (1)
website/scripts/generate_constants.js (1)
website/modules/@apostrophecms/shared-constants/index.js (1)
  • STANDARD_FORM_FIELD_NAMES (6-10)
🪛 Biome (1.9.4)
website/modules/asset/ui/src/js/formValidation.js

[error] 125-125: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e-tests
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: security-scan
🔇 Additional comments (9)
website/.gitignore (1)

18-20: Good call on ignoring the generated constants file

Keeping generated artefacts out of version control avoids noisy diffs and merge pain.

website/scripts/generate_constants.js (1)

56-57: Trailing comma after last property is fine but check lint rules

ES2017 allows trailing commas in object literals; however some code-style configs (e.g. airbnb-base) forbid them. Confirm your linter agrees; otherwise CI will fail.

website/modules/asset/ui/index.js (1)

1-1: Entry point looks good

Side-effect import cleanly re-exports the UI bundle; no issues spotted.

website/app.js (1)

41-41: Module key updated correctly

Renaming to '@apostrophecms/shared-constants' keeps config consistent with filesystem layout. 👍

website/modules/@apostrophecms/form-widget/index.js (1)

17-19: Confirm asset path/mathcing build alias
'module:asset/ui/src/index.js' assumes an alias called asset is registered with Apostrophe’s asset bundler. If that alias is missing or renamed (the physical path is website/modules/asset/ui/src/index.js), the script will never be shipped to the browser and client-side validation will silently break.

Please double-check the modules/asset bundle configuration (usually in the root app.js) or run apos dev:inspect to be sure the alias resolves.

website/modules/asset/ui/src/js/formValidation.test.js (1)

20-25: SubmitEvent is not available in JSDOM
JSDOM shipped with Jest (v28-29) still lacks a native SubmitEvent constructor. This line may throw on CI without a polyfill.

Verify test run on your CI node version. If it fails, fall back to new Event('submit', { cancelable: true }) or install the polyfill.

website/modules/@apostrophecms/form/index.js (1)

104-108: 🛠️ Refactor suggestion

JSON.parse error not handled inside parseFormData
If rawData is a malformed JSON string JSON.parse will throw and bubble up to the outer catch, returning HTTP 500 instead of a clean 400.

if (typeof rawData === 'string') {
-  return JSON.parse(rawData);
+  try {
+    return JSON.parse(rawData);
+  } catch {
+    return null;
+  }
}
⛔ Skipped due to learnings
Learnt from: VitalyyP
PR: speedandfunction/website#155
File: website/modules/@apostrophecms/form/index.js:7-18
Timestamp: 2025-06-06T07:47:18.719Z
Learning: In website/modules/@apostrophecms/form/index.js, the parseFormData function intentionally does not include try-catch for JSON.parse errors to avoid nested error handling. Errors are allowed to bubble up to higher-level handlers where they can be properly logged and handled, keeping the error handling architecture simpler and more maintainable.
website/modules/@apostrophecms/form-widget/views/widget.html (1)

34-35: Button always disabled when reCAPTCHA enabled
The button is rendered disabled but no data-* hook remains to enable it after reCAPTCHA resolves, so the form becomes unusable with JS off or if the enabling code expects the removed attribute. Verify the enabling script matches this markup.

website/modules/asset/ui/src/js/formValidation.js (1)

179-188: Consider adding credentials: 'same-origin' to include cookies

If the endpoint relies on session cookies/CSRF tokens, omit this and the browser may drop them on CORS-like requests.

Comment thread eslint-form-fields-solution.patch Outdated
Comment thread website/modules/@apostrophecms/form/index.js
Comment thread website/modules/@apostrophecms/form-widget/views/widget.html
Comment thread website/modules/asset/ui/src/js/formValidation.js Outdated
Comment thread website/modules/asset/ui/src/js/formValidation.js Outdated
Comment thread website/modules/asset/ui/src/js/formValidation.js Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
website/modules/asset/ui/src/js/formValidation.js (3)

99-115: 🛠️ Refactor suggestion

Still manually iterating the form – please switch to FormData API

We previously suggested replacing this bespoke loop with the native FormData constructor to correctly capture multi-value fields, checkboxes, files, etc. The current code still misses those edge-cases and is harder to maintain.

-const collectFormData = (form) => {
-  const formElements = form.elements;
-  const formData = {};
-  let index = 0;
-  while (index < formElements.length) {
-    const element = formElements[index];
-    if (
-      element.name &&
-      element.type !== 'submit' &&
-      element.type !== 'button'
-    ) {
-      formData[element.name] = element.value;
-    }
-    index += 1;
-  }
-  return formData;
-};
+const collectFormData = (form) => {
+  const data = {};
+  const fd = new FormData(form);
+  for (const [key, value] of fd.entries()) {
+    data[key] = key in data ? [].concat(data[key], value) : value;
+  }
+  return data;
+};

159-175: ⚠️ Potential issue

Fetch response is parsed without response.ok guard – JSON parse will throw on 4xx/5xx

handleServerResponse always calls response.json(); if the server returns a non-OK status or empty body the promise rejects and we silently swallow it in .catch(() => null). Wrap the parse in a status check and propagate the error so the UI can react.

-const handleServerResponse = (response, form) => {
-  return response
-    .json()
-    .then((data) => onHandleServerResponse(data, form))
-    .catch(() => null);
-};
+const handleServerResponse = async (response, form) => {
+  if (!response.ok) {
+    throw new Error(`Request failed: ${response.status}`);
+  }
+  const data = await response.json();
+  return onHandleServerResponse(data, form);
+};

147-157: 🛠️ Refactor suggestion

Errors are still silenced – user receives no feedback

Every network / parse failure ultimately resolves to null, echoing the earlier concern about “silent no-ops”. At minimum log the error; ideally surface a generic banner so the visitor is not left wondering.

🧹 Nitpick comments (1)
website/modules/asset/ui/src/js/formValidation.js (1)

150-155: document.querySelector limits multi-form support

Using the global document selector will only reveal the first [data-apos-form-thank-you] element. If multiple forms exist, show the thank-you message scoped to the current form (or its container) to avoid interference.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b2feba8 and 822a913.

📒 Files selected for processing (2)
  • .gitignore (1 hunks)
  • website/modules/asset/ui/src/js/formValidation.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🧰 Additional context used
🪛 Biome (1.9.4)
website/modules/asset/ui/src/js/formValidation.js

[error] 124-124: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: e2e-tests
  • GitHub Check: security-scan
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (actions)
🔇 Additional comments (1)
website/modules/asset/ui/src/js/formValidation.js (1)

121-124: Optional-chaining can simplify the null guards

-const error = field
-  .closest('.sf-field')
-  ?.querySelector('.validation-error');
+const error = field.closest('.sf-field')?.querySelector('.validation-error');

[nitpick]

🧰 Tools
🪛 Biome (1.9.4)

[error] 124-124: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (3)
website/modules/asset/ui/src/js/formValidation.js (3)

99-115: 🛠️ Refactor suggestion

Switch to the native FormData API – manual looping still misses edge-cases
This was raised earlier and remains unresolved.

The current loop drops:
• multiple inputs with the same name
• checked/unchecked state of checkboxes & radios
<select multiple> values
<input type="file"> objects

-const collectFormData = (form) => {
-  const formElements = form.elements;
-  const formData = {};
-  let index = 0;
-  while (index < formElements.length) {
-    const element = formElements[index];
-    if (
-      element.name &&
-      element.type !== 'submit' &&
-      element.type !== 'button'
-    ) {
-      formData[element.name] = element.value;
-    }
-    index += 1;
-  }
-  return formData;
-};
+const collectFormData = (form) => {
+  const data = {};
+  const fd = new FormData(form);
+  for (const [key, value] of fd.entries()) {
+    data[key] = key in data ? [].concat(data[key], value) : value;
+  }
+  return data;
+};

160-165: ⚠️ Potential issue

response.ok isn’t checked – JSON parsing will throw on 4xx/5xx

Same concern as the previous review: call response.json() only for successful responses and route errors to onSendFormDataResponse/UI notification.

-return response
-  .json()
-  .then((data) => onHandleServerResponse(data, form))
-  .catch(() => null);
+if (!response.ok) {
+  return Promise.reject(new Error(`Request failed: ${response.status}`));
+}
+return response
+  .json()
+  .then((data) => onHandleServerResponse(data, form))
+  .catch(() => null);

148-156: 🛠️ Refactor suggestion

User never sees server-side errors – surface them instead of silent null

onHandleServerResponse returns null for any non-success path, leaving the user without feedback. Log or display a generic banner so the failure is visible.

Minimum:

-}
-return null;
+}
+showValidationErrorFn(
+  form,
+  'Submission failed. Please try again later.',
+);
🧹 Nitpick comments (4)
website/modules/csrf-helper/index.js (1)

8-21: Duplicate helper & method → consider DRY

getCsrfToken is declared twice with identical logic (in extendMethods and extendHelpers).
Exporting it only once and re-using would reduce duplication.

website/modules/asset/ui/src/js/domHelpers.js (1)

5-9: Repeated errorClass branching – pull up to a helper

showValidationError and clearValidationError both recompute errorClass. Extracting to a tiny helper would avoid divergence.

-  let errorClass = 'validation-error';
-  if (field.type === 'checkbox') {
-    errorClass = 'apos-form-error';
-  }
+  const errorClass = field.type === 'checkbox'
+    ? 'apos-form-error'
+    : 'validation-error';
website/modules/@apostrophecms/form-checkboxes-field-widget/views/widget.html (2)

1-16: Template control flow injects bare {% tokens into markup

Splitting the data-required attribute across {% if %} / {% endif %} leaves raw templating tokens inside a multiline attribute list which some HTML linters (HTMLHint) flag as duplicate/invalid attributes.
A compact one-liner is clearer and avoids the warning:

<div
  data-apos-form-checkboxes
  class="apos-form-input-wrapper sf-field"
  {{ widget.required ? 'data-required="true"' : '' }}>
🧰 Tools
🪛 HTMLHint (1.5.0)

[error] 1-1: Doctype must be declared before any non-comment content.

(doctype-first)


[error] 13-13: Duplicate of attribute name [ {% ] was found.

(attr-no-duplication)


17-35: fieldset lacks aria-required for accessibility

Screen readers rely on ARIA when native required cannot be used (checkbox groups).
Consider:

<fieldset class="apos-form-fieldset" {{ widget.required ? 'aria-required="true"' : '' }}>
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ca042b5 and 1fe0fd0.

📒 Files selected for processing (10)
  • website/app.js (2 hunks)
  • website/modules/@apostrophecms/form-checkboxes-field-widget/views/widget.html (1 hunks)
  • website/modules/@apostrophecms/form/index.js (2 hunks)
  • website/modules/asset/ui/src/js/domHelpers.js (2 hunks)
  • website/modules/asset/ui/src/js/formValidation.js (2 hunks)
  • website/modules/asset/ui/src/js/formValidator.js (1 hunks)
  • website/modules/asset/ui/src/js/formValidator.test.js (1 hunks)
  • website/modules/asset/ui/src/js/validationSchemas.js (1 hunks)
  • website/modules/asset/ui/src/scss/_form.scss (1 hunks)
  • website/modules/csrf-helper/index.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • website/modules/asset/ui/src/scss/_form.scss
🚧 Files skipped from review as they are similar to previous changes (2)
  • website/app.js
  • website/modules/@apostrophecms/form/index.js
🧰 Additional context used
🧬 Code Graph Analysis (1)
website/modules/asset/ui/src/js/domHelpers.js (3)
website/modules/asset/ui/src/js/formValidation.js (5)
  • field (120-120)
  • form (6-6)
  • form (14-14)
  • errorMessage (7-7)
  • errorMessage (15-15)
website/modules/asset/ui/src/js/domHelpers.test.js (2)
  • field (4-4)
  • wrapper (5-5)
website/modules/asset/ui/src/js/formValidation.test.js (2)
  • form (13-13)
  • errorMessage (15-15)
🪛 HTMLHint (1.5.0)
website/modules/@apostrophecms/form-checkboxes-field-widget/views/widget.html

[error] 1-1: Doctype must be declared before any non-comment content.

(doctype-first)


[error] 13-13: Duplicate of attribute name [ {% ] was found.

(attr-no-duplication)

🪛 Biome (1.9.4)
website/modules/asset/ui/src/js/formValidation.js

[error] 124-124: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e-tests
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: security-scan
🔇 Additional comments (2)
website/modules/asset/ui/src/js/formValidator.test.js (1)

46-50: 👍 Added hasAttribute mock completes the spy surface

The validator now checks element.hasAttribute('required'); adding the stub keeps the unit tests hermetic.
Looks good.

website/modules/asset/ui/src/js/validationSchemas.js (1)

83-106: Checkbox schema assumes scalar boolean – verify multi-checkbox use-case

The fallback schema treats a checkbox field as a single boolean, which is correct for a lone checkbox but not for a group (the new widget renders many checkboxes with the same name).
If the validator receives the value of one input, this is fine. If it aggregates all checked values into an array, the schema will fail.

Please confirm the runtime shape before merge.

Comment thread website/modules/csrf-helper/index.js Outdated
Comment thread website/modules/asset/ui/src/js/domHelpers.js
Comment thread website/modules/asset/ui/src/js/formValidator.js
Comment thread website/modules/asset/ui/src/js/formValidation.js
- Add CSRF token handling in form submissions - Improve form validation safety checks - Add null checks for DOM operations - Update session configuration - Fix checkbox value handling in form validator - Clean up commented code and improve error handling

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
website/modules/asset/ui/src/js/formValidation.js (2)

159-164: Still parsing JSON without checking response.ok

Calling response.json() on a 4xx/5xx or empty body will throw. Verify the status first and route to error handling.

-  return response
-    .json()
-    .then((data) => onHandleServerResponse(data, form))
-    .catch(() => null);
+  if (!response.ok) {
+    return Promise.reject(
+      new Error(`Request failed with status ${response.status}`),
+    );
+  }
+  return response
+    .json()
+    .then((data) => onHandleServerResponse(data, form))
+    .catch(() => null);

99-115: 🛠️ Refactor suggestion

Leverage FormData instead of manual iteration

The custom loop misses edge-cases (multiple values per key, checked-only checkboxes, files, etc.) and duplicates native functionality. Replacing it with the platform API simplifies the code and improves correctness.

-const collectFormData = (form) => {
-  const formElements = form.elements;
-  const formData = {};
-  let index = 0;
-  while (index < formElements.length) {
-    const element = formElements[index];
-    if (
-      element.name &&
-      element.type !== 'submit' &&
-      element.type !== 'button'
-    ) {
-      formData[element.name] = element.value;
-    }
-    index += 1;
-  }
-  return formData;
-};
+const collectFormData = (form) => {
+  const data = {};
+  for (const [key, value] of new FormData(form).entries()) {
+    data[key] = key in data ? [].concat(data[key], value) : value;
+  }
+  return data;
+};
🧹 Nitpick comments (1)
website/modules/asset/ui/src/js/formValidation.js (1)

117-126: Condense null/undefined guards with optional chaining

Minor readability tweak – the three property checks can be collapsed.

-    const error = field
-      .closest('.sf-field')
-      ?.querySelector('.validation-error');
-    if (error && error.textContent && error.textContent.trim() !== '') {
+    const hasError =
+      field
+        .closest('.sf-field')
+        ?.querySelector('.validation-error')
+        ?.textContent?.trim();
+    if (hasError) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 124-124: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1fe0fd0 and a154fb0.

📒 Files selected for processing (7)
  • website/app.js (2 hunks)
  • website/modules/@apostrophecms/form/index.js (2 hunks)
  • website/modules/asset/ui/src/js/domHelpers.js (2 hunks)
  • website/modules/asset/ui/src/js/formValidation.js (2 hunks)
  • website/modules/asset/ui/src/js/formValidation.test.js (1 hunks)
  • website/modules/asset/ui/src/js/formValidator.js (1 hunks)
  • website/modules/csrf-helper/index.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • website/modules/asset/ui/src/js/formValidation.test.js
  • website/app.js
  • website/modules/asset/ui/src/js/domHelpers.js
  • website/modules/@apostrophecms/form/index.js
  • website/modules/csrf-helper/index.js
  • website/modules/asset/ui/src/js/formValidator.js
🧰 Additional context used
🪛 Biome (1.9.4)
website/modules/asset/ui/src/js/formValidation.js

[error] 124-124: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: e2e-tests
  • GitHub Check: security-scan

Comment thread website/modules/asset/ui/src/js/formValidation.js
…guration to main app config - Add better error handling in form validation - Remove redundant CSRF helper module - Improve return values in form validation functions

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
website/modules/asset/ui/src/js/formValidation.js (3)

99-115: Leverage the built-in FormData API instead of a manual loop

Manual traversal misses edge-cases (checkbox groups, multi-selects, files, multiple inputs with the same name) and duplicates logic that the platform already provides.

-const collectFormData = (form) => {
-  const formElements = form.elements;
-  const formData = {};
-  let index = 0;
-  while (index < formElements.length) {
-    const element = formElements[index];
-    if (
-      element.name &&
-      element.type !== 'submit' &&
-      element.type !== 'button'
-    ) {
-      formData[element.name] = element.value;
-    }
-    index += 1;
-  }
-  return formData;
-};
+const collectFormData = (form) => {
+  const data = {};
+  const fd = new FormData(form);
+  for (const [key, value] of fd.entries()) {
+    data[key] = key in data ? [].concat(data[key], value) : value;
+  }
+  return data;
+};

This single change correctly handles all field types and simplifies the code.


167-172: Check response.ok before parsing JSON

response.json() will throw on 4xx/5xx or empty bodies.

-  return response
-    .json()
-    .then((data) => onHandleServerResponse(data, form))
-    .catch(() => false);
+  if (!response.ok) {
+    return false;
+  }
+  return response
+    .json()
+    .then((data) => onHandleServerResponse(data, form))
+    .catch(() => false);

Avoids unhandled promise rejections and keeps error handling consistent.


140-147: 🛠️ Refactor suggestion

Surface network/validation errors instead of swallowing them

The catch block hides the underlying error; logging it greatly eases debugging.

-  .catch(() => {
+  .catch((err) => {
+    /* eslint-disable no-console */
+    console.error('Form submission failed', err);
     const errorMessage = form.querySelector('.error-message');
     if (errorMessage) {
       errorMessage.textContent =
         'Failed to submit form. Please try again later.';
     }
     return null;
   });

Provides visibility without altering behaviour for end-users.

🧹 Nitpick comments (3)
website/modules/asset/ui/src/js/formValidation.js (3)

118-129: Minor: use optional chaining to simplify null-checks

Lines 124-126 can be condensed and made safer:

-    const error = field
-      .closest('.sf-field')
-      ?.querySelector('.validation-error');
-    if (error && error.textContent && error.textContent.trim() !== '') {
+    const error =
+      field
+        .closest('.sf-field')
+        ?.querySelector('.validation-error')?.textContent?.trim();
+    if (error) {
       field.scrollIntoView({ behavior: 'smooth', block: 'center' });
       field.focus();
       break;
     }

Less branching, clearer intent.

🧰 Tools
🪛 Biome (1.9.4)

[error] 124-124: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


154-162: Scope the “thank-you” search to the current form

document.querySelector('[data-apos-form-thank-you]') grabs the first element in the DOM; multiple forms will interfere with each other.

-    const thankYou = document.querySelector('[data-apos-form-thank-you]');
+    const thankYou = form.closest('form, .sf-form, body')?.querySelector(
+      '[data-apos-form-thank-you]',
+    );

Keeps feedback local to the form that was just submitted.


174-188: Optional: add timeout / abort support to fetch

Very slow connections will hang indefinitely. Consider an AbortController:

+  const controller = new AbortController();
+  const id = setTimeout(() => controller.abort(), 15000); // 15 s
   return fetch(form.action, {
     method: 'POST',
     body: JSON.stringify({ data: formData }),
     headers: {
       'Content-Type': 'application/json',
       'Accept': 'application/json',
       'CSRF-Token':
         document
           .querySelector('meta[name="csrf-token"]')
           ?.getAttribute('content') || '',
     },
     credentials: 'same-origin',
+    signal: controller.signal,
   }).finally(() => clearTimeout(id));

Prevents the UI from waiting forever on network issues.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a154fb0 and 2de13c1.

📒 Files selected for processing (2)
  • website/app.js (2 hunks)
  • website/modules/asset/ui/src/js/formValidation.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/app.js
🧰 Additional context used
🪛 Biome (1.9.4)
website/modules/asset/ui/src/js/formValidation.js

[error] 124-124: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e-tests
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: security-scan

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 15, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
website/modules/asset/ui/src/js/formValidation.js (1)

162-167: ⚠️ Potential issue

Still parsing response.json() without checking response.ok
This was flagged in a previous review and is unresolved.

Server errors (4xx / 5xx) or non-JSON responses will explode here, forcing the chain into a generic catch with no context. Guard first:

-return response
-  .json()
-  .then((data) => onHandleServerResponse(data, form))
-  .catch(() => false);
+if (!response.ok) {
+  return false;
+}
+return response
+  .json()
+  .then((data) => onHandleServerResponse(data, form))
+  .catch(() => false);
🧹 Nitpick comments (2)
website/modules/asset/ui/src/js/formValidation.js (2)

112-125: Nit – simplify with optional chaining & early return

The triple condition can be shortened and avoids false negatives when whitespace is the only content.

-    const error = field
-      .closest('.sf-field')
-      ?.querySelector('.validation-error');
-    if (error && error.textContent && error.textContent.trim() !== '') {
+    const error = field
+      .closest('.sf-field')
+      ?.querySelector('.validation-error');
+    if (error?.textContent?.trim()) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 119-119: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


185-190: Prevent double-submits by disabling the form while pending

Because handleFormSubmit is async but does not block the UI, rapid clicks can fire multiple simultaneous requests. Disable the submit button(s) until the promise settles to avoid duplicate submissions.

Example approach:

const buttons = form.querySelectorAll('[type="submit"]');
buttons.forEach((b) => (b.disabled = true));

validateForm(...)
  .then(...)
  .finally(() => buttons.forEach((b) => (b.disabled = false)));
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2de13c1 and 89a1f29.

📒 Files selected for processing (1)
  • website/modules/asset/ui/src/js/formValidation.js (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
website/modules/asset/ui/src/js/formValidation.js (3)
website/modules/asset/ui/src/js/domHelpers.js (4)
  • form (45-45)
  • form (54-54)
  • errorMessage (47-47)
  • errorMessage (56-56)
website/modules/asset/ui/src/js/formValidator.js (1)
  • form (11-11)
website/modules/asset/ui/src/js/formValidation.test.js (2)
  • form (12-12)
  • errorMessage (14-14)
🪛 Biome (1.9.4)
website/modules/asset/ui/src/js/formValidation.js

[error] 119-119: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: e2e-tests
  • GitHub Check: security-scan
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: Analyze (javascript-typescript)

Comment thread website/modules/asset/ui/src/js/formValidation.js
Comment thread website/modules/asset/ui/src/js/formValidation.js Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 16, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
website/modules/asset/ui/src/js/formValidation.js (1)

185-208: ⚠️ Potential issue

File / complex-value inputs are silently discarded – keep FormData all the way

sendFormData converts FormData → plain object → JSON.stringify.
File, Blob, and even Date objects become {} (or [object File]), so uploads or rich values never reach the server.

-const sendFormData = (form, formData) => {
-  // Convert FormData to a plain object for the server
-  const data = {};
-  for (const [key, value] of formData.entries()) {
-    if (key in data) {
-      data[key] = [].concat(data[key], value);
-    } else {
-      data[key] = value;
-    }
-  }
-
-  return fetch(form.action, {
-    method: 'POST',
-    body: JSON.stringify({ data }),
-    headers: {
-      'Content-Type': 'application/json',
-      'Accept': 'application/json',
-      'CSRF-Token':
-        document
-          .querySelector('meta[name="csrf-token"]')
-          ?.getAttribute('content') || '',
-    },
-    credentials: 'same-origin',
-  });
-};
+const sendFormData = (form, formData) =>
+  fetch(form.action, {
+    method: 'POST',
+    body: formData, // let the browser set multipart boundary
+    headers: {
+      'Accept': 'application/json',
+      'CSRF-Token':
+        document
+          .querySelector('meta[name="csrf-token"]')
+          ?.getAttribute('content') || '',
+    },
+    credentials: 'same-origin',
+  });

Keeps files intact, removes a needless loop, and shrinks payload construction.
Server already expects multipart/form-data per previous backend change notes.
[FYI: the earlier review comment on this exact issue is still outstanding.]

🧹 Nitpick comments (2)
website/modules/asset/ui/src/js/formValidation.js (2)

62-66: Skip disabled fields during form-wide validation

Disabled controls are non-submittable and shouldn’t block form submission.
Consider:

-  const fields = form.querySelectorAll(
-    'input:not([type="submit"]):not([type="button"]):not([type="hidden"]), textarea, select',
-  );
+  const fields = form.querySelectorAll(
+    'input:not([type="submit"]):not([type="button"]):not([type="hidden"]):not(:disabled), textarea:not(:disabled), select:not(:disabled)',
+  );

125-132: Log swallowed network errors for easier debugging

The catch block now shows a UI message (good) but still drops the actual error.
Add a console log so failures aren’t invisible in DevTools:

-  .catch(() => {
+  .catch((err) => {
+    /* eslint-disable no-console */
+    console.error('Form submission failed', err);
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 89a1f29 and 3538468.

📒 Files selected for processing (2)
  • website/modules/@apostrophecms/form-widget/views/widget.html (3 hunks)
  • website/modules/asset/ui/src/js/formValidation.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/modules/@apostrophecms/form-widget/views/widget.html
🧰 Additional context used
🪛 Biome (1.9.4)
website/modules/asset/ui/src/js/formValidation.js

[error] 158-158: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: e2e-tests
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: security-scan
🔇 Additional comments (1)
website/modules/asset/ui/src/js/formValidation.js (1)

166-183: response.json() will throw on empty 204/205 responses

Calling response.json() unconditionally after a successful status will reject
for empty bodies, forcing the .catch() path and showing a generic error.

Guard for 204/205 or zero content-length:

   if (!response.ok) {
     …
   }
-  return response.json().then((data) => onHandleServerResponse(data, form));
+  if (response.status === 204 || response.headers.get('content-length') === '0') {
+    return onHandleServerResponse({}, form);
+  }
+  return response.json().then((data) => onHandleServerResponse(data, form));

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 16, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
website/modules/asset/ui/src/js/formValidation.js (1)

99-115: ⚠️ Potential issue

File / complex-field values still lost – stop converting FormData to JSON

Previous feedback highlighted that stringifying a File, Blob, or multi-value field turns it into [object File]/{} and breaks uploads.
collectFormData (line 99) now returns native FormData, but sendFormData (lines 186-208) immediately flattens it back to a plain object and sends JSON, re-introducing the same problem.

-const formData = collectFormData(form);
-...
-return fetch(form.action, {
-  method: 'POST',
-  body: JSON.stringify({ data }),
-  headers: {
-    'Content-Type': 'application/json',
-    ...
-  },
-  credentials: 'same-origin',
-});
+const formData = collectFormData(form);
+
+return fetch(form.action, {
+  method: 'POST',
+  body: formData,              // let the browser set multipart boundary
+  headers: {
+    'Accept': 'application/json',
+    'CSRF-Token':
+      document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '',
+  },
+  credentials: 'same-origin',
+});

This keeps files intact, handles duplicate field names natively, and removes the fragile manual loop.

Also applies to: 185-208

🧹 Nitpick comments (4)
website/modules/asset/ui/src/js/formValidation.js (4)

166-183: Guard against 204 / empty JSON responses

response.json() will throw on a 204 No Content or on responses without a valid JSON body, pushing the flow into the generic catch and hiding the real status. Check for a body before parsing:

-  return response.json().then((data) => onHandleServerResponse(data, form));
+  if (response.status === 204) {
+    return onHandleServerResponse({}, form);
+  }
+
+  return response
+    .text()
+    .then((txt) => (txt ? JSON.parse(txt) : {}))
+    .then((data) => onHandleServerResponse(data, form));

148-156: thankYou selector is global – breaks with multiple forms

document.querySelector('[data-apos-form-thank-you]') always picks the first matching element.
If the page hosts more than one form, only the first “thank-you” banner will be shown/hidden.

Consider scoping the search to the current form container:

-const thankYou = document.querySelector('[data-apos-form-thank-you]');
+const thankYou = form.closest('[data-apos-form-wrapper]')?.querySelector('[data-apos-form-thank-you]');

62-66: Skip disabled fields during validation

Disabled inputs are currently included in fields, wasting cycles and potentially flagging irrelevant errors.

-'input:not([type="submit"]):not([type="button"]):not([type="hidden"]), textarea, select'
+'input:not([type="submit"]):not([type="button"]):not([type="hidden"]):not([disabled]), textarea:not([disabled]), select:not([disabled])'

118-133: Log submission failures for easier debugging

The catch block shows a user-facing message but discards the actual error object. A console log (behind eslint-disable no-console) keeps dev insight without affecting UX.

-.catch(() => {
+.catch((err) => {
+  /* eslint-disable no-console */
+  console.error('Form submission failed:', err);
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3538468 and 2295135.

📒 Files selected for processing (1)
  • website/modules/asset/ui/src/js/formValidation.js (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: lint
  • GitHub Check: e2e-tests
  • GitHub Check: unit-tests
  • GitHub Check: security-scan

@sonarqubecloud

Copy link
Copy Markdown

@VitalyyP VitalyyP changed the title Fix form client validation and cleanup modules [659] Fix form client validation and cleanup modules Jun 16, 2025

@yuramax yuramax left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM! 👍

@IhorMasechko IhorMasechko left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@yuramax yuramax assigned VitalyyP and unassigned VitalyyP Jun 16, 2025
@VitalyyP VitalyyP changed the title [659] Fix form client validation and cleanup modules [659] Fix form client validation Jun 16, 2025
@VitalyyP
VitalyyP enabled auto-merge (squash) June 16, 2025 11:50
@VitalyyP VitalyyP changed the title [659] Fix form client validation Fix form client validation Jun 18, 2025
@VitalyyP
VitalyyP requested review from IhorMasechko and yuramax and removed request for Anton-88, IhorMasechko and yuramax July 1, 2025 07:58
@Anton-88 Anton-88 closed this Jul 2, 2025
auto-merge was automatically disabled July 2, 2025 09:45

Pull request was closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants