Skip to content

Feature: eForm auto add tickler window popup#2320

Draft
LiamStanziani wants to merge 9 commits intohotfix/01232026from
feat/eform-auto-add-tickler-window-popup
Draft

Feature: eForm auto add tickler window popup#2320
LiamStanziani wants to merge 9 commits intohotfix/01232026from
feat/eform-auto-add-tickler-window-popup

Conversation

@LiamStanziani
Copy link
Collaborator

@LiamStanziani LiamStanziani commented Mar 5, 2026

NOTE: These changes are a work in progress and will be updated overtime, manual review of the design and testing will need to be looked at for this feature.

Summary by Sourcery

Integrate tickler creation workflows into eForm toolbar actions, including auto-open and auto-save modes, and wire through supporting data and REST responses.

New Features:

  • Add tickler-aware wrapping of eForm toolbar actions (Save/Print/Download/Fax/Email/eDocument) with a single prompt per action chain when tickler integration tags are present.
  • Support tickler auto-open and auto-save modes for eForms, driven by hidden input configuration and contextual tickler data collected from the form.
  • Prefill the tickler message in ticklerAdd.jsp from an optional ticklerMessage request parameter to streamline tickler creation from eForms.

Bug Fixes:

  • Ensure jQuery UI dialog close buttons render correctly as an X despite Bootstrap CSS, and standardize dialog sizing for tickler-related popups.

Enhancements:

  • Return the created tickler ID in the addTickler REST response message field to enable deep-linking to the new tickler from client workflows.
  • Expose providerNo as a hidden field on eForm creation and display pages for use in tickler assignment defaults.

Summary by cubic

Adds tickler integration to eForms with optional auto-open or auto-save, supporting dynamic mode detection and accessible dialogs. Prompts before Save/Print/Download/Fax/Email/eDocument and links to the created tickler.

  • New Features

    • Wraps toolbar actions with a single prompt and supports auto-open (prefilled ticklerAdd.jsp) or auto-save (REST) flows with a “View” link on success.
    • Reads mode and data from hidden inputs at action time; includes providerNo from session; REST returns the tickler ID on success; ticklerAdd.jsp pre-fills the message.
  • Bug Fixes

    • Tri-state flow (“idle/inProgress/proceeding”) to handle chained actions, block inputs during dialogs, and reset state after proceed/cancel.
    • Fixed auto-save service date by sending local midnight with timezone offset.
    • Restored modal overlay visibility for dialogs to ensure proper focus; improved dialog UX and accessibility (styled close buttons, consistent sizing, clear popup-blocked message), and prevented parent reload in auto-open (updateParent=false, parentAjaxId).

Written for commit 3aad298. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

  • New Features

    • Integrated tickler functionality into eForm toolbar actions (save, print, download, fax, email, edocument) with interactive prompts and silent creation modes.
    • Added message pre-fill capability in tickler creation interface.
  • Improvements

    • Enhanced response data to include tickler identifiers.

@LiamStanziani LiamStanziani self-assigned this Mar 5, 2026
@sourcery-ai
Copy link

sourcery-ai bot commented Mar 5, 2026

Reviewer's Guide

Adds client-side tickler integration to the eForm floating toolbar, enabling optional popup-based or REST-based tickler creation around toolbar actions, wires it to backend tickler services, and supports pre-filling tickler messages and returning tickler IDs for linking.

Sequence diagram for eForm toolbar action with tickler autoOpen mode

