Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PagePattern: List detail with dashboard view container enhancements #8849

Open
krishollenbeck opened this issue Jun 25, 2024 · 0 comments
Open
Labels
team: landmark For Landmark issues type: bug 🐛 [3] Velocity rating (Fibonacci)

Comments

@krishollenbeck
Copy link
Contributor

krishollenbeck commented Jun 25, 2024

Is your feature request related to a problem or use case? Please describe.
Attached is an example of a somewhat common pattern in Landmark. List with a detail section displayed within the horizontal tabs component. We are running into some issues with extra scrollbars when using a dashboard view "Homepage" layout inside of a tab panel. (see attached screenshots)

Describe the solution you'd like
Some "out of the box" CSS support to handle this kind of pattern. We also set our own margin on the top/bottom containers. You can see this in the embedded HTML where I am using inline styles. I wasn't able to find an existing IDS container for this pattern. I am thinking this pattern in general could use some extra support.

Describe alternatives you've considered
Currently we are working around some of these issues with internal CSS overrides. However this becomes problematic when CSS changes via IDS upgrades sometimes cause unexpected breaking changes.

Additional context
image

image
<a href="#maincontent" class="skip-link" data-translate="text">SkipToMain</a>
{{> includes/svg-inline-refs}}
{{> includes/applicationmenu}}

