Cireson Partners, Customers and Community members share your customizations and examples here to help benefit the community as a whole to earn Kudos and badges.

DISCLAIMER

All files and projects located here are provided and come "as-is" and without any warranty or support. Use at your own risk. Your use of Community Uploads is subject to our Terms of Use.

Cireson does not and will not support or maintain these enhancements, extensions, and scripts.

For Team Cireson uploads click here.

Active Work Items badges on menu items

13»

Comments

  • Mina_SaidiMina_Saidi Customer IT Monkey ✭

    Hi All,

    Thank for this. I have set this up in our dev environment and I was wondering if its possible to show you when work items have been updated, e.g. status, comments added? at the moment it seems to only show me total work items in team view, unassigned work items in team view, my request and my work. it doesn't tell me when my work items/my requests have been updated as in comments added or status changed?

    any ideas? or have I done something wrong?

  • Gerhard_GoossensGerhard_Goossens Customer Advanced IT Monkey ✭✭✭

    Hi All,

    Thank for this. I have set this up in our dev environment and I was wondering if its possible to show you when work items have been updated, e.g. status, comments added? at the moment it seems to only show me total work items in team view, unassigned work items in team view, my request and my work. it doesn't tell me when my work items/my requests have been updated as in comments added or status changed?

    any ideas? or have I done something wrong?

    I just came out of a meeting where this was discussed. 
  • Gerhard_GoossensGerhard_Goossens Customer Advanced IT Monkey ✭✭✭
    I changed the code a bit to only show the badges on My Work and Team Work.
    Our analysts are trying to be very productive and open up to 20 tabs that create a lot of noise on the DB.

    So it just wrapped the code that generates the badge in an if statement to check if they are on My Work or Team Work :-)

    if (window.location.href.indexOf("f94d43eb-eb42-4957-8c48-95b9b903c631") > -1 || window.location.href.indexOf("cca5abda-6803-4833-accd-d59a43e2d2cf") > -1) {
    var badgeObserver = new MutationObserver(function (mutations) {
    var targetElement = $('#side_nav');
    if (targetElement.length > 0) {
    ApplyStyleSheetBadge(); // Add CSS
    createBadges(); // This will run on page load
    setInterval(function () {
    loadBadges() // this will run after every 60 seconds
    }, 120000);
    badgeObserver.disconnect();
    }
    });
    }

  • Ryan_LaneRyan_Lane Customer Advanced IT Monkey ✭✭✭
    Hi @Gerhard_Goossens
    To work with productive users and their multiple tabs I would suggest looking into using session storage to share badge count data between open tabs/windows on a single client.  The portal already uses the store plugin accessed via app.storage to handle sharing session data between page loads and tabs for navigation, grid states, view panels and quite a few other features.
    In my case I primarily use store for handing debug state and custom data between page loads:
    // Get custom session storage.
    app.storage.custom = store.namespace('custom');
    
    // Check if custom session storage value 'DEBUG_ENABLED' is true.
    if (app.storage.custom('DEBUG_ENABLED')) { // Debug Code Here } // Enable DEBUG Mode via Console/Script/Plugin // app.storage.custom.set('DEBUG_ENABLED', true); // Disable DEBUG Mode via Console/Script/Plugin // app.storage.custom.set('DEBUG_ENABLED', false);
    Making this session data useful for a multiple tab, asynchronous setup is a bit more involved then just adding a check during run-time so we're going to look at adding a listener to each window to monitor and process changes.  Fortunately, whenever store is used there is a storage event that we can subscribe to.
    Here's some example code to monitor for and set session data changes via the storage event:
    /*
     * Add listener for storage event in all tabs.
     */
    $(window).on('storage', function (event) {
      if (event.key === 'custom.BadgeContent') {
        // Update Badge Content Here
        console.log('BadgeContent Updated', {
          oldValue: event.originalEvent.oldValue,
          newValue: event.originalEvent.newValue,
        });
      }
    });
    
    /*
     * Set custom session value in tab.
     * storage event will trigger in all tabs except originating tab.
     */ 
    app.storage.custom.set('BadgeContent', {test: performance.now()} );
    
    Here's the code in action with two separate windows passing data to each other:
    Initial event subscription using $.on() in both left and right windows:

    From there we call set in the left window which triggers the storage event in the right window:

    Continuing we call set in the right window which triggers the storage event in the left window:


    From this point it's a matter of organizing how each tab will know that the data needs to be refreshed and when.  I think something like a LastModified timestamp and PendingUpdate timestamp to track how old the current badge data is and if another tab is potentially retrieving the data would be a good start.
    The pseudo workflow for intervals would be:
    Set 60 second interval for checking LastModified session value.
    On interval elapsed check if LastModified is older than timeout value (~60 seconds).
      If true then:
        Check if PendingUpdate is older than pending timeout value (~2 seconds or average max query duration) to account for closed tabs/windows.
          If true then:
              Set PendingUpdate timestamp and retrieve data in current tab.
              Once data is returned: Set LastModified timestamp. Update badge count displays in current tab. Update session data to trigger storage listeners in other tabs.
          If false then:
              Do nothing and wait for next 60 second interval to elapse.
      If false then:
        Do nothing and wait for next 60 second interval to elapse.
    Note With this there will be a little bit of play depending on when the secondary tab(s) load that could account for a small range of waiting between refreshes in secondary tabs.  Checking immediately for stored data on page load and then performing the interval may resolve this issue.
    Additional Note Checking to see if window/tab is currently active could also help in determining when and which tabs should refresh their badge counts.

    Hopefully this was helpful as an idea for handling the increased traffic.  Please let me know if you have any questions.  I'd be glad to help!
  • Steve_ClarkeSteve_Clarke Customer Adept IT Monkey ✭✭
    edited March 14
    Hey guys,

    I have created a new view for unassigned requests based off of a saved search. I am not sure how to reference this saved search in the following code, particularly the highlighted line which I believe would need to get the search result count.

    if(myRequests) {
    $.getJSON('/api/V3/WorkItem/GetGridWorkItemsMyRequests', { "userId": session.user.Id,"showInactiveItems": false }, function (data) {var badge = $('a[href="/Page/4534db6e-462d-4676-88c9-f684c19eb3ce"] .menu-badge');if (data.length > 0) {badge.removeClass('no-badge');badge.text(data.length);} else {badge.addClass('no-badge');badge.text('');}});}



    If anyone could provide some assistance that would be awesome.

    Thanks,

    Steve
  • Tom_HendricksTom_Hendricks Customer Super IT Monkey ✭✭✭✭✭
    You are correct, you need to point to a different endpoint for your saved search.  You'll have to try this out, but I'll try to point you in the right direction.

    On a saved search page, the grid itself calls
    /search/GetAdHocResults?dataTable="WorkItem"&filterCriteria=<<huge JSON object representing your search criteria>>

    If you want to grab the particular filter for your particular search, go to the saved search page for your unassigned requests, and in the browser console, type 
    var grid = $($('div.grid-container')[0]).data('kendoGrid'); var filterCriteria = grid.dataSource.options.transport.read.data.filterCriteria;
    Just copy the value of filterCriteria to the clipboard.

    Then you can modify your code above to something like:
    if(myRequests) {
    $.getJSON('/search/GetAdHocResults', { "dataTable": "WorkItem", "filterCriteria": << PASTE YOUR CRITERIA HERE, IN QUOTES >> }, function (data) { var badge = $('a[href="/Page/4534db6e-462d-4676-88c9-f684c19eb3ce"] .menu-badge'); if (data.length > 0) { badge.removeClass('no-badge'); badge.text(data.length); } else { badge.addClass('no-badge'); badge.text(''); } }); }

  • Tom_HendricksTom_Hendricks Customer Super IT Monkey ✭✭✭✭✭
    @Ryan_Lane, I have tried out your idea.  I've had some trouble carving out time to really dig in and measure it, but at a quick glance at least, I think it is working!
  • Steve_ClarkeSteve_Clarke Customer Adept IT Monkey ✭✭
    Thanks @Tom_Hendricks. I am still struggling to get it working but thank you for the starting point.
  • Tom_HendricksTom_Hendricks Customer Super IT Monkey ✭✭✭✭✭
    This is the part I haven't had time to look at, but I wonder if it might be causing you issues--I'm not sure if the results from saved searches are coming back in a single JSON object, or from many.  I say that only because of all the network traffic that occurs with a saved search grid vs a SQL or OData grid.  What I pulled in my example is from the DataSource on the Kendo grid, but there might be more going on here in addition.  

    At some point, I would probably say that re-writing this as a SQL query would be much easier, but I also kind of want to see how this could work.  :)
  • Steve_ClarkeSteve_Clarke Customer Adept IT Monkey ✭✭
    Thanks for your help @Tom_Hendricks. Funny you should say about the SQL query because that is exactly what I did on Friday. Ended up getting it working that way which was much easier in the end, and probably a bit cleaner.

    Thanks again for jumping in and providing your thoughts/assistance  :)
  • Gerhard_GoossensGerhard_Goossens Customer Advanced IT Monkey ✭✭✭
    @Brett_Moffett WOW, this is awesome. Thank you for the commitment to make this awesome addon even better. 
  • Mark_GearyMark_Geary Customer IT Monkey ✭
    HI I use this but I cant get it to work on the Active work as we have changed the name of ours to It department work list. What do I need to change to with this?
  • Brett_MoffettBrett_Moffett Cireson PACE Super IT Monkey ✭✭✭✭✭
    You will need to grab the view's GUID (In the URL of the page) and replace it in the JS code.
    The code is fairly well documented so you should see where to replace it.
    Let me know if you need a hand and we can work through it here on the community.
  • Mark_GearyMark_Geary Customer IT Monkey ✭
    Hi I have put the GUID from the URL in the one area in the JS and in the SQL as well for the active work Items but it still is not showing works on the rest.
  • Brett_MoffettBrett_Moffett Cireson PACE Super IT Monkey ✭✭✭✭✭

    Hello all.

    New version.

    Version 1.2.1

    1. You can now configure the number of days a Work Item is not modified for before it shows up on the Stale Work Item count.

    You can get the latest version at the GitHub repository:

    https://github.com/BrettMoff/CiresonBadges
    


    Future Features:

    • Disable\Enable Count badge (Not sure this is a particularly useful badge)
    • Setting for refresh time


  • Matt_OvertonMatt_Overton Customer IT Monkey ✭

    Thanks for this @Brett_Moffett !


    I'm having a similar issue to @Mark_Geary where I can't seem to get it to work for the pages that have different GUIDs. I've copied the GUIDs for My Work, My Requests and Active Work into the JS in the relevant places, but no joy - the badges simply aren't appearing on any of them.

    I can only get it to work for the Team icons and Watch List. What could I be doing wrong?

Sign In or Register to comment.