sequenceDiagram
    actor User
    participant Browser_eForm as Browser_eForm
    participant eform_floating_toolbar_js as eform_floating_toolbar_js
    participant ticklerAdd_jsp as ticklerAdd_jsp

    User->>Browser_eForm: Click toolbar action (Save/Print/Download/Fax/Email/eDocument)
    Browser_eForm->>eform_floating_toolbar_js: Call wrapped remoteAction
    eform_floating_toolbar_js->>eform_floating_toolbar_js: hasTicklerTags() returns autoOpen
    eform_floating_toolbar_js->>eform_floating_toolbar_js: _ticklerHandled = true
    eform_floating_toolbar_js->>eform_floating_toolbar_js: promptTicklerAutoOpen(proceedCallback)
    eform_floating_toolbar_js->>Browser_eForm: Open ticklerConfirmDialog

    alt User chooses Yes
        User-->>Browser_eForm: Click Yes
        Browser_eForm->>eform_floating_toolbar_js: Confirm dialog Yes handler
        eform_floating_toolbar_js->>eform_floating_toolbar_js: collectTicklerData()
        eform_floating_toolbar_js->>ticklerAdd_jsp: window.open(ticklerAdd.jsp with query params)
        loop Poll popup
            eform_floating_toolbar_js->>ticklerAdd_jsp: Check popup.closed
        end
        eform_floating_toolbar_js->>Browser_eForm: Show ticklerProceedDialog
        alt User clicks Yes, proceed
            User-->>Browser_eForm: Yes, proceed
            Browser_eForm->>eform_floating_toolbar_js: Proceed dialog Yes handler
            eform_floating_toolbar_js->>Browser_eForm: Call original toolbar action
        else User clicks No, cancel
            User-->>Browser_eForm: No, cancel
            Browser_eForm->>eform_floating_toolbar_js: Proceed dialog Cancel handler
            eform_floating_toolbar_js->>eform_floating_toolbar_js: resetTicklerHandled()
        end
    else User chooses No
        User-->>Browser_eForm: Click No
        Browser_eForm->>eform_floating_toolbar_js: Confirm dialog No handler
        eform_floating_toolbar_js->>Browser_eForm: Call original toolbar action
        eform_floating_toolbar_js->>eform_floating_toolbar_js: resetTicklerHandled()
    end
Loading

Sequence diagram for eForm toolbar action with tickler autoSave mode

sequenceDiagram
    actor User
    participant Browser_eForm as Browser_eForm
    participant eform_floating_toolbar_js as eform_floating_toolbar_js
    participant TicklerREST as TicklerREST_ws_rs_tickler_add
    participant TicklerWebService as TicklerWebService
    participant TicklerManager as TicklerManager

    User->>Browser_eForm: Click toolbar action (Save/Print/Download/Fax/Email/eDocument)
    Browser_eForm->>eform_floating_toolbar_js: Call wrapped remoteAction
    eform_floating_toolbar_js->>eform_floating_toolbar_js: hasTicklerTags() returns autoSave
    eform_floating_toolbar_js->>eform_floating_toolbar_js: _ticklerHandled = true
    eform_floating_toolbar_js->>eform_floating_toolbar_js: promptTicklerAutoSave(proceedCallback)
    eform_floating_toolbar_js->>eform_floating_toolbar_js: collectTicklerData()
    eform_floating_toolbar_js->>TicklerREST: POST /ws/rs/tickler/add (JSON payload)
    TicklerREST->>TicklerWebService: addTickler(Tickler)
    TicklerWebService->>TicklerManager: addTickler(LoggedInInfo, Tickler)
    TicklerManager-->>TicklerWebService: success flag
    TicklerWebService->>TicklerWebService: set tickler.id
    TicklerWebService->>TicklerWebService: response.setSuccess(...)
    TicklerWebService->>TicklerWebService: response.setMessage(String.valueOf(tickler.id))
    TicklerWebService-->>TicklerREST: GenericRESTResponse(success, message=ticklerId)

    alt REST call success
        TicklerREST-->>eform_floating_toolbar_js: JSON with success true and ticklerId
        eform_floating_toolbar_js->>eform_floating_toolbar_js: Build ticklerEdit.jsp viewUrl
        eform_floating_toolbar_js->>Browser_eForm: Open ticklerAutoSaveSuccessDialog with View link
        User-->>Browser_eForm: Click OK
        Browser_eForm->>eform_floating_toolbar_js: Success dialog OK handler
        eform_floating_toolbar_js->>Browser_eForm: Call original toolbar action
    else REST call error or unsuccessful response
        TicklerREST-->>eform_floating_toolbar_js: HTTP error or success false
        eform_floating_toolbar_js->>Browser_eForm: Open ticklerAutoSaveErrorDialog(detail)
        alt User chooses OK (proceed anyway)
            User-->>Browser_eForm: OK (proceed anyway)
            Browser_eForm->>eform_floating_toolbar_js: Error dialog OK handler
            eform_floating_toolbar_js->>Browser_eForm: Call original toolbar action
        else User chooses Cancel
            User-->>Browser_eForm: Cancel
            Browser_eForm->>eform_floating_toolbar_js: Error dialog Cancel handler
            eform_floating_toolbar_js->>eform_floating_toolbar_js: resetTicklerHandled()
        end
    end
Loading

Class diagram for updated TicklerWebService addTickler behavior

