Skip to content

feat: login required functionality v1#9

Merged
harshtandiya merged 5 commits into
developfrom
feat/form-settings
Jan 2, 2026
Merged

feat: login required functionality v1#9
harshtandiya merged 5 commits into
developfrom
feat/form-settings

Conversation

@harshtandiya
Copy link
Copy Markdown
Collaborator

@harshtandiya harshtandiya commented Jan 2, 2026

Summary by CodeRabbit

  • New Features

    • Login requirement check for forms and per-page login/logout UI with brand logo and session-aware header.
    • New header component added to submission pages and login redirect flow for protected forms.
  • Improvements

    • Form routing and navigation guards refined to handle guest access and redirects.
    • Stronger TypeScript typing across form fields and components; builder settings updated to sync login requirement with incomplete-form option.

✏️ Tip: You can customize this high-level summary in your review settings.

- Updated components to use TypeScript for better type safety.
- Refined form field type definitions and imports in RenderField.vue and FieldRenderer.vue.
- Added new properties to the Form interface for improved form management.
- Cleaned up unused functions and ensured consistent formatting across files.
- Added `is_login_required` function to check if login is required for a specific form.
- Updated router to enforce login checks before entering the form submission page.
- Enhanced `FormBuilderHeader` to construct submission page URLs correctly.
- Introduced utility function `isLoginRequired` for API calls related to login requirements.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 2, 2026

📝 Walkthrough

Walkthrough

Adds backend endpoints for login checks and brand logo; introduces a session-aware PageHeader; tightens TypeScript typings for forms and form fields; implements per-route login guards and router changes; updates form settings UI to sync login_required with allow_incomplete; several frontend components migrated/typed.

Changes

Cohort / File(s) Summary
Backend API Additions
forms_pro/api/form.py, forms_pro/api/settings.py
New public endpoints: is_login_required(route) returns a form's login_required flag; get_brand_logo() returns the app brand logo string.
Form Types & Field Types
frontend/src/types/form.ts, frontend/src/utils/form_fields.ts, frontend/components.d.ts
Switched Form from interface → type with new optional fields (route, is_published, allow_incomplete, linked_doctype, linked_team_id, login_required); added FormFieldType/FormFields types and typed all field definitions; added PageHeader global component declaration.
Routing & Guards
frontend/src/router.ts
Form route changed to /p/:route(.*); added per-route beforeEnter guard calling isLoginRequired; added meta.allowGuest and updated global guard to redirect to /login?redirect-to=... when required.
Frontend Utilities
frontend/src/utils/form.ts
Added isLoginRequired(route) utility that calls backend is_login_required API and returns boolean.
Session-aware Header & Page UI
frontend/src/components/submission/PageHeader.vue (new), frontend/src/components/submission/FormHeader.vue, frontend/src/pages/SubmissionPage.vue
New PageHeader: brand logo, login/logout UI, uses session and router for redirects; FormHeader simplified access to title/description; SubmissionPage renders PageHeader and updates branding link and footer styling.
Form Builder & Field Rendering
frontend/src/components/FormBuilderHeader.vue, frontend/src/components/RenderField.vue, frontend/src/components/builder/FieldRenderer.vue
FormBuilderHeader builds path from route record to avoid encoded params; RenderField migrated to TypeScript and uses explicit FormFieldType typing; FieldRenderer moved to TypeScript and removed unused code.
Form Settings UI
frontend/src/components/builder/sidebar/SettingsSection.vue
Added Tooltip and watcher to sync login_required with allow_incomplete; login_required checkbox disabled when allow_incomplete is true and tooltip explains behavior.
Store Changes
frontend/src/stores/editForm.ts
save() now submits the full formResource.value.doc as a single doc object; success/error handlers adjusted.

Sequence Diagram

