2

1

When I look at a case with a lot of events, it can be overwhelming.

Is there a way to make it so that events that I've already seen are hidden (or at least truncated)?

flag

2 Answers

1

The following BugMonkey script shows one way to have more control over which/how case events are displayed:

// Provide a menu on case view that allows you to do one of the following:
//   View all events
//   Show all events as one-line summaries
//   Show seen events as one-line summaries
//   Hide seen events
$(document).ready(function() {
    // Don't do anything unless we're looking at a single bug
    if (!window.goBug || 
        !$("#bugviewContainer").length || 
        $("#miniBugList").length) 
        return;

    // The text displayed in the display menu
    var modes = {
        showAll: {
            text: "Show All",
            label: "Showing all events",
            show: ".bugevent"
        },
        summarizeAll: {
            text: "Summarize All",
            label: "Summarizing all events",
            show: ".small-summary"
        },
        summarizeSeen: {
            text: "Summarize Seen",
            label: "Summarizing #seen events",
            show: ".bugevent:not(.seen),.small-summary.seen"
        },
        hideSeen: {
            text: "Hide Seen",
            label: "Hiding #seen events",
            show: ".bugevent:not(.seen)"
        }
    };

    // The name of the cookie used to save settings
    var sCookie = "sSeenEventMode";

    // Read the user's current settings.  Default is to show all
    var sSeenMode = getCookie(sCookie) || "showAll";

    // Determine the last event the user saw
    var ixLastView = goBug.ixBugEventLastView;

    // A table describing the translation from a standard bug event 
    // to its summary
    var summTrans = [
        { sel: ".action", color: "#000", css: { "font-weight": "bold"} },
        { sel: ".date a", color: "#68615e" },
        { fnHtml: function(ev) {
            return (ev.find(".emailBody").html() || ev.find(".body").html() || "").
               replace(/<[^>]*>/g, " ");
        }, color: "#888"
        },
        { sel: ".changes", color: "#aaa" }
    ];

    var jAllEvents = $("#BugEvents .bugevent");

    // Process bug events we've already seen
    var numSeen =
    jAllEvents
    // Filter out events we haven't seen
    .filter(function() { 
       return /\d+/.exec($(this).attr("id")) <= ixLastView; 
    })
    .addClass("seen")
    .length;

    // Process all visible bug events
    jAllEvents
    .each(function() {
        var ev = $(this);

        // Create the event summary 
        var divSummary = $("<div>")
        .addClass("small-summary")
        .css({
            "white-space": "nowrap",
            overflow: "hidden",
            "text-overflow": "ellipsis",
            "font-size": "10px",
            "margin-bottom": "4px",
            "cursor": "pointer"
        })
        .insertBefore(this)
        .click(function() {
            // Clicking anywhere on the summary hides it 
            // and displays the full bug event
            $(this).hide().next(".bugevent").show();
        });

        if (ev.hasClass("seen")) divSummary.addClass("seen");

        // Convert the bug event into a summary
        $.each(summTrans, function(ix, tbl) {
            var entry = $("<span>")
            .css(tbl.css)
            .css({
                color: tbl.color,
                "margin-right": "4px"
            })
            .appendTo(divSummary);

            if (tbl.fnHtml)
                entry.html(tbl.fnHtml(ev));
            else
                entry.text(ev.find(tbl.sel).text())
        });
    });

    var divMenu = $("<div>")
    .css({
        "margin-bottom": "1em",
        border: "1px dotted #888",
        padding: "4px",
        "background-color": "#f4f4f4"
    })
    .insertBefore("#BugEvents");

    var spanLabel = $("<span>")
    .css({
        "font-weight": "bold",
        "float": "right"
    })
    .appendTo(divMenu);

    // Set the display mode
    var setMode = function(ev, sMode) {
        // If this is being used as an event handler, 
        // get the mode from the link that was clicked
        sMode = sMode || $(this).attr("mode");

        // Don't underline the link that represents the current display mode
        divMenu.find("a")
        .css("text-decoration", function() {
            return $(this).attr("mode") == sMode ? "none" : "underline";
        });

        // Only show the events/summaries allowed by the user's selection
        $("#BugEvents").find(".bugevent,.small-summary")
        .hide()
        .filter(modes[sMode].show)
        .show();

        // Update the label
        spanLabel.html(modes[sMode].label.replace(/#seen/g, numSeen));

        // Remember the user's selection
        setCookie(sCookie, sMode);
    };

    // Add the display modes to the menu
    for (var mode in modes) {
        $("<a>")
        .text(modes[mode].text)
        .css("margin", ".5em")
        .attr({ href: "javascript:void(0)", mode: mode })
        .appendTo(divMenu)
        .click(setMode);
    }

    // Apply the user's saved mode
    setMode(null, sSeenMode);
});

If you'd like to use the code as is, you can use the Closure compiled version:

$(document).ready(function(){if(!(!window.goBug||!$("#bugviewContainer").length||$("#miniBugList").length)){var e={showAll:{text:"Show All",label:"Showing all events",show:".bugevent"},summarizeAll:{text:"Summarize All",label:"Summarizing all events",show:".small-summary"},summarizeSeen:{text:"Summarize Seen",label:"Summarizing #seen events",show:".bugevent:not(.seen),.small-summary.seen"},hideSeen:{text:"Hide Seen",label:"Hiding #seen events",show:".bugevent:not(.seen)"}},i=getCookie("sSeenEventMode")||
"showAll",j=goBug.ixBugEventLastView,k=[{sel:".action",color:"#000",css:{"font-weight":"bold"}},{sel:".date a",color:"#68615e"},{fnHtml:function(b){return(b.find(".emailBody").html()||b.find(".body").html()||"").replace(/<[^>]*>/g," ")},color:"#888"},{sel:".changes",color:"#aaa"}],c=$("#BugEvents .bugevent"),l=c.filter(function(){return/\d+/.exec($(this).attr("id"))<=j}).addClass("seen").length;c.each(function(){var b=$(this),a=$("<div>").addClass("small-summary").css({"white-space":"nowrap",overflow:"hidden",
"text-overflow":"ellipsis","font-size":"10px","margin-bottom":"4px",cursor:"pointer"}).insertBefore(this).click(function(){$(this).hide().next(".bugevent").show()});b.hasClass("seen")&&a.addClass("seen");$.each(k,function(n,d){var g=$("<span>").css(d.css).css({color:d.color,"margin-right":"4px"}).appendTo(a);d.fnHtml?g.html(d.fnHtml(b)):g.text(b.find(d.sel).text())})});var f=$("<div>").css({"margin-bottom":"1em",border:"1px dotted #888",padding:"4px","background-color":"#f4f4f4"}).insertBefore("#BugEvents"),
m=$("<span>").css({"font-weight":"bold","float":"right"}).appendTo(f);c=function(b,a){a=a||$(this).attr("mode");f.find("a").css("text-decoration",function(){return $(this).attr("mode")==a?"none":"underline"});$("#BugEvents").find(".bugevent,.small-summary").hide().filter(e[a].show).show();m.html(e[a].label.replace(/#seen/g,l));setCookie("sSeenEventMode",a)};for(var h in e)$("<a>").text(e[h].text).css("margin",".5em").attr({href:"javascript:void(0)",mode:h}).appendTo(f).click(c);c(null,i)}});
link|flag
Cool! . – Michel de Ruiter Dec 4 2010 at 14:41
Any chance of making this work with #miniBugList cases? – Michel de Ruiter Jan 10 2011 at 16:09
Any chance we could get a screenshot added, and also updated to work with the new import tool? – cdeszaq Jan 10 2011 at 21:37
This doesn't seem to work in FBOD v8.8.6.0H (DB 794, Build 0) – CADbloke Feb 7 2012 at 2:35
actually, it alters the CSS but the menu is not on the page anywhere – CADbloke Feb 7 2012 at 3:04
show 1 more comment
1

I took Daniel's version and tried to improve on it over time.

Major new features:

  • summary tooltips
  • easily expand, collapse or hide individual events
  • integrated Toggle quoted texts link
  • border color makes unseen events stand out

Minor improvements and fixes:

  • changed to BugMonkey 2 format
  • compatible with Tidy Case Events and Case Event Merge plugins
  • works with recent FogBugz (.summary, jQuery version)
  • compatible with minor, pseudo and borrowed events
  • updates on edits
  • added extra counts
  • changed Summarize All position

I tested it with recent versions of FogBugz: I might have broken older versions.

Hope this helps. At least I find it very useful!

Screen shot: alt text

name:          Summarize Events
description:   Add menu to case to summarize/hide seen events or summarize/show all events
author:        Daniel LeCheminant, Michel de Ruiter
version:       1.2.7.0

js:

if (!window.goBug || !$("#bugviewContainer").length || $("#miniBugList").length)
  return; // Don't do anything unless we're looking at a single bug :-(
var modes = { // The text displayed in the display menu
  showAll: {
    text:  "Show All",
    label: "Showing all #all (seen #seen)",
    show:  ".bugevent:not(.minor),.pseudobugevent,.small-summary.minor"
  },
  summarizeSeen: {
    text:  "Summarize Seen",
    label: "Summarizing #seen of #all",
    show:  ".bugevent:not(.seen),.small-summary.seen:not(.minor,.SOcollapsed)"
  },
  hideSeen: {
    text:  "Hide Seen",
    label: "Hiding #seen of #all",
    show:  ".bugevent:not(.seen)"
  },
  space1: {
    text:  ""
  },
  summarizeAll: {
    text:  "Summarize All",
    label: "Summarizing all #alls (seen #seen)",
    show:  ".small-summary:not(.SOcollapsed)"
  },
  space2: {
    text:  ""
  }
};
var summTrans = [ // A table describing the translation from a standard bug event to its summary
  { sel: ".action",  color: "#000", css: { "font-weight": "bold"} },
  { sel: ".date a",  color: "#68615e" },
  { fnHtml: function(ev) {
      return (ev.find(".emailBody").html() || ev.find(".body").html() || "").replace(/<[^>]*>/g, " ");
    },               color: "#888" },
  { sel: ".changes", color: "#aaa" }
];
$.fn.textNodes = function() {
  var ret = [];
  (function(el) {
    if (el === undefined) // Necessary when "Not showing ... additional events"
      return;
    if (el.nodeType == 3)
      ret.push(el.innerHTML || el.textContent || "");
    else
      for (var i = 0; i < el.childNodes.length; ++i)
        arguments.callee(el.childNodes[i]);
  })(this[0]);
  return ret;
}
var sCookie = "sSeenEventMode"; // Name of the cookie used to save settings
$("#BugEvents > .bugevent:hidden").addClass("minor"); // Initially hidden events are 'minor' ones.
function doIt(sCommand) {
  var sSeenMode = getCookie(sCookie) || "showAll"; // Default to all
  var jAllEvents = $("#BugEvents .summary").parent();
  var numAll = jAllEvents.length;
  var ixLastView = goBug.ixBugEventLastView;   // Determine the last event the user saw.
  var jSeen = jAllEvents.filter(function() {   // Process bug events we've already seen.
    return /\d+/.exec($(this).attr("id") || "0") <= ixLastView; // Pseudo events are always 'seen',
  });
  if (jSeen.length < numAll)
    jSeen = jSeen.add('.borrowed .bugevent');  // as are old events 'borrowed' from duplicates.
  var numSeen = jSeen.addClass("seen").length;
  var numHidden = $("#BugEvents .bugevent.minor:not(.seen)").length;
  $('div.small-summary').remove(); // Remove any existing ones
  jAllEvents.each(function() { // Process all visible bug events
    var ev = $(this); // Create the event summary:
    var txt = ev.find(".body").clone();
    txt.find("script,.showQuote,pre.linenos,.emailActionsMore").remove();
    txt.find(".emailHeaderName").each(function(i) {
      $(this).replaceWith($(this).text() + " " + $(this).next().remove().text());
    });
    txt.find(".codesnippet").each(function(i) {
      $(this).find("br").replaceWith("\n");
      $(this).replaceWith($(this).find(".prettyprint").text());
    });
    txt.find("br").remove();
    txt = txt.textNodes();
    $.each(txt, function(i, v) {
      txt[i] = v.replace(/^\n/, "");
    });
    txt = $.makeArray(txt);
    txt = txt.join("\n");
    txt = txt.replace(/\s+$/g, "");
    txt = txt.replace(/^\s+/g, "");
    txt = txt.replace(/[ \t\xA0]+$/mg, "");
    txt = txt.replace(/\n\n+$/mg, "\n");
    var divSummary = $("<div>").addClass("small-summary").attr("title", txt).css({
        "white-space":   "nowrap",
        "overflow":      "hidden",
        "text-overflow": "ellipsis",
        "font-size":     "10px",
        "margin-bottom": "3px",
        "cursor":        "pointer"
      }).insertBefore(this)
      .click(function() { // Clicking the summary hides it and displays the full bug event
        $(this).hide().next(".bugevent,.pseudobugevent").show();
      });
    if (ev.hasClass("minor"))
      divSummary.addClass("minor");
    if (ev.hasClass("seen"))
      divSummary.addClass("seen");
    if (ev.has('input.scratchedOutFlagScratch').length > 0)
      divSummary.addClass("SOcollapsed");
    $.each(summTrans, function(ix, tbl) { // Convert the bug event into a summary
      var entry = $("<span>").css({
          "color":        tbl.color,
          "margin-right": "4px"
        }).appendTo(divSummary);
      if (tbl.css)
        entry.css(tbl.css);
      if (tbl.fnHtml)
        entry.html(tbl.fnHtml(ev));
      else
        entry.text(ev.find(tbl.sel).text());
    });
  });
  $("#BugEvents .summary").filter(":not(:has(.topright))").prepend($("<div>").addClass("topright")
    .append($("<a>").text("\u2014").attr("title", "Summarize").click(function() {
        $(this).closest(".summary").parent().hide().prev(".small-summary").show();
      }))
    .append($("<a>").text("\xD7").attr("title", "Hide").click(function() {
        $(this).closest(".summary").parent().hide();
      })));
  $('div#summarize').remove(); // Remove any existing one
  var divMenu = $("<div>").attr("id", "summarize").css({
    "margin-bottom":    "6px",
    "border":           "1px dotted #888",
    "padding":          "4px",
    "background-color": "#f4f4f4"
  }).insertBefore("#BugEvents");
  var spanLabel = $("<span>").css({
    "font-weight": "bold",
    "float":       "right"
  }).appendTo(divMenu);
  var setMode = function(ev, sMode) { // Set the display mode
    // If this is being used as an event handler, get the mode from the link that was clicked
    sMode = sMode || $(this).attr("mode");
    // Don't underline the link that represents the current display mode
    divMenu.find("a").css("text-decoration", function() {
      return $(this).attr("mode") == sMode ? "none" : "underline";
    });
    // Only show the events/summaries allowed by the user's selection
    $("#BugEvents").find(".bugevent,.pseudobugevent,.small-summary")
    .hide().filter(modes[sMode].show).show();
    spanLabel.html(modes[sMode].label
                   .replace(/#seen/g,   numSeen)
                   .replace(/#all/g,    numAll)
                   .replace(/#hidden/g, numHidden));
    setCookie(sCookie, sMode); // Remember the user's selection
  };
  for (var mode in modes) { // Add the display modes to the menu
    $("<a>").text(modes[mode].text).css("margin", ".5em")
    .attr({ href: "javascript:void(0)", mode: mode })
    .appendTo(divMenu).click(setMode);
  }
  var quotedTexts = $(".showQuote > a[href='#'][onclick]");
  if (quotedTexts.length > 0) {
    $("<a>").text("Toggle quoted texts").css("margin", ".5em")
      .attr("title", quotedTexts.length)
      .attr("href", "javascript:void(0)").appendTo(divMenu)
      .click(function() {
        $(".showQuote > a[href='#'][onclick]").each(function(){ this.onclick(); });
      });
  }
  if (sCommand == 'load')
    setMode(null, sSeenMode); // Apply the user's saved mode
}
doIt($("#sEventEdit").length > 0 ? "new" : "load");
$(window).on("BugViewChange", function(e, data) { doIt(data.sCommand); });
// Work around ListBrowser skipping hidden elements:
var originalFlipAttachDeleteIcons = TabManager.flipAttachDeleteIcons;
TabManager.flipAttachDeleteIcons = function(sCommand) {
  var hidden = $("#BugEvents").find(".bugevent:hidden,.pseudobugevent:hidden").show();
  originalFlipAttachDeleteIcons(sCommand);
  hidden.hide();
};


css:

/* The Case Event Merge plugin makes this "none" by default. */
#bugviewContainer #BugEvents .borrowed .bugevent.brief { display: block; }
#bugviewContainer .bugevents .borrowed .bugevent       em.borrowed { font-size: 10px; line-height: 10px; }
#bugviewContainer .bugevents           .bugevent       { border: 1px solid #808080 !important; }
#bugviewContainer .bugevents     .pseudobugevent,
#bugviewContainer .bugevents           .bugevent.seen  { border: 1px solid #C0C0C0 !important; }
#bugviewContainer .bugevents     .pseudobugevent.minor,
#bugviewContainer .bugevents           .bugevent.minor { border: 1px solid yellow  !important; }
#BugEvents .summary div.topright                       { float: right; }
#BugEvents .summary div.topright a                     { font-size: 9px; margin-left: 6px; cursor: pointer; }
#bugviewContainerTop                                   { margin-bottom: 2px; }
link|flag

Your Answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.