classDiagram
    class TicklerWebService {
        +GenericRESTResponse addTickler(Tickler tickler)
    }

    class GenericRESTResponse {
        -boolean success
        -String message
        +void setSuccess(boolean success)
        +void setMessage(String message)
        +boolean isSuccess()
        +String getMessage()
    }

    class Tickler {
        -Long id
        -Integer demographicNo
        -String message
        -String taskAssignedTo
        -String priority
        -LocalDateTime serviceDate
        -String status
        +Long getId()
        +void setId(Long id)
        +Integer getDemographicNo()
        +void setDemographicNo(Integer demographicNo)
        +String getMessage()
        +void setMessage(String message)
        +String getTaskAssignedTo()
        +void setTaskAssignedTo(String taskAssignedTo)
        +String getPriority()
        +void setPriority(String priority)
        +LocalDateTime getServiceDate()
        +void setServiceDate(LocalDateTime serviceDate)
        +String getStatus()
        +void setStatus(String status)
    }

    class TicklerManager {
        +boolean addTickler(LoggedInInfo loggedInInfo, Tickler tickler)
    }

    TicklerWebService --> TicklerManager : uses
    TicklerWebService --> Tickler : parameter
    TicklerWebService --> GenericRESTResponse : returns
Loading

File-Level Changes

Change Details Files
Wrap eForm floating toolbar actions to optionally prompt for tickler creation before proceeding, supporting auto-open and auto-save modes with jQuery UI dialogs.
  • Detect tickler mode from hidden inputs and guard against existing setAtickler implementation before wrapping actions.
  • Introduce a wrapper around remoteSave/Print/Download/Fax/Email/eDocument that runs tickler prompts once per action chain, resetting state appropriately.
  • Implement auto-open flow that confirms with the user, opens ticklerAdd.jsp in a popup with pre-populated query params, then asks whether to proceed once the popup closes.
  • Implement auto-save flow that posts tickler data to the REST tickler add endpoint, shows success or error dialogs, and lets the user proceed or cancel based on outcome.
  • Create and initialize jQuery UI dialogs for confirm, proceed, success, and error, including styling the close button to render a visible X despite Bootstrap/jQuery UI conflicts.
src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js
Allow ticklerAdd.jsp to pre-populate the tickler message from a request parameter for use by the auto-open workflow.
  • Read ticklerMessage from the HTTP request, defaulting to an empty string when absent.
  • Render ticklerMessage into the tickler message textarea with proper HTML encoding to avoid injection issues.
src/main/webapp/tickler/ticklerAdd.jsp
Expose the newly created tickler ID from the REST addTickler endpoint so callers can link directly to the created tickler.
  • After successfully adding a tickler, set the REST response message to the stringified tickler ID.
src/main/java/ca/openosp/openo/webserv/rest/TicklerWebService.java
Pass the current provider number into eForms as a hidden field for use as the default tickler assignee.
  • In eForm creation view, add a hidden providerNo input populated from provider_no.
  • In eForm display view, add a hidden providerNo input populated from the logged-in provider number.
src/main/webapp/eform/efmformadd_data.jsp
src/main/webapp/eform/efmshowform_data.jsp

Possibly linked issues

  • #[Feature]: Add special eform fields to support opening the "add tickler" window automatically when submitting the eform: PR implements the requested eForm tickler tags, auto-open/auto-save behavior, and related backend/supporting changes.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@LiamStanziani LiamStanziani requested a review from Copilot March 5, 2026 18:07
@LiamStanziani
Copy link
Collaborator Author

@coderabbitai review

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant feature to automate tickler creation directly from eForms. It streamlines workflows by allowing eForms to be configured to either prompt the user to create a tickler via an interactive popup or silently create one using a REST API, based on predefined eForm tags. This enhancement aims to improve efficiency and ensure timely follow-ups related to eForm submissions.

Highlights

  • eForm Tickler Integration: Implemented a new eForm tickler integration feature, allowing for automatic tickler creation in two modes: interactive popup ('autoOpen') or silent REST creation ('autoSave').
  • Tickler ID in Response: Modified the 'TicklerWebService' to return the ID of a newly created tickler, enabling direct linking to the tickler from success messages.
  • Provider Number Integration: Integrated 'providerNo' into eForm data submission for both new form creation and display, ensuring relevant provider information is available for tickler assignment.
  • Toolbar Action Wrapping: Wrapped eForm floating toolbar actions (save, print, download, fax, email, edocument) to conditionally trigger tickler creation prompts based on eForm configuration.
  • jQuery UI Dialogs: Developed a suite of jQuery UI dialogs to manage user interaction during tickler creation, including confirmation, success, and error messages, and handling popup window lifecycles.