sequenceDiagram
    participant User
    participant Router as Router & Guards
    participant Frontend as Frontend Page
    participant API as Backend API
    participant Session as Session Manager

    User->>Router: Navigate to /p/form-route
    Router->>API: request is_login_required(route)
    API-->>Router: { login_required: true/false }

    alt login_required && !Session.logged_in
        Router->>User: Redirect to /login?redirect-to=/p/form-route
    else
        Router->>Frontend: allow navigation / render page
        Frontend->>Session: check session state
        alt Session.logged_in
            Frontend-->>User: show avatar + logout option
            User->>Frontend: click logout
            Frontend->>Session: session.logout.submit()
        else
            Frontend-->>User: show Login button
            User->>Frontend: click Login
            Frontend->>User: redirect to /login?redirect-to=/p/form-route
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • feat: teams v1 #5 — touches the same Form field linked_team_id; likely related to adding that backend/doctypes support.

Poem

🐰✨ Hopping through routes and checks so bright,
A header that welcomes by day and night.
Types sharpened, guards in a row,
Logos gleam and sessions flow.
Forms now guard the paths they keep — hop, leap, and show!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature added: login required functionality. It covers the primary purpose of the changeset across both backend and frontend.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98ce49e and 919e5f2.

📒 Files selected for processing (4)
  • forms_pro/api/form.py
  • frontend/src/pages/SubmissionPage.vue
  • frontend/src/router.ts
  • frontend/src/utils/form.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • forms_pro/api/form.py
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/router.ts (2)
frontend/src/utils/form.ts (1)
  • isLoginRequired (10-20)
frontend/src/data/session.ts (1)
  • session (32-59)
⏰ 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). (1)
  • GitHub Check: Server
🔇 Additional comments (6)
frontend/src/pages/SubmissionPage.vue (3)

6-7: LGTM! Clean component imports.

The imports for Logo and PageHeader components are properly structured and align with the new header composition introduced in this PR.


15-15: LGTM! PageHeader integration.

The PageHeader component is correctly positioned at the top of the page, providing a consistent session-aware header across submission pages.


28-36: LGTM! Security fix applied.

The external link now includes rel="noopener noreferrer" (line 33), addressing the security concern from the previous review. The updated text color class and Logo component usage are also appropriate.

frontend/src/router.ts (3)

2-6: LGTM! Type safety improvements.

The addition of RouteRecordRaw type import and explicit typing of the routes array enhances type safety and aligns with TypeScript best practices.


31-43: Add error handling for the login requirement check.

The past issue regarding the missing return value has been fixed (lines 40, 42). However, the beforeEnter guard lacks error handling for when isLoginRequired fails or returns undefined. Currently, if the API call fails, the undefined result causes the guard to allow access (fail-open behavior).

