SuiteCRM 8.8.0 – Global search results open inside iframe, causing duplicate navigation bars

Hi everyone,

I did not post for a while :slight_smile:
I ask to IA to help write my issues as i’m not english native, this should be easier for you all to read :slight_smile:

Thanks a lot for your time !

My issue :

We are experiencing an issue with global search in SuiteCRM 8.8.0.

Searching for an account returns the expected results. However, clicking the account name opens its record with a second navigation bar displayed below the main one. The “Actions” dropdown in the Opportunities subpanel then stops working, preventing the user from creating an opportunity from that account.

The issue has been reproduced in Chrome and Edge, on different computers, including with my own administrator account.

Steps to reproduce

  1. Enter an existing account name in the global search bar.

  2. On the search results page, click the account name.

  3. The record opens with two navigation bars, while the browser address bar remains on the search results URL.

Opening the same account through the Accounts module works normally. Right-clicking the global search result and opening it in a new tab also works: there is only one navigation bar and the Actions dropdown works.

What we found in the browser’s Network panel

The main search page URL is:

https://<crm-host>/public/#/home/search?query_string=<account-name>

The account link in the search results points to:

https://<crm-host>/public/index.php?action=DetailView&module=Accounts&record=<record-id>&offset=1

Clicking it produces a GET request with the following details:

Status: 302 Found
Location: ./#/accounts/record/<record-id>?offset=1

Referer: https://<crm-host>/public/legacy/index.php?query_string=<account-name>&module=Home&action=Search
Sec-Fetch-Dest: iframe

This appears to load the SuiteCRM 8 application inside the existing legacy search iframe, resulting in the duplicate navigation bars.

Configuration checked

In public/legacy/config.php:

'site_url' => 'https://<crm-host>/public',
'host_name' => '<crm-host>',

Neither setting is overridden in config_override.php.

In public/legacy/.htaccess:

RewriteBase /public/legacy

Has anyone encountered this specific behaviour? Is there an existing fix, configuration setting, or GitHub issue covering it? Is it known to be resolved in a later release?

I would prefer to use an existing solution before making any custom code changes.

Thank you for your help.

Hi,

nobody have also this issue or have found a way to fix it ?

Thanks for your help :slight_smile:

Xavier

Hello Chabi,

do you have a screenshot?

There are two navigation bars underneath each other?
I have two users in two different projects which sometimes see the same issue.
But so far, I haven’t been able to reproduce it.

As for your description:
You’ll never see public in the URL in your browser.
Check your server setup carefully:

After setting up the server correctly, you never need to open / touch the config.php or any .htaccess file (for standard szenarios).

Hello Bastian,

Thanks for your reply. Yes, there are two complete navigation bars underneath each other, each with its own search box and user icon. I’m attaching a screenshot showing this.

In our case, I can reproduce it consistently by clicking an account name in the global search results, including with my administrator account. Opening the same result in a new tab works normally: only one navigation bar appears, and the Actions dropdown works.

I checked the subdomain’s document root in cPanel. It currently points to the SuiteCRM installation directory, one level above public, rather than directly to the public directory. This explains why /public appears in our URLs.

The current settings match that layout:

'site_url' => 'https://<crm-host>/public',
'host_name' => '<crm-host>',
RewriteBase /public/legacy

I understand that pointing the document root directly to public is the recommended setup. Before changing it on the live installation, do you think this could explain the iframe navigation issue? Have you checked whether the two affected projects you mentioned use a similar setup?

Thanks again for your help!

Sure, I’ve checked it. One server, I installed myself with a fairly standard setup which worked on above 100 installations before already.
And the other one was by the IT with some communication. I’ll double check, but I don’t see public anywhere in the instances I manage / I’m working on.

So not sure, whether the iframe issue will go away. But I’d still correct the server setup and see whether things got better.

Hello Bastian,

Thanks for checking and for your advice.

There is one additional constraint: the CRM retrieves Microsoft 365 emails through OAuth, and the Microsoft application configuration is managed by the client’s IT department. Changing the document root and removing /public from the URLs would therefore require coordination with them to check and, if necessary, update the OAuth redirect URI.

I agree that the server setup should be brought into line with the recommendation. However, since the same symptom also occurs on your installations without /public in the URL, I would prefer to investigate the navigation issue further before making this change on the live system.

In our case, the behaviour is consistently reproducible: clicking a global search result loads the record inside the iframe and duplicates the navigation bar. Opening exactly the same link in a new tab works correctly.

Is there anything specific I could capture in the browser console, inspect in the generated link, or check in the logs to help identify why the navigation stays inside the iframe?

Thanks again for your help!

Unfortunately, I can’t really know / help.

I’m still not able to reproduce the issue.
I’d look into the console and network tab and follow the responses of the requests in the network tab.
In the worst case, compared that to a working version - like the online demo and check for differences.
Probably the biggest difference would be the public inside the URL.
In order to get this working, I assume, you’ve got customizations in the code / .htaccess / server redirects, so it’s even more difficult, since you’re not debugging SuiteCRM, you’d be debugging your custom SuiteCRM environment which can’t be compared to standard installations.

Fixing the duplicated navbar in SuiteCRM 8 “half-migrated” modules

Applies to: SuiteCRM 8.x (we used 8.8 / Angular 18). This is a patch to the core frontend, so it has to be re-applied after a SuiteCRM upgrade.

1. Confirm it is the same problem

You see this when a module’s list view is still legacy (rendered in an <iframe>) but its record view is the new Angular one (#/module/record/<id>). Clicking a record in the legacy list shows a second navbar.

To confirm, open DevTools → Elements and click a record. If you find an <app-root> inside the <iframe>, it is this bug: the whole Angular app booted nested inside the iframe.

2. Understand the cause

  • The legacy list link is a modern route (/#/...), clicked inside the iframe, so the iframe navigates to it and Angular boots a second time.
  • The classic view is supposed to “break out” to the top window, but that relied on the iframe’s unload event, which is unreliable in Chrome and deprecated.
  • The existing observer listens for load on the iframe’s contentWindow, which only fires for the first load. After the first navigation the contentWindow is replaced and the listener is lost.

3. Apply the patch

Edit:
core/app/core/src/lib/views/classic/components/classic-view/classic-view.component.ts

a) In initIframe(), right after this.wrapper.appendChild(iframe); / this.iframe = iframe;, add a load listener on the iframe element (not on contentWindow):

// `load` on the iframe ELEMENT fires on EVERY navigation
iframe.addEventListener('load', this.onIFrameElementLoad.bind(this));

b) Add this method to the same class:

protected onIFrameElementLoad(): void {
    let href = null;
    try {
        href = this.iframe && this.iframe.contentWindow && this.iframe.contentWindow.location.href;
    } catch (e) {
        // cross-origin or iframe already destroyed: ignore
        return;
    }

    if (href && this.shouldRedirect(href)) {
        this.onPageChange(href);
    }
}

It reuses the existing shouldRedirect() and onPageChange(). shouldRedirect() only breaks out for /#/ links that don’t match the active route, so legacy→legacy navigation and the initial list load stay inside the iframe.

Do not try to fix this by hiding the header (show_header). The second navbar is the nested v8 app’s own header, not the legacy one.

Hope you can fix this.

Thanks a lot for all this, I really appreciate the time spent to help me :slight_smile:

Some question :

If I plan to update SuiteCRM (from 8.8.0 to the last update), I could first try to rewrite to /public/ directly first ? To have the recommanded setup ?

Is this could fix the issue to upgrade to the last version or is this no relevant ?

Again, a very big thanks for the help given here :slight_smile:

Have a nice day everyone :slight_smile:

Xavier