New: open AI Assistant in a popup overlay from top-toolbar icon (#38311)

Per maintainer feedback on #38307: "adding a popup (without leaving
current page) is better than opening a complete page".

The AI Assistant top-toolbar icon (added in develop by e735bed1 via
top_menu_ai() in main.inc.php) is a plain <a href> that navigates
the user away from whatever page they were on. This patch makes the
icon open the Assistant in a popup overlay instead, so the user
keeps their working context while interacting with the assistant.

Approach:

Reuses the existing Dolibarr core helper dolButtonToOpenUrlInDialogPopup()
(htdocs/core/lib/functions.lib.php) which:

  - Builds an <a> with accesskey, title, and an icon
  - On click, injects an <iframe src="$url" width="100%" height="98%">
    into a hidden <div id="idfordialog$name">
  - Opens the div as a jQuery UI dialog: modal:true, width:'80%',
    height: window.innerHeight - 150
  - Auto-appends "dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup=$name"
    to the URL so the embedded page renders without the surrounding
    top/left chrome (Dolibarr core handles these URL params in
    main.inc.php; no change needed to /ai/assistant/index.php)
  - Falls back gracefully to target="_blank" when JavaScript is off

Zero changes are needed to /ai/assistant/index.php itself: the
dol_openinpopup / dol_hide_topmenu / dol_hide_leftmenu URL params
are already handled generically by main.inc.php (the same way
modulebuilder, ECM and other popup-friendly screens are loaded).

Visible behaviour:

- Click on the AI top-toolbar icon -> Assistant opens centered as
  a modal dialog over the current page; the chat UI loads inside
  the iframe; closing the dialog returns the user to their original
  page with no navigation.
- Accesskey 'a' (unchanged from e735bed1) still focuses/triggers the
  icon.
- Tooltip switches from "AI (Ctrl+Alt+a)" to the localized
  "AI Assistant" string (the helper uses $label for both the title
  attribute and the dialog title -- one string for both is the
  helper's design).

Other top_menu_* icons (bookmark, quickadd, search, import) are
unchanged.

Tested:
- Click icon -> popup opens, Assistant chat works inside iframe.
- Close dialog -> back on the original page with no navigation.
- JavaScript disabled -> link degrades to opening in a new tab
  (target="_blank"), Assistant page renders normally with its full
  chrome.
- Accesskey Ctrl+Alt+a still triggers the icon.
This commit is contained in:
Pichinov-Jose 2026-05-18 22:04:43 +02:00 committed by GitHub
parent 18b7fa0fd4
commit 74fc27b68b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 103 additions and 4 deletions

View file

@ -426,3 +426,79 @@
background-color: #6c757d;
border-color: #6c757d;
}
/* -------------------------------------------------------------------------
* Popup mode (loaded via dol_openinpopup URL param from the top-toolbar
* AI icon -> dolButtonToOpenUrlInDialogPopup() iframe).
*
* Dolibarr core adds the body class "dol_openinpopup" when this param is
* set (htdocs/main.inc.php), so we can target popup-only tweaks here
* without touching index.php.
*
* Sizing strategy:
* The chat-container in standalone mode uses "height: 70vh; min-height:
* 650px" which is great on a full page but causes the dialog iframe to
* overflow on small windows. In popup mode we make the chat-container
* fill the iframe viewport exactly (height: 100% of body, body itself
* pinned to 100vh of iframe) and drop the 650px floor; .chat-history
* keeps its flex-grow:1 + overflow-y:auto so message scroll still works
* INTERNALLY without an iframe-level scrollbar.
*
* We also flatten the visual chrome (border, shadow, rounded corners,
* capped max-width, top margin) that is now redundant with the dialog
* frame, and hide the duplicate "AI Assistant" H2 (the dialog title bar
* already shows it).
* ------------------------------------------------------------------------- */
body.dol_openinpopup {
margin: 0;
padding: 0;
height: 100vh;
overflow: hidden;
}
/* In popup mode the DOM is:
* body > #id-container > .fiche > .ai-chat-container
* (top_menu and left_menu blocks are skipped by main.inc.php when
* dol_openinpopup is set, but #id-container and .fiche are always
* emitted). For "height: 100%" on .ai-chat-container to resolve to
* the iframe viewport, every ancestor in the chain must also be
* 100% high. */
body.dol_openinpopup #id-container,
body.dol_openinpopup .fiche {
height: 100%;
margin: 0;
padding: 0;
}
body.dol_openinpopup .ai-chat-container {
max-width: none;
margin: 0;
border: 0;
border-radius: 0;
box-shadow: none;
height: 100%;
min-height: 0;
max-height: 100%;
}
/* Flexbox shrink fix: a flex-grow:1 child defaults to min-height:auto
* (content-based), which prevents the chat-history from shrinking below
* its message-content height and causes the WHOLE container to overflow
* the iframe after a long response. Forcing min-height:0 lets the
* chat-history shrink to fit the available column space and scroll
* INTERNALLY (overflow-y:auto is already on .chat-history). */
body.dol_openinpopup .chat-history {
min-height: 0;
}
/* The dialog title bar already shows "AI Assistant", so hide the redundant
* H2 inside .chat-header but keep .header-controls (Clear + mode select). */
body.dol_openinpopup .chat-header {
border-radius: 0;
justify-content: flex-end;
}
body.dol_openinpopup .chat-header h2 {
display: none;
}

View file

@ -2731,10 +2731,33 @@ function top_menu_ai()
$html = '';
if (isModEnabled('ai')) {
$html .= '<!-- div for quick ai link -->
<div id="topmenu-tool" class="atoplogin dropdown inline-block">
<a accesskey="a" class="nofocusvisible" href="'.DOL_URL_ROOT.'/ai/assistant/index.php" title="'.$langs->trans('AIAssistant').' ('.$conf->browser->stringforfirstkey.' a)"><i class="fa fa-magic"></i></a>
</div>';
// Open the AI Assistant in a popup overlay rather than navigating away,
// so the user keeps their current page context while interacting with
// the assistant. Uses the standard Dolibarr helper which builds an
// iframe-in-jQuery-UI-dialog (modal, 80% width, height-150) and auto-
// appends dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup=NAME
// so the embedded page renders without the surrounding chrome.
// JS-disabled fallback: the helper degrades to target="_blank".
// $label is used by dolButtonToOpenUrlInDialogPopup() both for the
// title="" tooltip on the <a> AND for the jQuery UI dialog title.
// Include the keyboard-shortcut hint (matching the convention used
// e.g. by the PublicVirtualCardUrl call earlier in this file and by
// bookmark/quickadd/search) so the icon tooltip on hover reads e.g.
// "AI Assistant (Ctrl Alt a)" -- the dialog title shows the same.
$ailabel = $langs->trans('AIAssistant').' ('.$conf->browser->stringforfirstkey.' a)';
$aibtn = dolButtonToOpenUrlInDialogPopup(
'aiassistant',
$ailabel,
'<i class="fa fa-magic"></i>',
'/ai/assistant/index.php',
'',
'nofocusvisible',
'',
'',
'a'
);
$html .= '<!-- div for quick ai link (opens AI Assistant in popup) -->
<div id="topmenu-tool" class="atoplogin dropdown inline-block">'.$aibtn.'</div>';
}
return $html;