Changelog
  • src/main/java/ca/openosp/openo/webserv/rest/TicklerWebService.java
    • Added the ID of the newly created tickler to the success message of the addTickler response.
  • src/main/webapp/eform/efmformadd_data.jsp
    • Added providerNo as a hidden input element to the eForm.
  • src/main/webapp/eform/efmshowform_data.jsp
    • Added providerNo as a hidden input element to the eForm.
  • src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js
    • Implemented logic to detect ticklerAutoOpen and ticklerAutoSave tags within eForms.
    • Wrapped eForm toolbar actions (save, print, download, fax, email, edocument) to incorporate tickler creation workflows.
    • Added functions to collect tickler data from hidden input fields.
    • Created and initialized jQuery UI dialogs for tickler confirmation, auto-save success, auto-save error, and post-popup proceeding.
    • Developed promptTicklerAutoOpen to manage the interactive tickler popup flow, including opening ticklerAdd.jsp and polling for its closure.
    • Implemented promptTicklerAutoSave to handle silent tickler creation via a REST API call.
    • Included utility functions for styling jQuery UI dialog close buttons to resolve CSS conflicts.
  • src/main/webapp/tickler/ticklerAdd.jsp
    • Retrieved and initialized ticklerMessage from request parameters.
    • Pre-populated the tickler message textarea with the ticklerMessage parameter.
Activity
  • The pull request is marked as a work in progress, indicating ongoing development and refinement.
  • The author has requested manual review of the design and testing, in addition to AI reviews for implementation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@LiamStanziani
Copy link
Collaborator Author

@SourceryAI review

@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

Important

Review skipped

Draft detected.

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

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2c8a8458-5d60-4ea0-9213-b60ac26f725f

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/eform-auto-add-tickler-window-popup

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.

@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

📝 Walkthrough

Walkthrough

The pull request integrates tickler functionality into eForms by adding provider number tracking fields to form submissions, implementing a comprehensive tickler workflow in the toolbar that gates form actions behind optional tickler creation prompts, and enhancing the tickler response message with ticket identifiers.

Changes

Cohort / File(s) Summary
Backend API Response Enhancement
src/main/java/ca/openosp/openo/webserv/rest/TicklerWebService.java
Sets the response message to the tickler's ID after successful creation, providing feedback to the caller.
EForm Data Persistence
src/main/webapp/eform/efmformadd_data.jsp, src/main/webapp/eform/efmshowform_data.jsp
Adds hidden providerNo input fields to capture and submit provider information with EForm data.
Tickler Form Pre-population
src/main/webapp/tickler/ticklerAdd.jsp
Retrieves and HTML-encodes the ticklerMessage request parameter to pre-fill the tickler message textarea.
Tickler UI Integration
src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js
Introduces comprehensive tickler integration layer with 12 new functions that conditionally gate toolbar actions (save, print, download, fax, email, edocument) behind optional tickler creation prompts, supporting both interactive (autoOpen) and silent (autoSave) modes with multi-dialog workflows for confirmation, success, and error handling.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Toolbar as Floating Toolbar
    participant Dialog as Tickler Dialog
    participant API as Tickler REST API
    participant Action as Form Action

    User->>Toolbar: Click Save/Print/etc
    Toolbar->>Toolbar: Check hasTicklerTags()
    alt Has Tickler Tags
        Toolbar->>Dialog: Collect form data & open dialog
        alt AutoOpen Mode (Interactive)
            Dialog->>User: Display tickler confirmation
            User->>Dialog: Enter tickler details
            User->>Dialog: Submit
            Dialog->>API: POST tickler with form data
            API-->>Dialog: Success with tickler ID
            Dialog->>User: Show success message
            User->>Dialog: Proceed/View Tickler
        else AutoSave Mode (Silent)
            Dialog->>API: POST tickler silently
            API-->>Dialog: Success with tickler ID
            Dialog->>User: Notify creation (optional)
        end
        Dialog->>Action: Proceed with original action
    else No Tickler Tags
        Toolbar->>Action: Skip tickler flow
    end
    Action->>Action: Execute (Save/Print/Download/etc)
    Action-->>User: Complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • D3V41

Poem