<section class="module-nav-container mode-collapsed">
  <aside id="nav" class="module-nav" data-options="{ 'filterable': true }">
    <div class="module-nav-bar">
      <!-- Module Nav's top-level navigation items are inside the accordion -->
      <div class="module-nav-accordion accordion panel" data-options="{'allowOnePane': false }">
        <!-- Module switcher -->
        <div class="module-nav-header accordion-section">
          <div class="module-nav-switcher">
            <div class="module-nav-section role-dropdown">
              <label for="module-nav-role-switcher" class="label audible">Roles</label>
              <select id="module-nav-role-switcher" name="module-nav-role-switcher" class="dropdown" data-options="{attributes: [{ name: 'id', value: 'switcher-id-1' }, { name: 'data-automation-id', value: 'switcher-automation-id' }]}" data-automation-id="custom-automation-dropdown-id">
                <option value="admin" data-icon="{icon: 'app-ac'}">Admin Console</option>
                <option value="job-console" data-icon="{icon: 'app-jo'}">Job Console</option>
                <option value="landing-page-designer" data-icon="{icon: 'app-lmd'}">Landing Page Designer</option>
                <option value="process-server-admin" data-icon="{icon: 'app-psa'}">Process Server Administrator</option>
                <option value="proxy-management" data-icon="{icon: 'app-pm'}">Proxy Management</option>
                <option value="security-system-management" data-icon="{icon: 'app-ssm'}">Security System Management</option>
                <option value="user-management" data-icon="{icon: 'app-um'}">User Management</option>
              </select>
            </div>
          </div>
        </div>

        <div class="module-nav-search-container accordion-section">
          <label class="audible" for="module-nav-searchfield">Search</label>
          <input id="module-nav-searchfield" data-init="false" class="searchfield module-nav-search" placeholder="Search" />
        </div>

        <!-- Most accordion items should be placed in the "main" section -->
        <div class="module-nav-main accordion-section">
          <div class="accordion-header">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-male"></use>
            </svg>
            <a href="#" id="item-config" data-automation-id="module-nav-item-config"><span>Configuration and Personalization</span></a>
          </div>
          <div class="accordion-pane">
            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>

            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>

            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>
          </div>

          <div class="accordion-header">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-database"></use>
            </svg>
            <a href="#" id="item-database" data-automation-id="module-nav-item-databasde"><span>Database</span></a>
          </div>
          <div class="accordion-pane">
            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>

            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>

            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>
          </div>

          <div class="accordion-header">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-translate"></use>
            </svg>
            <a href="#" id="item-translation" data-automation-id="module-nav-item-translation"><span>Data Translation</span></a>
          </div>
          <div class="accordion-pane">
            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>

            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>

            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>
          </div>

          <div class="accordion-header">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-security-on"></use>
            </svg>
            <a href="#" id="item-security" data-automation-id="module-nav-item-security"><span>Security</span></a>
          </div>
          <div class="accordion-pane">
            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>

            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>

            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>
          </div>

          <div class="accordion-header">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-line-bar-chart"></use>
            </svg>
            <a href="#" id="item-analytics" data-automation-id="module-nav-item-analytics"><span>Analytics</span></a>
          </div>
          <div class="accordion-pane">
            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>

            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>

            <div class="accordion-header">
              <a href="#"><span>Label</span></a>
            </div>
          </div>

          <div class="accordion-header">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-import-spreadsheet"></use>
            </svg>
            <a href="#" id="item-audit" data-automation-id="module-nav-item-audit"><span>Audit and Monitoring</span></a>
          </div>
        </div>

        <!-- Footer items are separate and "optionally" pinnable -->
        <div class="module-nav-footer accordion-section">
          <div class="accordion-header">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-document"></use>
            </svg>
            <a href="#" id="module-nav-item-documents" data-automation-id="module-nav-documents"><span>Documents</span></a>
          </div>

          <div class="accordion-header is-selected">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-report"></use>
            </svg>
            <a href="#" id="module-nav-item-reports" data-automation-id="module-nav-reports"><span>Reports</span></a>
          </div>

          <div class="accordion-header">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-notification"></use>
            </svg>
            <a href="#" id="module-nav-item-notifications"
               data-automation-id="module-nav-notifications"><span>Notification</span></a>
          </div>
        </div>

        <!-- Settings area is also separate and permanently "pinned" to the bottom -->
        <div class="module-nav-settings accordion-section">
          <div
            class="module-nav-settings-btn accordion-header"
            data-automation-id="module-nav-settings"
            id="module-nav-settings-btn">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-settings"></use>
            </svg>
            <a href="#"><span>Settings</span></a>
          </div>
          <ul class="popupmenu module-nav-settings-menu">
            <li>
              <a href="#">
                <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
                  <use href="#icon-observation-precautions"></use>
                </svg>
                <span>Jobs</span>
              </a>
            </li>
            <li>
              <a href="#">
                <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
                  <use href="#icon-report"></use>
                </svg>
                <span>Reports</span>
              </a>
            </li>
            <li>
              <a href="#">
                <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
                  <use href="#icon-isolation"></use>
                </svg>
                <span>Actions</span>
              </a>
            </li>
            <li>
              <a href="#">
                <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
                  <use href="#icon-edit"></use>
                </svg>
                <span>Personalization</span>
              </a>
            </li>
            <li class="separator"></li>
            <li>
              <a href="#">
                <span>Create Report</span>
              </a>
            </li>
            <li>
              <a href="#">
                <span>Proxy</span>
              </a>
            </li>
            <li>
              <a href="#">
                <span>Set "As Of Date"</span>
              </a>
            </li>
            <li>
              <a href="#">
                <span>User Context</span>
              </a>
            </li>
            <li class="separator"></li>
            <li>
              <a href="#">
                <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
                  <use href="#icon-settings"></use>
                </svg>
                <span>Settings</span>
              </a>
            </li>
            <li>
              <a href="#">
                <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
                  <use href="#icon-info"></use>
                </svg>
                <span>About</span>
              </a>
            </li>
            <li>
              <a href="#">
                <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
                  <use href="#icon-help"></use>
                </svg>
                <span>Help</span>
              </a>
            </li>
          </ul>
        </div>
      </div>
    </div>

    <!-- Detail area is optional and can have additional context -->
    <div class="module-nav-detail">&nbsp;</div>
  </aside>
  <!-- Page Container -->
  <div class="page-container scrollable">
    <div style="margin: 5px 20px 10px 20px">
      <div class="toolbar" role="toolbar">
        <div class="title">
          Compressors
          <span class="datagrid-result-count">(N Results)</span>
        </div>
        <div class="buttonset">

          <label class="audible" for="common-toolbar-searchfield">Keyword Search</label>
          <input id="common-toolbar-searchfield" name="common-toolbar-searchfield" class="searchfield" />

          <button class="btn btn-toggle no-ripple hide-focus is-pressed" type="button" aria-pressed="true" id="toggle-compact">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-change-row-line-height"></use>
            </svg>
            <span>Compact Mode</span>
          </button>
        </div>

        <div class="more">
          <button class="btn-actions" type="button">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use href="#icon-more"></use>
            </svg>
            <span class="audible">More Actions</span>
          </button>
          <ul class="popupmenu">
            <li><a data-option="personalize-columns" href="#" data-translate="text">PersonalizeColumns</a></li>
            <li><a data-option="reset-layout" href="#" data-translate="text">ResetDefault</a></li>
            <li class="separator"></li>
            <li class="heading">Filter</li>
            <li class="show-filter is-toggleable is-checked"><a data-option="show-filter-row" data-translate="text">ShowFilterRow</a></li>
            <li class="is-indented"><a data-option="run-filter" data-translate="text">RunFilter</a></li>
            <li class="is-indented"><a data-option="clear-filter" data-translate="text">ClearFilter</a></li>
            <li class="separator single-selectable-section"></li>
            <li class="heading">Row Height</li>
            <li class="is-selectable is-checked"><a data-option="row-extra-small" href="#" data-translate="text">ExtraSmall</a></li>
            <li class="is-selectable"><a data-option="row-small" href="#" data-translate="text">Small</a></li>
            <li class="is-selectable"><a data-option="row-medium" href="#" data-translate="text">Medium</a></li>
            <li class="is-selectable"><a data-option="row-large" href="#" data-translate="text">Large</a></li>
          </ul>

        </div>
      </div>
      <div id="datagrid">
      </div>
    </div>

    <div style="margin: 0 20px">
      <div id="header-tabs" class="tab-container" data-options='{ "containerElement": "#tab-panel-container" }'>
        <ul class="tab-list">
          <li class="tab"><a id="tabs-1" data-automation-id="tabs-1-a" href="#header-tabs-1">Tab 1</a></li>
          <li class="tab"><a id="tabs-2" data-automation-id="tabs-2-a" href="#header-tabs-2">Tab 2</a></li>
        </ul>
      </div>
      <div id="tab-panel-container">
        <div id="header-tabs-1" data-automation-id="tabs-1-panel" class="tab-panel">
          <div class="homepage" data-columns="3">
            <div class="content">
              <div class="widget">
                <div class="widget-header">
                  <h2 class="widget-title">Widget</h2>
                </div>
              </div>
              <div class="widget">
                <div class="widget-header">
                  <h2 class="widget-title">Widget</h2>
                </div>
              </div>
              <div class="widget">
                <div class="widget-header">
                  <h2 class="widget-title">Widget</h2>
                </div>
              </div>
              <div class="widget">
                <div class="widget-header">
                  <h2 class="widget-title">Widget</h2>
                </div>
              </div>
              <div class="widget">
                <div class="widget-header">
                  <h2 class="widget-title">Widget</h2>
                </div>
              </div>
              <div class="widget">
                <div class="widget-header">
                  <h2 class="widget-title">Widget</h2>
                </div>
              </div>
              <div class="widget">
                <div class="widget-header">
                  <h2 class="widget-title">Widget</h2>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div id="header-tabs-2" data-automation-id="tabs-2-panel" class="tab-panel">
          <div class="homepage" data-columns="3">
            <div class="content">
              <div class="widget">
                <div class="widget-header">
                  <h2 class="widget-title">Business Insight</h2>
                  <button class="btn-actions" type="button">
                    <span class="audible">Actions</span>
                    <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
                      <use href="#icon-more"></use>
                    </svg>
                  </button>
                  <ul class="popupmenu actions top">
                    <li><a href="#">Action One</a></li>
                    <li><a href="#">Action Two</a></li>
                  </ul>
                </div>

                <div class="widget-content">
                  <div id="datagrid1">
                  </div>
                </div>
              </div>
              <div class="widget">
                <div class="widget-header">
                  <h2 class="widget-title">Calendar (Feb 2021)</h2>
                  <button class="btn-actions" type="button">
                    <span class="audible">Actions</span>
                    <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
                      <use href="#icon-more"></use>
                    </svg>
                  </button>
                  <ul class="popupmenu actions top">
                    <li><a href="#">Action One</a></li>
                    <li><a href="#">Action Two</a></li>
                  </ul>
                </div>

                <div class="widget-content">
                  <div class="calendar" data-init="false" id="calendar-one">
                    <div class="calendar-monthview">
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>