🔎 Recommended improvement
 beforeEnter: async (to, from) => {
-  const loginRequired = await isLoginRequired(to.params.route as string);
+  try {
+    const loginRequired = await isLoginRequired(to.params.route as string);

-  if (loginRequired && !session.isLoggedIn) {
-    window.location.href = `/login?redirect-to=/forms${to.fullPath}`;
-    return false;
+    if (loginRequired && !session.isLoggedIn) {
+      window.location.href = `/login?redirect-to=/forms${to.fullPath}`;
+      return false;
+    }
+    return true;
+  } catch (error) {
+    console.error("Error checking login requirement:", error);
+    // Fail-open: allow access on error, or fail-closed: redirect to login
+    return true;
   }
-  return true;
 },

Note: This depends on fixing the error handling in isLoginRequired (frontend/src/utils/form.ts) itself.


62-66: LGTM! Global guard respects guest access.

The updated global navigation guard correctly checks to.meta.allowGuest !== true to allow navigation on routes that permit guest access, aligning with the new login-required functionality.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

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

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/utils/form_fields.ts (1)

147-195: Function can return undefined for unknown field types.

The return type is string, but indexing FIELD_TYPE_MAP with an unknown key returns undefined. This could cause issues downstream when the mapped field type is used.

🔎 Proposed fix with fallback
 export const mapDoctypeFieldForForm = (fieldtype: string): string => {
   const FIELD_TYPE_MAP = {
     // ... existing mappings
   };

-  return FIELD_TYPE_MAP[fieldtype as keyof typeof FIELD_TYPE_MAP];
+  return FIELD_TYPE_MAP[fieldtype as keyof typeof FIELD_TYPE_MAP] ?? "Data";
 };

Alternatively, update the return type to string | undefined and handle it at call sites.

🧹 Nitpick comments (2)
frontend/src/components/builder/FieldRenderer.vue (1)

112-112: Replace any type with proper type inference.

The explicit any type annotation bypasses TypeScript's type checking. Consider either removing the type annotation to allow TypeScript to infer the type, or using a more specific type based on the field data structure.

🔎 Suggested improvement
-                @change="(value: any) => (modelValue = value)"
+                @change="(value) => (modelValue = value)"

Or define a proper type if the inferred type is too broad.

frontend/src/components/builder/sidebar/SettingsSection.vue (1)

71-98: Consider UX implications of automatic restoration.

When allow_incomplete is toggled from false → true → false, login_required is restored to originalFormData.login_required. This means any manual changes to login_required made while allow_incomplete was false will be lost. This might be unexpected for users who adjust login_required before enabling incomplete forms.

Suggested behavior: Consider preserving the user's manual changes to login_required when they were made before allow_incomplete was enabled.

🔎 Alternative implementation
+// Track the login_required state before allow_incomplete was enabled
+const loginRequiredBeforeIncomplete = ref(null);

 watch(
     () => editFormStore.formData.allow_incomplete,
     (newVal) => {
         if (newVal) {
+            // Save current state before forcing true
+            loginRequiredBeforeIncomplete.value = editFormStore.formData.login_required;
             editFormStore.formData.login_required = true;
         }
         if (!newVal) {
-            editFormStore.formData.login_required = editFormStore.originalFormData.login_required;
+            // Restore to the state before incomplete was enabled, if available
+            if (loginRequiredBeforeIncomplete.value !== null) {
+                editFormStore.formData.login_required = loginRequiredBeforeIncomplete.value;
+                loginRequiredBeforeIncomplete.value = null;
+            }
         }
     }
 );
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9998a0 and 98ce49e.

📒 Files selected for processing (15)
  • forms_pro/api/form.py
  • forms_pro/api/settings.py
  • frontend/components.d.ts
  • frontend/src/components/FormBuilderHeader.vue
  • frontend/src/components/RenderField.vue
  • frontend/src/components/builder/FieldRenderer.vue
  • frontend/src/components/builder/sidebar/SettingsSection.vue
  • frontend/src/components/submission/FormHeader.vue
  • frontend/src/components/submission/PageHeader.vue
  • frontend/src/pages/SubmissionPage.vue
  • frontend/src/router.ts
  • frontend/src/stores/editForm.ts
  • frontend/src/types/form.ts
  • frontend/src/utils/form.ts
  • frontend/src/utils/form_fields.ts
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/src/types/form.ts (1)
frontend/src/types/formfield.ts (1)
  • FormField (1-10)
frontend/src/router.ts (2)
frontend/src/utils/form.ts (1)
  • isLoginRequired (10-20)
frontend/src/data/session.ts (1)
  • session (32-59)
⏰ 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: Frappe Linter
  • GitHub Check: Server
🔇 Additional comments (12)
frontend/src/components/builder/FieldRenderer.vue (1)

1-1: LGTM! TypeScript migration improves type safety.

The migration to TypeScript aligns with the broader typing improvements across the project.

frontend/components.d.ts (1)

25-25: LGTM! Component declaration added correctly.

The PageHeader component is now properly registered in the global component types, enabling TypeScript autocomplete and type checking.

frontend/src/components/builder/sidebar/SettingsSection.vue (1)

21-31: LGTM! Watcher correctly synchronizes login and incomplete form settings.

The watcher ensures that when incomplete forms are allowed, login is required, which is a sensible security constraint. The restoration to originalFormData.login_required when incomplete forms are disabled maintains the original setting.

forms_pro/api/settings.py (1)

5-13: LGTM! Guest access is appropriate for public form branding.

The function correctly allows guest access for retrieving the brand logo, which is necessary for public form submission pages. The str() wrapper ensures type safety.

frontend/src/pages/SubmissionPage.vue (2)

6-7: LGTM!

The PageHeader component integration is clean and follows Vue 3 composition API patterns.

Also applies to: 15-15


28-28: No action needed—the custom color class is defined in the Frappe UI preset.

The text-ink-gray-8 class is not a custom class that needs to be added to your local Tailwind configuration. It is already provided by the frappe-ui preset imported in tailwind.config.ts. Frappe UI includes an ink-gray color palette with multiple shades (ink-gray-4, ink-gray-5, ink-gray-6, ink-gray-8, etc.) as part of its preset, and these classes are available automatically.

frontend/src/components/FormBuilderHeader.vue (1)

12-29: Route name is correctly matched to router configuration.

The hardcoded route name "Form Submission Page" is confirmed to exist in router.ts (line 32) and matches the route definition.

frontend/src/stores/editForm.ts (1)

101-110: LGTM! Clean refactor of the save submission.

The change to submit the entire formResource.value.doc simplifies the code. The success and error handling callbacks are appropriately structured.

Note that togglePublish (lines 125-141) still uses partial object submission ({ is_published: ... }). This is fine since it only needs to update a single field, but worth being aware of the intentional difference in patterns.

frontend/src/types/form.ts (1)

3-14: Good type improvements.

The removal of the index signature ([key: string]: any) and addition of explicit optional fields improves type safety. The new fields (route, is_published, allow_incomplete, linked_doctype, linked_team_id, login_required) properly model the form configuration options needed for this feature.

frontend/src/router.ts (1)

31-34: Route pattern and guest meta look good.

The (.*) pattern allows multi-segment form routes (e.g., /p/org/form-name), and allowGuest: true correctly marks this route for the global guard logic.

frontend/src/utils/form_fields.ts (2)

18-25: Well-structured type definitions.

The FormFieldType and FormFields types provide good type safety. The separation allows reuse of field definitions (like DataField) while FormFields adds the name property for the lookup array.


130-145: Clean array construction.

Using the spread operator with named field constants keeps the code DRY and maintainable.

Comment thread forms_pro/api/form.py
Comment on lines +20 to +36
@frappe.whitelist(allow_guest=True)
def is_login_required(route: str) -> bool:
"""
Check if login is enabled for a form.

args:
form_id: str - The ID of the form to check.

returns:
bool - True if login is required, False otherwise.
"""
login_enabled = frappe.db.get_value(
doctype="Form",
filters={"route": route},
fieldname="login_required",
)
return bool(login_enabled)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix docstring parameter name and verify None handling.

Two concerns:

  1. Documentation error: The docstring references form_id in the args section, but the parameter is named route.
  2. Silent failure for non-existent routes: When frappe.db.get_value returns None (route doesn't exist), bool(None) returns False, making non-existent forms appear as "login not required". Consider if this is the desired behavior or if you should explicitly handle the non-existent route case.
🔎 Proposed fix for docstring
     """
     Check if login is enabled for a form.
 
     args:
-        form_id: str - The ID of the form to check.
+        route: str - The route of the form to check.
 
     returns:
         bool - True if login is required, False otherwise.
     """
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@frappe.whitelist(allow_guest=True)
def is_login_required(route: str) -> bool:
"""
Check if login is enabled for a form.
args:
form_id: str - The ID of the form to check.
returns:
bool - True if login is required, False otherwise.
"""
login_enabled = frappe.db.get_value(
doctype="Form",
filters={"route": route},
fieldname="login_required",
)
return bool(login_enabled)
@frappe.whitelist(allow_guest=True)
def is_login_required(route: str) -> bool:
"""
Check if login is enabled for a form.
args:
route: str - The route of the form to check.
returns:
bool - True if login is required, False otherwise.
"""
login_enabled = frappe.db.get_value(
doctype="Form",
filters={"route": route},
fieldname="login_required",
)
return bool(login_enabled)
🤖 Prompt for AI Agents
In forms_pro/api/form.py around lines 20 to 36, fix the docstring to reference
the actual parameter name "route" and correct the returns description, and add
explicit handling for when frappe.db.get_value returns None (non-existent route)
instead of silently treating it as False; if login_enabled is None raise a clear
exception (e.g. frappe.DoesNotExistError or frappe.throw with a descriptive
message) so callers know the route was not found, otherwise return
bool(login_enabled).

Comment thread forms_pro/api/settings.py
Comment on lines +1 to +13
import frappe
from frappe.core.doctype.navbar_settings.navbar_settings import get_app_logo


@frappe.whitelist(allow_guest=True)
def get_brand_logo() -> str:
"""
Get the brand logo for the form.

Returns:
str: The brand logo of the website or the default app logo if brand logo is not set.
"""
return str(get_app_logo())
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the get_app_logo function definition in the Frappe codebase
find . -type f -name "*.py" | head -20

Repository: BuildWithHussain/forms_pro

Length of output: 917


🏁 Script executed:

# Search for get_app_logo function definition
rg -n "def get_app_logo" --type=py -A 15

Repository: BuildWithHussain/forms_pro

Length of output: 52


🏁 Script executed:

# Search for imports of get_app_logo and usage patterns
rg -n "get_app_logo" --type=py | head -30

Repository: BuildWithHussain/forms_pro

Length of output: 234


🌐 Web query:

Frappe get_app_logo function guest context allow_guest

💡 Result:

Short answer — use website context or a guest-allowed endpoint.

Steps:

  1. For static/logo values, set them via hooks (website_context) or implement update_website_context to add logo paths (this is available to website pages, including Guest). Example in hooks.py:

    • website_context = {"favicon": "/assets/your_app/img/favicon.png", "splash_image": "/files/your_logo.png"}
    • or implement update_website_context = "your_app.overrides.website_context" and set context["brand_html"] / context["banner_image"]. [1]
  2. If you need to call a Python method from client-side code to return the app logo, expose that method with @frappe.whitelist(allow_guest=True) so Guest can call it. Note: allow_guest=True only lets the Guest call the method — it does not bypass permission checks inside the method, so ensure you only access data that guests may read. [2][3]

References:

  • website_context / update_website_context (hooks) documentation. [1]
  • @frappe.whitelist(allow_guest=True) and guest-method behavior / forum guidance. [2][3]

If you want, tell me whether you need an example update_website_context implementation or a whitelisted method snippet.


🌐 Web query:

frappe.core.doctype.navbar_settings get_app_logo source code

💡 Result:

The function is implemented in the Navbar Settings DocType class at:
frappe/core/doctype/navbar_settings/navbar_settings.py — method get_app_logo (i.e. frappe.core.doctype.navbar_settings.navbar_settings.get_app_logo). See the Frappe repo and endpoint listing for reference. [1][2]

Sources:

  • Frappe GitHub repository (code tree root). [1]
  • Whitelisted endpoints listing showing the exact import path. [2]

🌐 Web query:

site:github.com frappe get_app_logo implementation navbar_settings

💡 Result:

I searched GitHub for Frappe references to get_app_logo and navbar/navbar_settings. Relevant repo issues and threads discussing navbar/app logo behavior and Website Settings include:

  • "Website Settings > Login Page > 'App Logo' doesn't change the App Logo" (frappe/frappe). [1]
  • "App logo Not changing after changing navbar logo" (frappe/erpnext). [2]
  • Example traceback referencing navbar/header image usage in ERPNext templates (frappe/erpnext). [3]

If you want, I can (a) search for the exact function/implementation file that computes/returns the app logo within the Frappe codebase, or (b) open the specific files in the frappe/erpnext repos to locate where navbar_settings or get_app_logo are implemented. Which would you like next?


🏁 Script executed:

# Try to find if get_app_logo is documented in Frappe or if there's any error handling pattern
rg -i "get_app_logo|navbar_settings" --type=py

Repository: BuildWithHussain/forms_pro

Length of output: 229


🌐 Web query:

frappe navbar_settings.py get_app_logo def source code implementation

💡 Result:

I couldn't find a definitive copy of navbar_settings.py/get_app_logo across public Frappe sources. Which Frappe version or repository (GitHub URL or your site) should I look in? I can fetch and paste the exact function once you point me to the correct branch/repo/version.


🌐 Web query:

"def get_app_logo" frappe source

💡 Result:

I couldn't find a function named def get_app_logo in the Frappe codebase. Frappe exposes app/logo via hooks and website settings instead — e.g. the login page uses frappe.get_website_settings("app_logo") or the hooks value app_logo_url (frappe.get_hooks("app_logo_url")[-1]). See the hooks docs and the forum discussion for the code references. [1][2]

Sources:

  • Frappe hooks documentation (lists app_logo_url hook). [1]
  • Forum snippet showing login/signup using frappe.get_website_settings("app_logo") or frappe.get_hooks("app_logo_url")[-1]. [2]

🏁 Script executed:

# Look for test files that might exercise this code
find . -name "*test*.py" | xargs grep -l "get_brand_logo\|settings" 2>/dev/null | head -10

Repository: BuildWithHussain/forms_pro

Length of output: 52


🏁 Script executed:

# Check if there are any requirements or setup files specifying Frappe version
find . -name "requirements.txt" -o -name "setup.py" -o -name "pyproject.toml" | xargs cat 2>/dev/null

Repository: BuildWithHussain/forms_pro

Length of output: 1103


🏁 Script executed:

# Search for any error handling or try-catch around the get_app_logo import
rg -B5 -A5 "get_app_logo" --type=py

Repository: BuildWithHussain/forms_pro

Length of output: 756


Verify get_app_logo() exists and add error handling for guest context.

The web search could not find get_app_logo() in the Frappe codebase—Frappe typically uses hooks (app_logo_url) or website_settings("app_logo") instead. Even if the function exists, @frappe.whitelist(allow_guest=True) does not bypass permission checks inside the called function, so verify it works safely with guest users. Additionally, the function call lacks any try-catch block to handle potential exceptions when accessed in a guest context.

Confirm the import path and add error handling:

@frappe.whitelist(allow_guest=True)
def get_brand_logo() -> str:
    """
    Get the brand logo for the form.

    Returns:
        str: The brand logo of the website or the default app logo if brand logo is not set.
    """
    try:
        return str(get_app_logo())
    except Exception as e:
        # Return a fallback or log the error
        frappe.logger().warning(f"Failed to get app logo: {e}")
        return ""
🤖 Prompt for AI Agents
In forms_pro/api/settings.py around lines 1-13, verify that get_app_logo is a
valid import from frappe (if not, use the standard website settings/app_logo
hook such as website_settings("app_logo") or app_logo_url) and make the function
safe for guest access by wrapping the call in a try/except: call the verified
logo getter inside try, log any exception with frappe.logger().warning including
the exception details, and return a safe fallback (empty string or configured
default) on error so guest requests never raise; ensure no privileged APIs are
invoked that require authentication.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It exists in frappe's codebase

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines 13 to 17
const getComponent = computed(() => {
return formFields.find((field) => field.name === props.field.fieldtype);
});

const getBinds = computed(() => {
return {
...props.field,
...props.field.options,
...props.field.default,
};
return formFields.find(
(field: FormFields) => field.name === props.field.fieldtype
) as FormFieldType;
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential runtime error when field type is not found.

formFields.find() returns undefined if no matching field type exists. The cast to FormFieldType silences the TypeScript error but doesn't prevent the runtime crash when accessing getComponent.component in the template.

🔎 Proposed fix with fallback handling
 const getComponent = computed(() => {
-    return formFields.find(
+    const found = formFields.find(
         (field: FormFields) => field.name === props.field.fieldtype
-    ) as FormFieldType;
+    );
+    if (!found) {
+        console.warn(`Unknown field type: ${props.field.fieldtype}`);
+        return DataField; // fallback to DataField
+    }
+    return found;
 });

You'll need to import DataField from @/utils/form_fields as the fallback.

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

🤖 Prompt for AI Agents
In frontend/src/components/RenderField.vue around lines 13 to 17, getComponent
currently casts the result of formFields.find(...) to FormFieldType which can be
undefined at runtime; update the computed to import DataField from
"@/utils/form_fields" and use it as a safe fallback when find returns undefined
(i.e., return the found FormFieldType or DataField), removing the unsafe cast so
the template can always access getComponent.component without crashing.

Comment on lines 11 to 18
<div v-if="submissionFormStore.formResource.data" class="flex flex-col gap-4 text-gray-800">
<h1 class="text-3xl font-bold">
{{ submissionFormStore.formResource.data?.title ?? "" }}
{{ submissionFormStore.formResource.data.title }}
</h1>
<div
v-html="submissionFormStore.formResource.data?.description"
class="form-description"
v-html="submissionFormStore.formResource.data.description"
class="form-description !px-0"
></div>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find the submission form store and formResource definition
fd -e ts -e vue -e js | head -20

# Search for formResource usage
rg -n 'formResource' --type vue --type ts -B2 -A2

# Look for the API endpoints
fd -name '*.py' | xargs grep -l 'form.*resource\|frappe.whitelist'

Repository: BuildWithHussain/forms_pro

Length of output: 1241


🏁 Script executed:

# Find all Vue and TypeScript files with formResource
rg 'formResource' --type-list | head

# Search for formResource in the codebase
rg 'formResource' -B2 -A2

# Find the submission form store
fd 'store|submission' --type f | grep -E '\.(ts|js|vue)$'

# Look for API endpoints
fd '\.py$' | xargs grep -l 'form' | head -20

Repository: BuildWithHussain/forms_pro

Length of output: 17886


🏁 Script executed:

# Check the API implementation for get_form_by_route
cat frontend/src/stores/submissionForm.ts | head -50

# Look at the form.py API
cat forms_pro/api/form.py

# Check the Form doctype definition
fd 'form.json' | head -5

Repository: BuildWithHussain/forms_pro

Length of output: 5302


🏁 Script executed:

# Read the Form doctype JSON
cat forms_pro/forms_pro/doctype/form/form.json | grep -A10 -B2 '"fieldname": "title"' | head -20

# Also check for description field
cat forms_pro/forms_pro/doctype/form/form.json | grep -A10 -B2 '"fieldname": "description"' | head -20

# Get file size first to decide how to read it
wc -l forms_pro/forms_pro/doctype/form/form.json

Repository: BuildWithHussain/forms_pro

Length of output: 549


Add optional chaining for the description property.

The title field is required in the Form doctype, but description is optional. Accessing formResource.data.description directly without optional chaining will cause issues if the API returns an undefined value. Use formResource.data.description?. or add a fallback value.

🤖 Prompt for AI Agents
In frontend/src/components/submission/FormHeader.vue around lines 11 to 18, the
template binds submissionFormStore.formResource.data.description directly but
description is optional; update the v-html binding to use optional chaining or a
safe fallback (e.g.,
submissionFormStore.formResource.data.description?.toString() or
submissionFormStore.formResource.data.description ?? '') so that undefined
descriptions do not throw errors and the template renders safely.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

not required

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@harshtandiya, understood. I'll note your decision on this.

Comment on lines +8 to +11
const brandLogo = createResource({
url: "forms_pro.api.settings.get_brand_logo",
auto: true,
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add error handling and loading state for brand logo.

The brand logo is rendered directly without handling loading or error states. If brandLogo.data is undefined (during loading or on error), the img tag will have a broken src attribute.

🔎 Proposed improvements
 <template>
     <div class="max-w-screen-md mx-auto flex justify-between items-center">
-        <img :src="brandLogo.data" alt="Brand Logo" class="w-10 h-10" />
+        <img 
+            v-if="brandLogo.data" 
+            :src="brandLogo.data" 
+            alt="Brand Logo" 
+            class="w-10 h-10" 
+        />
+        <div v-else class="w-10 h-10 bg-gray-200 rounded animate-pulse"></div>
         <div>

Also applies to: 19-19

🤖 Prompt for AI Agents
In frontend/src/components/submission/PageHeader.vue around lines 8-11 and line
19, the brandLogo is used directly which can produce a broken img src when
brandLogo.data is undefined; update the template to conditionally render the
<img> only when brandLogo.data is truthy, show a loading skeleton or placeholder
while brandLogo.loading is true, and render a fallback/logo text when
brandLogo.error is set; additionally add an img @error handler to swap to the
fallback source or hide the image to ensure no broken src is displayed.

Comment on lines +13 to +15
function redirectToLogin() {
window.location.href = `/login?redirect-to=${route.fullPath}`;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

URL-encode the redirect path.

The route.fullPath should be URL-encoded when used as a query parameter to handle special characters correctly.

🔎 Proposed fix
 function redirectToLogin() {
-    window.location.href = `/login?redirect-to=${route.fullPath}`;
+    window.location.href = `/login?redirect-to=${encodeURIComponent(route.fullPath)}`;
 }
🤖 Prompt for AI Agents
In frontend/src/components/submission/PageHeader.vue around lines 13 to 15, the
redirect URL uses route.fullPath directly as a query value which can break with
special characters; fix by URL-encoding the path when constructing the query
(use encodeURIComponent(route.fullPath)) so the redirect-to parameter is safely
encoded before assigning window.location.href.

Comment thread frontend/src/pages/SubmissionPage.vue Outdated
Comment thread frontend/src/router.ts
Comment on lines +3 to +9
/**
* Check if login is required for a form submission page.
*
* @param formId - The ID of the form to check.
*
* @returns bool - True if login is required, False otherwise.
*/
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix JSDoc parameter name.

The JSDoc references formId but the parameter is named route.

🔎 Proposed fix
 /**
  * Check if login is required for a form submission page.
  *
- * @param formId - The ID of the form to check.
+ * @param route - The route of the form to check.
  *
  * @returns bool - True if login is required, False otherwise.
  */
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Check if login is required for a form submission page.
*
* @param formId - The ID of the form to check.
*
* @returns bool - True if login is required, False otherwise.
*/
/**
* Check if login is required for a form submission page.
*
* @param route - The route of the form to check.
*
* @returns bool - True if login is required, False otherwise.
*/
🤖 Prompt for AI Agents
In frontend/src/utils/form.ts around lines 3 to 9, the JSDoc incorrectly names
the parameter as "formId" while the actual function parameter is "route"; update
the JSDoc to reference "@param route" (and adjust the description to explain
that route is the form submission route or identifier expected by the function)
and ensure the "@returns" line uses correct casing/description (e.g., "boolean"
or "True if login is required, false otherwise") so the doc matches the function
signature and return value.

Comment on lines +10 to +20
export async function isLoginRequired(route: string) {
const loginRequired = useCall({
baseUrl: "/api/v2/method/",
url: "forms_pro.api.form.is_login_required",
params: { route },
immediate: false,
});

await loginRequired.execute();
return loginRequired.data;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add error handling and return type annotation.

The function lacks error handling for API failures and a TypeScript return type. If the API call fails, loginRequired.data may be undefined, leading to unexpected behavior.

🔎 Proposed improvements
-export async function isLoginRequired(route: string) {
+export async function isLoginRequired(route: string): Promise<boolean> {
   const loginRequired = useCall({
     baseUrl: "/api/v2/method/",
     url: "forms_pro.api.form.is_login_required",
     params: { route },
     immediate: false,
   });
 
   await loginRequired.execute();
+  
+  if (loginRequired.error) {
+    console.error("Failed to check login requirement:", loginRequired.error);
+    return false; // Or throw an error, depending on desired behavior
+  }
+  
   return loginRequired.data;
 }
🤖 Prompt for AI Agents
In frontend/src/utils/form.ts around lines 10 to 20, the isLoginRequired
function is missing a TypeScript return type and lacks error handling for failed
API calls; update the signature to return Promise<boolean>, wrap the API call in
try/catch, await loginRequired.execute() inside the try, read loginRequired.data
but guard against undefined (return a sensible default like false or rethrow a
wrapped error), and log or surface the caught error so callers receive a
deterministic boolean result instead of potential undefined.

@harshtandiya harshtandiya merged commit 5d79130 into develop Jan 2, 2026
4 checks passed
@harshtandiya harshtandiya deleted the feat/form-settings branch January 6, 2026 15:38
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.

1 participant