🐰 A tickler's tale in forms so grand,
With hidden fields across the land,
Dialogs dance when actions flow,
Provider numbers steal the show!
wiggle nose

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main feature being added: automatic tickler window popup for eForms, which is the primary objective of this changeset.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/eform-auto-add-tickler-window-popup

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

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 4 issues, and left some high level feedback:

  • The tickler integration adds a lot of global functions and state onto window (e.g. resetTicklerHandled, _ticklerDialogButtonClicked, hasTicklerTags helpers) inside eform_floating_toolbar.js; consider encapsulating these under a single namespaced object or module to reduce risk of collisions with other scripts on the page.
  • In styleTicklerDialogCloseButton the comment says the close button is styled "with an X character" but the implementation only swaps the class to btn-close and removes contents; if Bootstrap-specific styling is relied on, this could render as an empty button in non-Bootstrap contexts—either add explicit text/aria-label or adjust the comment/implementation so they match.
  • The various dialog texts in initTicklerDialogs (proceed, success, error) are currently hardcoded; since ticklerPromptMessage is already configurable via a hidden field, you may want to make the other user-facing strings similarly configurable to better support localization and site-specific wording.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The tickler integration adds a lot of global functions and state onto `window` (e.g. `resetTicklerHandled`, `_ticklerDialogButtonClicked`, `hasTicklerTags` helpers) inside `eform_floating_toolbar.js`; consider encapsulating these under a single namespaced object or module to reduce risk of collisions with other scripts on the page.
- In `styleTicklerDialogCloseButton` the comment says the close button is styled "with an X character" but the implementation only swaps the class to `btn-close` and removes contents; if Bootstrap-specific styling is relied on, this could render as an empty button in non-Bootstrap contexts—either add explicit text/aria-label or adjust the comment/implementation so they match.
- The various dialog texts in `initTicklerDialogs` (proceed, success, error) are currently hardcoded; since `ticklerPromptMessage` is already configurable via a hidden field, you may want to make the other user-facing strings similarly configurable to better support localization and site-specific wording.

## Individual Comments

