creating a custom tabList (nav menu) based on teams

Collapse
X
 
  • Time
  • Show
Clear All
new posts

  • jamie
    replied
    Originally posted by rabii
    i guess you will need to rewrite you own custom navbar class - look at this class

    https://github.com/espocrm/espocrm/b...navbar.js#L492
    i ended up doing it via a javascript override


    Code:
    define('custom:menu', [], function () {
    class User {
    async getUserTeamID() {
    try {
    const response = await fetch('api/v1/App/user');
    const data = await response.json();
    return data.user.defaultTeamName;
    } catch (error) {
    console.error('Failed to fetch user data:', error);
    return null;
    }
    }
    }
    return User;
    });
    let tabList = [];
    window.addEventListener('popstate', () => {
    if (tabList.length > 0) {
    replaceNavTabs(tabList);
    }
    });
    document.addEventListener('DOMContentLoaded', () => {
    Espo.loader.require('custom:menu', async function (User) {
    const myInstance = new User();
    // const teamID = await myInstance.getUserTeamID();
    const teamID = 'Systems'; // hardcoded for now
    // const teamID = 'sales'; // hardcoded for now
    // const teamID = 'Sales Administration'; // hardcoded for now
    console.log('team :', teamID);
    const configPath = `client/custom/modules/hiden/config/menuTabs/${teamID}.json`;
    const forAllConfig = `client/custom/modules/hiden/config/menuTabs/all.json`;
    try {
    const response = await fetch(configPath);
    const forAllRes = await fetch(forAllConfig);
    if (!response.ok) {
    throw new Error(`Failed to load config for team ${teamID}`);
    }
    tabList = await response.json();
    forAll = await forAllRes.json();
    tabList.unshift(...forAll);
    
    replaceNavTabs(tabList);
    } catch (e) {
    console.error(e);
    }
    });
    });
    function replaceNavTabs(customTabs) {
    function waitForNavTabs(callback, interval = 100, timeout = 5000) {
    const start = Date.now();
    const timer = setInterval(() => {
    const navTabs = document.querySelector('ul.tabs.navbar-nav');
    if (navTabs) {
    clearInterval(timer);
    callback(navTabs);
    } else if (Date.now() - start > timeout) {
    clearInterval(timer);
    console.warn('Nav tabs not found');
    }
    }, interval);
    }
    waitForNavTabs(navTabs => {
    navTabs.innerHTML = '';
    customTabs.forEach(tab => {
    if (tab.type === 'group') {
    // Dropdown group
    const li = document.createElement('li');
    li.className = 'tab tab-group dropdown';
    li.dataset.name = tab.dataName;
    const a = document.createElement('a');
    a.className = 'nav-link-group';
    a.setAttribute('data-toggle', 'dropdown');
    a.href = '#';
    if (tab.shortLabelIcon) {
    const shortSpan = document.createElement('span');
    shortSpan.className = 'short-label';
    shortSpan.innerHTML = `<span class="${tab.shortLabelIcon}" style="color: ${tab.iconColor || 'inherit'}"></span>`;
    a.appendChild(shortSpan);
    }
    if (tab.fullLabel) {
    const fullSpan = document.createElement('span');
    fullSpan.className = 'full-label';
    fullSpan.textContent = tab.fullLabel;
    a.appendChild(fullSpan);
    }
    const caret = document.createElement('span');
    caret.className = 'fas fa-caret-right group-caret';
    a.appendChild(caret);
    li.appendChild(a);
    // Dropdown menu
    const ulDropdown = document.createElement('ul');
    ulDropdown.className = 'dropdown-menu';
    ulDropdown.setAttribute('role', 'menu');
    (tab.items || []).forEach(subTab => {
    const subLi = document.createElement('li');
    subLi.className = 'tab';
    subLi.dataset.name = subTab.dataName;
    const subA = document.createElement('a');
    subA.href = subTab.href || '#';
    subA.className = 'nav-link';
    if (subTab.shortLabelIcon) {
    const shortSpan = document.createElement('span');
    shortSpan.className = 'short-label';
    shortSpan.innerHTML = `<span class="${subTab.shortLabelIcon}" style="color: ${subTab.iconColor || 'inherit'}"></span>`;
    subA.appendChild(shortSpan);
    }
    if (subTab.fullLabel) {
    const fullSpan = document.createElement('span');
    fullSpan.className = 'full-label';
    fullSpan.textContent = subTab.fullLabel;
    subA.appendChild(fullSpan);
    }
    subLi.appendChild(subA);
    ulDropdown.appendChild(subLi);
    });
    li.appendChild(ulDropdown);
    navTabs.appendChild(li);
    } else {
    // Single tab
    const li = document.createElement('li');
    li.className = 'tab';
    li.dataset.name = tab.dataName;
    const a = document.createElement('a');
    a.href = tab.href || '#';
    a.className = 'nav-link';
    if (tab.shortLabelIcon) {
    const shortSpan = document.createElement('span');
    shortSpan.className = 'short-label';
    shortSpan.innerHTML = `<span class="${tab.shortLabelIcon}" style="color: ${tab.iconColor || 'inherit'}"></span>`;
    a.appendChild(shortSpan);
    }
    if (tab.fullLabel) {
    const fullSpan = document.createElement('span');
    fullSpan.className = 'full-label';
    fullSpan.textContent = tab.fullLabel;
    a.appendChild(fullSpan);
    }
    li.appendChild(a);
    navTabs.appendChild(li);
    }
    });
    });
    }
    Last edited by jamie; 11-25-2025, 02:36 PM. Reason: code

    Leave a comment:


  • emillod
    replied
    Yep, it's possible, we've added for example help icon to show sidepanel with bug form report Click image for larger version

Name:	image.png
Views:	34
Size:	4.0 KB
ID:	123199

    Leave a comment:


  • rabii
    replied
    i guess you will need to rewrite you own custom navbar class - look at this class

    EspoCRM – Open Source CRM Application. Contribute to espocrm/espocrm development by creating an account on GitHub.

    Leave a comment:


  • jamie
    started a topic creating a custom tabList (nav menu) based on teams

    creating a custom tabList (nav menu) based on teams

    We need to customize the top menu, also known as the nav menu or tab list, based on a user’s team.

    We don’t just want to show or hide items, since that keeps the same structure; we need to modify its configuration.

    The Deep Wiki AI suggests this is possible, but it seems a bit questionable to me.

    Has anyone else done this?
Working...