<script>
  $('body').one('initialized', function () {

    $('#calendar-one').calendar({
      month: 1,
      day: 2,
      year: 2022,
      showToday: false,
      showViewChanger: false,
    });

    var grid,
      columns = [],
      data = [];

    //Define Columns for the Grid.
    columns.push({ id: 'selectionCheckbox', sortable: false, resizable: false, formatter: Soho.Formatters.SelectionCheckbox, align: 'center' }),
    columns.push({ id: 'id', name: 'Id', field: 'id', formatter: Soho.Formatters.Readonly, filterType: 'text'});
    columns.push({ id: 'productId', name: 'Product Id', field: 'productId', formatter: Soho.Formatters.Readonly, filterType: 'text'});
    columns.push({ id: 'productName', name: 'Product Name', sortable: false, field: 'productName', filterType: 'text', formatter: Soho.Formatters.Hyperlink, editor: Soho.Editors.Input});
    columns.push({ id: 'activity', hidden: true, name: 'Activity', field: 'activity',  filterType: 'integer', editor: Soho.Editors.Input});
    columns.push({ id: 'quantity', name: 'Quantity', field: 'quantity', filterType: 'contents', options: [{id: '1', value: '1', label: '1'}, {id: '2', value: '2', label: '2'}]});
    columns.push({ id: 'price', name: 'Price', field: 'price', width: 125, filterType: 'decimal', formatter: Soho.Formatters.Decimal});
    columns.push({ id: 'orderDate', name: 'Order Date', field: 'orderDate', filterType: 'date', formatter: Soho.Formatters.Date, dateFormat: 'M/d/yyyy'});

    //Init and get the api for the grid
    grid = $('#datagrid').datagrid({
      allowSelectAcrossPages: true,
      columns: columns,
      selectable: 'multiple',
      paging: true,
      editable: true,
      filterable: true,
      pagesize: 10,
      rowHeight: 'extra-small',
      resultsText: function (grid, count, filterCount) {
        console.log('ResultsText:', grid, count, filterCount);
        if (filterCount > 0) {
          return '(' + filterCount + ' of '+ count + ')';
        }
        else {
          return '(' + 'all '+ count + ')';
        }
      },
      source: function(req, response) {
        var url = '{{basepath}}api/compressors?pageNum='+ req.activePage +'&pageSize='+ req.pagesize;

        if (req.sortField) {
          url += '&sortField=' + req.sortField + '&sortAsc=' + req.sortAsc;
        }

        if (req.filterExpr && req.filterExpr[0]) {
          url += '&filterValue=' + req.filterExpr[0].value;
          url += '&filterOp=' + req.filterExpr[0].operator;
          url += '&filterColumn=' + req.filterExpr[0].columnId;
        }

        //Get Page Based on info in Req, return results into response;
        $.getJSON(url, function(res) {
          // This is the total going into the grid so the pager works (filtered total or total)
          req.total = res.total;
          req.preserveSelected = true;
          if ((req.filterExpr && req.filterExpr[0])) {
            req.total = res.total;
            req.grandTotal = res.grandTotal; // This is the total amount on the server
          }
          response(res.data, req);
        });
      },
      toolbar: {title: 'Data Grid Header Title', filterRow: true, personalize: true, results: true, keywordFilter: false, actions: true, rowHeight: true, filterRow: true}
    });

    $('#toggle-compact').on('click', function () {
      Soho.utils.toggleCompactMode(document.querySelector('form'));
    });

    $('#header-tabs').on('focusin', 'a', function() {
      if (console && typeof console.log === 'function') {
        console.log('Tab Content: "'+ $(this).text().trim() +'"');
      }
    });

    var grid1,
      columns1 = [];

    columns1.push({ id: 'productId', name: 'Product Id', field: 'productId', percent: .30});
    columns1.push({ id: 'productName', name: 'Product Name', sortable: false, field: 'productName', percent: .40, formatter: Soho.Formatters.Hyperlink, editor: Soho.Editors.Input});
    columns1.push({ id: 'quantity', name: 'Quantity', field: 'quantity',  percent: .30 });

    //Init and get the api for the grid
    grid1 = $('#datagrid1').datagrid({
      columns: columns1,
      selectable: 'multiple',
      editable: true,
      rowHeight: 'medium',
      isList: true,
      indeterminate: true,
      showPageSizeSelector: false,
      paging: true,
      pagesize: 10,
      source: function(req, response) {
        var url = '{{basepath}}api/compressors?pageNum='+ req.activePage +'&pageSize='+ req.pagesize;

        if (req.sortField) {
          url += '&sortField=' + req.sortField + '&sortAsc=' + req.sortAsc;
        }

        if (req.filterExpr && req.filterExpr[0]) {
          url += '&filterValue=' + req.filterExpr[0].value;
          url += '&filterOp=' + req.filterExpr[0].operator;
          url += '&filterColumn=' + req.filterExpr[0].columnId;
        }

        //Get Page Based on info in Req, return results into response;
        $.getJSON(url, function(res) {
          req.total = res.total;
          response(res.data, req);
        });
      },
    }).on('selected', function (e, args) {
      console.log(args.row, args.item);
    });

    $('html').personalize({ colors: '#fff' });
    $('[data-theme-name="theme-classic"]').parent().addClass('is-disabled');

    const navEl = $('#nav');
    const navAPI = navEl.data('modulenav');
    const containerEl = $('.module-nav-container');
    const displayCheckEl = $('#display-detail-check');
    const hideCompletelyEl = $('#hide-completely');
    const hamburgerBtnEl = $('#header-hamburger');
    const pinSectionsCheckEl = $('#pin-sections');
    const disableSwitcher = $('#disable-switcher');

    displayCheckEl.on('change.test', (e) => {
      navAPI.updated({ showDetailView: displayCheckEl[0].checked });
    });

    pinSectionsCheckEl.on('change.test', (e) => {
      navAPI.updated({ pinSections: pinSectionsCheckEl[0].checked });
    });

    disableSwitcher.on('change.test', (e, mode) => {
      navAPI.updated({ disableSwitcher: disableSwitcher[0].checked });
    })

    if (hamburgerBtnEl.length) {
      hamburgerBtnEl.on('click.test', (e) => {
        navAPI.handleHamburgerClick();
      });
    }

    navEl.on('displaymodechange.test', (e, mode) => {
      console.log('Display mode changed to:', mode);
    });

    // Connect component event handling
    const roleSwitcherEl = $('.role-dropdown');
    const roleSwitcherAPI = roleSwitcherEl.data('modulenavswitcher');
    const roleDropdownEl = $('#module-nav-role-switcher');
    const roleButtonEl = $('.module-btn button');

    roleDropdownEl.on('change.test', (e) => {
      console.info('Module Nav Role Change:', e.target.value);
    });

    roleButtonEl.on('click.test', (e) => {
      console.info('Module Button Click');
    })

    hideCompletelyEl.on('change.test', (e) => {
      console.log(hideCompletelyEl[0].checked)

      if (hideCompletelyEl[0].checked) {
        navAPI.updated({ displayMode: false });
        hamburgerBtnEl.attr('disabled', 'true');
      }
      else {
        navAPI.updated({ displayMode: navAPI.isLargerThanBreakpoint() ? 'collapsed' : 'expanded' });
        hamburgerBtnEl.removeAttr('disabled');
      }
    });

    // Customizations to the component after init
    navAPI.updated({ displayMode: 'collapsed' });

    $('.module-nav-switcher').on('listcontextmenu', function (e, delegate) {
      console.log('Context Menu Event Fired')
      const url = $(delegate.target).text().replace(/^\s+|\s+$/g, '').replace(' ', '').toLocaleLowerCase();
      $(delegate.target)
        .attr('href', `https://example.com/${url}`);
    });
  });
</script>

@tmcconechy tmcconechy changed the title List detail with dashboard view container enhancements PagePattern: List detail with dashboard view container enhancements Jun 25, 2024
@tmcconechy tmcconechy added type: bug 🐛 [3] Velocity rating (Fibonacci) team: landmark For Landmark issues labels Jun 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
team: landmark For Landmark issues type: bug 🐛 [3] Velocity rating (Fibonacci)
Projects
Status: Check Back
Development

No branches or pull requests

2 participants