### Comment 1
<location path="src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js" line_range="49-58" />
<code_context>
+	if (ticklerMode) {
+		initTicklerDialogs();
+
+		// _ticklerHandled stays true during one action chain (e.g. Print→Save)
+		// so Save doesn't re-trigger the dialog when called internally by Print.
+		// resetTicklerHandled() clears it after the chain completes or is canceled.
+		var _ticklerHandled = false;
+		window.resetTicklerHandled = function() { _ticklerHandled = false; };
+
+		var _origSave = remoteSave;
+		var _origPrint = remotePrint;
+		var _origDownload = remoteDownload;
+		var _origFax = remoteFax;
+		var _origEmail = remoteEmail;
+		var _origEdocument = remoteEdocument;
+
+		function wrapWithTicklerCheck(originalFn) {
+			return function() {
+				if (_ticklerHandled) {
</code_context>
<issue_to_address>
**issue (bug_risk):** _ticklerHandled is never reset after a successful action chain, so future actions may skip tickler prompts unintentionally.

`resetTicklerHandled()` is only called on cancel/close (X/Escape), not on successful completion of the flow. In successful paths (e.g., auto-open Yes → popup → proceed, or auto-save success), `_ticklerHandled` stays `true`, so subsequent toolbar actions on the same page will skip tickler entirely. If the goal is “once per page load,” the code is correct but the comment should say that; if the goal is to skip tickler only for internal chained calls (e.g., Print → Save), you’ll need to reset the flag after the outermost operation completes (e.g., in `proceedCallback` or the success dialog OK handler).
</issue_to_address>

### Comment 2
<location path="src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js" line_range="705-706" />
<code_context>
+ * default icon sprite. Resolves the Bootstrap/jQuery UI CSS conflict where
+ * the close icon renders as an empty square.
+ */
+function styleTicklerDialogCloseButton(dialogSelector) {
+    jQuery(dialogSelector).on("dialogopen", function() {
+        var closeBtn = jQuery(this).parent().find(".ui-dialog-titlebar-close");
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Removing all classes from the dialog close button may interfere with jQuery UI styling/behavior.

`removeClass()` with no arguments removes all classes, including `ui-dialog-titlebar-close` and other jQuery UI hooks. This can break styling or other code that relies on those classes. Instead, only remove the icon-related classes and add the Bootstrap class, e.g. `closeBtn.removeClass('ui-icon ui-icon-closethick').addClass('btn-close');` so you resolve the icon conflict without dropping the dialog’s base classes.

```suggestion
        var closeBtn = jQuery(this).parent().find(".ui-dialog-titlebar-close");
        closeBtn
            .empty()
            .removeClass("ui-button-icon-only ui-button-icon ui-icon ui-icon-closethick")
            .addClass("btn-close")
            .css({
```
</issue_to_address>

### Comment 3
<location path="src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js" line_range="742" />
<code_context>
+ * opener window (which would destroy our poll timer and proceed callback).
+ * Polls for popup close, then shows the proceed dialog.
+ */
+function openTicklerPopup(proceedCallback) {
+    var data = collectTicklerData();
+    var contextPath = getTicklerFieldValue("context", "");
</code_context>
<issue_to_address>
**suggestion:** Popup-blocked scenario is treated as a closed popup, which can confuse users.

If `window.open` is blocked, `popup` is `null`, so the first poll treats this as a closed popup and shows the “tickler window has closed…” dialog even though it never opened. Consider checking `!popup` immediately after `window.open` and handling it separately (e.g., a specific popup-blocked message or going straight to `proceedCallback` without referencing a closed window).
</issue_to_address>

### Comment 4
<location path="src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js" line_range="44" />
<code_context>
 		showSuccessAlert(remoteClose);
 	}
+
+	// Tickler integration: wrap toolbar actions if eForm has tickler tags
+	var ticklerMode = hasTicklerTags();
+	if (ticklerMode) {
</code_context>
<issue_to_address>
**issue (complexity):** Consider encapsulating the tickler state and dialog behavior in a small controller and shared dialog helper to avoid scattered globals and repeated flag plumbing.

You can keep all existing behavior but reduce the mental overhead by encapsulating the tickler state and dialog wiring into a small controller, and by centralizing the repetitive dialog button/close logic.

### 1. Encapsulate `_ticklerHandled` & `_ticklerDialogButtonClicked`

Instead of exposing `resetTicklerHandled` and `_ticklerDialogButtonClicked` on `window`, keep them inside a controller and expose only the minimal API you actually need:

```js
// create once when ticklerMode is detected
var TicklerController = (function (ticklerMode) {
    var handled = false;
    var dialogButtonClicked = false;

    function resetHandled() {
        handled = false;
    }

    function markDialogButton() {
        dialogButtonClicked = true;
    }

    function onDialogClose() {
        if (!dialogButtonClicked) {
            resetHandled();
        }
        dialogButtonClicked = false;
    }

    function wrapWithGate(originalFn) {
        return function () {
            if (handled) return originalFn.apply(this, arguments);

            handled = true;
            var args = arguments, self = this;
            var proceed = function () { originalFn.apply(self, args); };

            if (ticklerMode === "autoOpen") {
                promptTicklerAutoOpen(proceed);
            } else if (ticklerMode === "autoSave") {
                promptTicklerAutoSave(proceed);
            }
        };
    }

    return {
        wrapWithGate: wrapWithGate,
        resetHandled: resetHandled,
        markDialogButton: markDialogButton,
        onDialogClose: onDialogClose
    };
}(ticklerMode));
```

Then replace the global usage:

```js
// instead of window.resetTicklerHandled / window._ticklerDialogButtonClicked
// wrap toolbar actions
window.remoteSave      = TicklerController.wrapWithGate(_origSave);
window.remotePrint     = TicklerController.wrapWithGate(_origPrint);
window.remoteDownload  = TicklerController.wrapWithGate(_origDownload);
window.remoteFax       = TicklerController.wrapWithGate(_origFax);
window.remoteEmail     = TicklerController.wrapWithGate(_origEmail);
window.remoteEdocument = TicklerController.wrapWithGate(_origEdocument);
```

…and in dialog-related code:

```js
// initTicklerDialogs
function initTicklerDialogs() {
    // ...
    jQuery("#ticklerConfirmDialog").dialog({
        autoOpen: false,
        modal: true,
        width: 420,
        buttons: {},
        close: TicklerController.onDialogClose
    });
    // same for other tickler dialogs
}
```

```js
// inside any button handler
"Yes": function() {
    TicklerController.markDialogButton();
    jQuery(this).dialog("close");
    // ...
}

// when you need to cancel the chain
"Cancel": function() {
    TicklerController.markDialogButton();
    jQuery(this).dialog("close");
    TicklerController.resetHandled();
}
```

This removes the cross‑cutting globals (`_ticklerHandled`, `resetTicklerHandled`, `_ticklerDialogButtonClicked`) and makes the tickler flow self-contained.

### 2. Centralize the repetitive dialog button pattern

Most dialog flows follow: set buttons → each button sets “button clicked” → close → optionally `proceedCallback()` or reset. You can centralize that:

```js
function openTicklerDialog(dialogId, buttonsConfig) {
    var mappedButtons = {};
    Object.keys(buttonsConfig).forEach(function (label) {
        mappedButtons[label] = function () {
            TicklerController.markDialogButton();
            jQuery(this).dialog("close");
            buttonsConfig[label]();   // delegate to caller-specific behavior
        };
    });
    jQuery(dialogId).dialog("option", "buttons", mappedButtons).dialog("open");
}
```

Then your specific flows collapse to the intent, without repeating the flag plumbing:

```js
function promptTicklerAutoOpen(proceedCallback) {
    openTicklerDialog("#ticklerConfirmDialog", {
        "Yes": function () { openTicklerPopup(proceedCallback); },
        "No": function () { proceedCallback(); TicklerController.resetHandled(); }
    });
}

function showProceedDialog(proceedCallback) {
    openTicklerDialog("#ticklerProceedDialog", {
        "Yes, proceed": function () { proceedCallback(); },
        "No, cancel": function () { TicklerController.resetHandled(); }
    });
}

function showTicklerError(detail, proceedCallback) {
    jQuery("#ticklerErrorDetail").text(detail);
    openTicklerDialog("#ticklerAutoSaveErrorDialog", {
        "OK (proceed anyway)": function () { proceedCallback(); },
        "Cancel": function () { TicklerController.resetHandled(); }
    });
}
```

This keeps all current behavior (including the “X/Escape cancels the chain” semantics) but:

- removes global flags,
- makes the state transitions explicit via `TicklerController`,
- and shrinks the duplicated dialog boilerplate into a single helper.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/main/webapp/eform/efmformadd_data.jsp (1)

148-152: Use the same provider source across eForm entry flows.

Line 148 uses provider_no, while Line 151 already resolves LoggedInInfo. Using loggedInInfo.getLoggedInProviderNo() for providerNo keeps behavior aligned with efmshowform_data.jsp.

Suggested refactor
-    thisEForm.addHiddenInputElement("providerNo", provider_no);
+    LoggedInInfo loggedInInfo = LoggedInInfo.getLoggedInInfoFromSession(request);
+    thisEForm.addHiddenInputElement("providerNo", loggedInInfo.getLoggedInProviderNo());
 
     // Add email consent properties
-    LoggedInInfo loggedInInfo = LoggedInInfo.getLoggedInInfoFromSession(request);
     addHiddenEmailProperties(loggedInInfo, thisEForm, demographic_no);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/webapp/eform/efmformadd_data.jsp` around lines 148 - 152, Replace
use of the standalone provider_no when adding the providerNo hidden field with
the provider from the resolved session user to keep flows consistent: inside the
block where LoggedInInfo loggedInInfo =
LoggedInInfo.getLoggedInInfoFromSession(request); call
loggedInInfo.getLoggedInProviderNo() and pass that value into
thisEForm.addHiddenInputElement("providerNo", ...) instead of provider_no;
ensure null-safety if getLoggedInProviderNo() can be null to match existing
behavior in efmshowform_data.jsp.
src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js (1)

798-833: Convert this auto-save request to async/await.

The AJAX request uses callback-based handlers (success and error functions), which violates the coding guideline that requires async/await for promises in JavaScript files. Converting to async/await will improve error handling, reduce nesting, and simplify control flow maintenance.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js` around
lines 798 - 833, Make the AJAX call to add the tickler async by turning the
surrounding function into an async function and awaiting jQuery.ajax(...) (jqXHR
is thenable) instead of using success/error callbacks: call await
jQuery.ajax({url: contextPath + "/ws/rs/tickler/add", type: "POST", contentType:
"application/json", data: JSON.stringify(payload), dataType: "json"}); then wrap
it in try/catch—on success check resp && resp.success, extract ticklerId and
build viewUrl, set jQuery("#ticklerViewLink").attr("href", viewUrl), configure
and open jQuery("#ticklerAutoSaveSuccessDialog") with the same OK handler that
sets window._ticklerDialogButtonClicked and calls proceedCallback; in the catch
block reproduce the existing error parsing logic (inspect xhr.responseText,
JSON.parse if possible, fallback to "HTTP " + xhr.status or default detail) and
call showTicklerError(detail, proceedCallback); ensure variable names payload,
contextPath, proceedCallback, ticklerViewLink, ticklerAutoSaveSuccessDialog, and
showTicklerError are used so the refactor maps to the original behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/ca/openosp/openo/webserv/rest/TicklerWebService.java`:
- Around line 402-404: In TicklerWebService (the method that calls
ticklerManager.addTickler and sets the response), only set
response.setMessage(String.valueOf(tickler.getId())) when the creation
succeeded; i.e., capture the boolean result from
ticklerManager.addTickler(getLoggedInInfo(), tickler) (or check
response.isSuccess()) and call response.setMessage(...) inside the success
branch so message is not populated when success is false.

In `@src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js`:
- Around line 62-72: The wrapper function wrapWithTicklerCheck sets the
module-level flag _ticklerHandled true before showing prompts but never resets
it after successful action chains, causing later toolbar actions to skip
prompts; update the proceedCallback and any other success continuation (the
places that call proceed() / originalFn.apply like proceedCallback and the other
proceed handlers) to reset _ticklerHandled = false once the originalFn has been
invoked (or in a finally-style continuation after originalFn completes) so the
flag is cleared for subsequent independent toolbar actions while preserving the
single-prompt behavior during the prompt sequence.

---

Nitpick comments:
In `@src/main/webapp/eform/efmformadd_data.jsp`:
- Around line 148-152: Replace use of the standalone provider_no when adding the
providerNo hidden field with the provider from the resolved session user to keep
flows consistent: inside the block where LoggedInInfo loggedInInfo =
LoggedInInfo.getLoggedInInfoFromSession(request); call
loggedInInfo.getLoggedInProviderNo() and pass that value into
thisEForm.addHiddenInputElement("providerNo", ...) instead of provider_no;
ensure null-safety if getLoggedInProviderNo() can be null to match existing
behavior in efmshowform_data.jsp.

In `@src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js`:
- Around line 798-833: Make the AJAX call to add the tickler async by turning
the surrounding function into an async function and awaiting jQuery.ajax(...)
(jqXHR is thenable) instead of using success/error callbacks: call await
jQuery.ajax({url: contextPath + "/ws/rs/tickler/add", type: "POST", contentType:
"application/json", data: JSON.stringify(payload), dataType: "json"}); then wrap
it in try/catch—on success check resp && resp.success, extract ticklerId and
build viewUrl, set jQuery("#ticklerViewLink").attr("href", viewUrl), configure
and open jQuery("#ticklerAutoSaveSuccessDialog") with the same OK handler that
sets window._ticklerDialogButtonClicked and calls proceedCallback; in the catch
block reproduce the existing error parsing logic (inspect xhr.responseText,
JSON.parse if possible, fallback to "HTTP " + xhr.status or default detail) and
call showTicklerError(detail, proceedCallback); ensure variable names payload,
contextPath, proceedCallback, ticklerViewLink, ticklerAutoSaveSuccessDialog, and
showTicklerError are used so the refactor maps to the original behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dcffae9f-3cef-40e5-ba58-a6dbd4f33b38

📥 Commits

Reviewing files that changed from the base of the PR and between b244f18 and ca639ec.

📒 Files selected for processing (5)
  • src/main/java/ca/openosp/openo/webserv/rest/TicklerWebService.java
  • src/main/webapp/eform/efmformadd_data.jsp
  • src/main/webapp/eform/efmshowform_data.jsp
  • src/main/webapp/eform/eformFloatingToolbar/eform_floating_toolbar.js
  • src/main/webapp/tickler/ticklerAdd.jsp

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a feature for eForms to automatically prompt for or create ticklers. The changes are implemented across the backend REST service, JSPs, and client-side JavaScript. My review focuses on improving the robustness, maintainability, and consistency of the new code. I've provided suggestions to enhance API design clarity, ensure safer data handling in JSPs (with one comment specifically referencing consistency rules), and modernize the JavaScript implementation by using appropriate variable scopes and browser APIs.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@LiamStanziani LiamStanziani requested a review from Copilot March 5, 2026 18:23
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

  - Use session-based LoggedInInfo for providerNo in both JSP files
  - Only set tickler ID in REST response on successful creation
  - Remove redundant LoggedInInfo call in efmshowform_data.jsp
  - Scope _dialogButtonClicked to closure instead of window global
  - Use targeted removeClass for close button styling
  - Convert all tickler var declarations to const/let
  - Reset _ticklerHandled after successful action chains
  - Handle popup blocker with clear message instead of false closed dialog
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.

[Feature]: Add special eform fields to support opening the "add tickler" window automatically when submitting the eform

2 participants