Web Inspector: REGRESSION(r242604): Console: unread indicator overlaps selection background of previous scope bar item
https://bugs.webkit.org/show_bug.cgi?id=204630

Reviewed by Timothy Hatcher.

When a new message is added that is immediately filtered, such as from an existing filter or
previously selected scope bar items, rather than show a blinking circle next to the level of
the new message in the scope bar (which doesn't cover the case where there's a filter and
was often hard to notice), add a dismissable warning banner explaning that the message had
been filtered with a button to clear all filters.

* UserInterface/Views/LogContentView.js:
(WI.LogContentView):
(WI.LogContentView.prototype.didAppendConsoleMessageView):
(WI.LogContentView.prototype._previousMessageRepeatCountUpdated):
(WI.LogContentView.prototype._logCleared):
(WI.LogContentView.prototype._messageSourceBarSelectionDidChange):
(WI.LogContentView.prototype._scopeBarSelectionDidChange):
(WI.LogContentView.prototype._filterMessageElements):
(WI.LogContentView.prototype._showHiddenMessagesBannerIfNeeded): Added.
(WI.LogContentView.prototype._markScopeBarItemUnread): Deleted.
(WI.LogContentView.prototype._markScopeBarItemForMessageLevelUnread): Deleted.
* UserInterface/Views/LogContentView.css:
(.content-view.log):
(.content-view.log > .hidden-messages-banner): Added.
(.content-view.log > .hidden-messages-banner > button): Added.
(.content-view.log > .hidden-messages-banner > .dismiss): Added.
(body[dir=ltr] .content-view.log > .hidden-messages-banner > .dismiss): Added.
(body[dir=rtl] .content-view.log > .hidden-messages-banner > .dismiss): Added.
(.console-messages):
(.log-scope-bar > li:not(.unread) > .indicator): Deleted.
(.log-scope-bar > li.unread > .indicator): Deleted.
(.log-scope-bar > li.unread:hover > .indicator): Deleted.
(.log-scope-bar > li.unread.evaluations > .indicator): Deleted.
(.log-scope-bar > li.unread.errors > .indicator): Deleted.
(.log-scope-bar > li.unread.warnings > .indicator): Deleted.
(.log-scope-bar > li.unread.logs > .indicator): Deleted.
(@keyframes unread-background-pulse): Deleted.

* UserInterface/Views/FindBanner.js:
(WI.FindBanner):
(WI.FindBanner.prototype.clearAndBlur): Added.
(WI.FindBanner.prototype._clearAndBlur): Deleted.
Expose a public way to clear the find banner.

* Localizations/en.lproj/localizedStrings.js:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@253173 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog
index 553d8f0..cac8e4d 100644
--- a/Source/WebInspectorUI/ChangeLog
+++ b/Source/WebInspectorUI/ChangeLog
@@ -1,5 +1,54 @@
 2019-12-05  Devin Rousso  <drousso@apple.com>
 
+        Web Inspector: REGRESSION(r242604): Console: unread indicator overlaps selection background of previous scope bar item
+        https://bugs.webkit.org/show_bug.cgi?id=204630
+
+        Reviewed by Timothy Hatcher.
+
+        When a new message is added that is immediately filtered, such as from an existing filter or
+        previously selected scope bar items, rather than show a blinking circle next to the level of
+        the new message in the scope bar (which doesn't cover the case where there's a filter and
+        was often hard to notice), add a dismissable warning banner explaning that the message had
+        been filtered with a button to clear all filters.
+
+        * UserInterface/Views/LogContentView.js:
+        (WI.LogContentView):
+        (WI.LogContentView.prototype.didAppendConsoleMessageView):
+        (WI.LogContentView.prototype._previousMessageRepeatCountUpdated):
+        (WI.LogContentView.prototype._logCleared):
+        (WI.LogContentView.prototype._messageSourceBarSelectionDidChange):
+        (WI.LogContentView.prototype._scopeBarSelectionDidChange):
+        (WI.LogContentView.prototype._filterMessageElements):
+        (WI.LogContentView.prototype._showHiddenMessagesBannerIfNeeded): Added.
+        (WI.LogContentView.prototype._markScopeBarItemUnread): Deleted.
+        (WI.LogContentView.prototype._markScopeBarItemForMessageLevelUnread): Deleted.
+        * UserInterface/Views/LogContentView.css:
+        (.content-view.log):
+        (.content-view.log > .hidden-messages-banner): Added.
+        (.content-view.log > .hidden-messages-banner > button): Added.
+        (.content-view.log > .hidden-messages-banner > .dismiss): Added.
+        (body[dir=ltr] .content-view.log > .hidden-messages-banner > .dismiss): Added.
+        (body[dir=rtl] .content-view.log > .hidden-messages-banner > .dismiss): Added.
+        (.console-messages):
+        (.log-scope-bar > li:not(.unread) > .indicator): Deleted.
+        (.log-scope-bar > li.unread > .indicator): Deleted.
+        (.log-scope-bar > li.unread:hover > .indicator): Deleted.
+        (.log-scope-bar > li.unread.evaluations > .indicator): Deleted.
+        (.log-scope-bar > li.unread.errors > .indicator): Deleted.
+        (.log-scope-bar > li.unread.warnings > .indicator): Deleted.
+        (.log-scope-bar > li.unread.logs > .indicator): Deleted.
+        (@keyframes unread-background-pulse): Deleted.
+
+        * UserInterface/Views/FindBanner.js:
+        (WI.FindBanner):
+        (WI.FindBanner.prototype.clearAndBlur): Added.
+        (WI.FindBanner.prototype._clearAndBlur): Deleted.
+        Expose a public way to clear the find banner.
+
+        * Localizations/en.lproj/localizedStrings.js:
+
+2019-12-05  Devin Rousso  <drousso@apple.com>
+
         Web Inspector: add WI.EngineeringSetting and WI.DebugSetting to avoid callsite checking
         https://bugs.webkit.org/show_bug.cgi?id=204785
 
diff --git a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
index f9dcdbd..7c26f34 100644
--- a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
+++ b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
@@ -594,6 +594,7 @@
 localizedStrings["Heap Snapshot %s-%s-%s at %s.%s.%s"] = "Heap Snapshot %s-%s-%s at %s.%s.%s";
 localizedStrings["Heap Snapshot Object (%s)"] = "Heap Snapshot Object (%s)";
 localizedStrings["Height"] = "Height";
+localizedStrings["Hide"] = "Hide";
 localizedStrings["Hide Console"] = "Hide Console";
 localizedStrings["Hide Console (%s)"] = "Hide Console (%s)";
 localizedStrings["Hide Elements"] = "Hide Elements";
@@ -1164,6 +1165,7 @@
 localizedStrings["The contents and enabled state will be preserved across Web Inspector sessions."] = "The contents and enabled state will be preserved across Web Inspector sessions.";
 localizedStrings["The page's content has changed"] = "The page's content has changed";
 localizedStrings["The resource was requested insecurely."] = "The resource was requested insecurely.";
+localizedStrings["There are unread messages that have been filtered"] = "There are unread messages that have been filtered";
 localizedStrings["There is an incurred energy penalty each time the page enters script. This commonly happens with timers, event handlers, and observers."] = "There is an incurred energy penalty each time the page enters script. This commonly happens with timers, event handlers, and observers.";
 localizedStrings["These are all of the different test result levels."] = "These are all of the different test result levels.";
 localizedStrings["These are all of the different types of data that can be returned with the test result."] = "These are all of the different types of data that can be returned with the test result.";
diff --git a/Source/WebInspectorUI/UserInterface/Views/FindBanner.js b/Source/WebInspectorUI/UserInterface/Views/FindBanner.js
index 05783aa..d8ec625 100644
--- a/Source/WebInspectorUI/UserInterface/Views/FindBanner.js
+++ b/Source/WebInspectorUI/UserInterface/Views/FindBanner.js
@@ -74,7 +74,7 @@
         this._nextResultButton.appendChild(nextResultButtonGlyphElement);
 
         if (fixed)
-            this._clearAndBlurKeyboardShortcut = new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Escape, this._clearAndBlur.bind(this), this.element);
+            this._clearAndBlurKeyboardShortcut = new WI.KeyboardShortcut(null, WI.KeyboardShortcut.Key.Escape, this.clearAndBlur.bind(this), this.element);
         else {
             let doneButtonElement = document.createElement("button");
             doneButtonElement.textContent = WI.UIString("Done");
@@ -164,7 +164,7 @@
             this._inputField.select();
     }
 
-    _clearAndBlur()
+    clearAndBlur()
     {
         this.numberOfResults = null;
 
diff --git a/Source/WebInspectorUI/UserInterface/Views/LogContentView.css b/Source/WebInspectorUI/UserInterface/Views/LogContentView.css
index a9efbc3..261b891 100644
--- a/Source/WebInspectorUI/UserInterface/Views/LogContentView.css
+++ b/Source/WebInspectorUI/UserInterface/Views/LogContentView.css
@@ -23,62 +23,58 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-.log-scope-bar > li:not(.unread) > .indicator {
-    display: none;
-}
-
-.log-scope-bar > li.unread > .indicator {
-    display: inline-block;
-    width: 8px;
-    height: 8px;
-    animation: unread-background-pulse 1.5s ease-in-out infinite alternate-reverse;
-    -webkit-clip-path: circle(50% at 50% 50%);
-
-    -webkit-margin-start: -10px;
-    -webkit-margin-end: 2px;
-}
-
-.log-scope-bar > li.unread:hover > .indicator {
-    visibility: hidden;
-}
-
-.log-scope-bar > li.unread.evaluations > .indicator {
-    background-color: darkgrey;
-}
-
-.log-scope-bar > li.unread.errors > .indicator {
-    background-color: hsl(0, 95%, 72%);
-}
-
-.log-scope-bar > li.unread.warnings > .indicator {
-    background-color: hsl(48, 98%, 51%);
-}
-
-.log-scope-bar > li.unread.logs > .indicator {
-    background-color: hsl(213, 92%, 77%);
-}
-
-@keyframes unread-background-pulse {
-    from { background-color: transparent; }
-}
-
 .content-view.log {
-    overflow-y: auto;
-    overflow-x: hidden;
+    display: flex;
+    flex-direction: column;
+}
+
+.content-view.log > .hidden-messages-banner {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    position: relative;
+    height: var(--navigation-bar-height);
+    padding: 0 4px;
+    color: var(--yellow-highlight-text-color);
+    background-color: var(--yellow-highlight-background-color);
+    border-bottom: 1px solid var(--border-color);
+}
+
+.content-view.log > .hidden-messages-banner {
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+}
+
+.content-view.log > .hidden-messages-banner > button {
+    -webkit-margin-start: 4px;
+}
+
+.content-view.log > .hidden-messages-banner > .dismiss {
+    position: absolute;
+    width: 16px;
+    height: 16px;
+    padding-bottom: 2px;
+}
+
+body[dir=ltr] .content-view.log > .hidden-messages-banner > .dismiss {
+    right: 5px;
+}
+
+body[dir=rtl] .content-view.log > .hidden-messages-banner > .dismiss {
+    left: 5px;
 }
 
 .console-messages {
     display: flex;
     flex-direction: column;
-
-    word-wrap: break-word;
-
+    height: 100%;
     font-family: -webkit-system-font, sans-serif;
     font-size: 12px;
-
-    min-height: 100%;
-
+    word-wrap: break-word;
     outline: none;
+    overflow-x: hidden;
+    overflow-y: auto;
 }
 
 .console-messages > :first-child {
diff --git a/Source/WebInspectorUI/UserInterface/Views/LogContentView.js b/Source/WebInspectorUI/UserInterface/Views/LogContentView.js
index def8161..3121723 100644
--- a/Source/WebInspectorUI/UserInterface/Views/LogContentView.js
+++ b/Source/WebInspectorUI/UserInterface/Views/LogContentView.js
@@ -33,6 +33,7 @@
 
         this._nestingLevel = 0;
         this._selectedMessages = [];
+        this._immediatelyHiddenMessages = new Set;
 
         // FIXME: Try to use a marker, instead of a list of messages that get re-added.
         this._provisionalMessages = [];
@@ -96,12 +97,6 @@
             new WI.ScopeBarItem(WI.LogContentView.Scopes.Infos, WI.UIString("Infos"), {className: "infos", hidden: true}),
             new WI.ScopeBarItem(WI.LogContentView.Scopes.Debugs, WI.UIString("Debugs"), {className: "debugs", hidden: true}),
         ];
-
-        for (let scopeBarItem of scopeBarItems) {
-            let indicatorElement = scopeBarItem.element.insertBefore(document.createElement("div"), scopeBarItem.element.firstChild);
-            indicatorElement.className = "indicator";
-        }
-
         this._scopeBar = new WI.ScopeBar("log-scope-bar", scopeBarItems, scopeBarItems[0]);
         this._scopeBar.visibilityPriority = WI.NavigationItem.VisibilityPriority.High;
         this._scopeBar.addEventListener(WI.ScopeBar.Event.SelectionChanged, this._scopeBarSelectionDidChange, this);
@@ -237,12 +232,17 @@
         if (!this._scopeBar.item(WI.LogContentView.Scopes.All).selected) {
             if (messageView instanceof WI.ConsoleCommandView || messageView.message instanceof WI.ConsoleCommandResultMessage)
                 this._scopeBar.item(WI.LogContentView.Scopes.Evaluations).toggle(true, {extendSelection: true});
-            else
-                this._markScopeBarItemForMessageLevelUnread(messageView.message.level);
         }
 
         console.assert(messageView.element instanceof Element);
         this._filterMessageElements([messageView.element]);
+
+        if (!this._isMessageVisible(messageView.element)) {
+            this._immediatelyHiddenMessages.add(messageView);
+            this._showHiddenMessagesBannerIfNeeded();
+        }
+
+        this._lastMessageView = messageView;
     }
 
     get supportsSearch() { return true; }
@@ -441,22 +441,6 @@
         return undefined;
     }
 
-    _markScopeBarItemUnread(scope)
-    {
-        let item = this._scopeBar.item(scope);
-        if (item && !item.selected && !this._scopeBar.item(WI.LogContentView.Scopes.All).selected)
-            item.element.classList.add("unread");
-    }
-
-    _markScopeBarItemForMessageLevelUnread(level)
-    {
-        let scope = this._scopeFromMessageLevel(level);
-        if (!scope)
-            return;
-
-        this._markScopeBarItemUnread(scope);
-    }
-
     _messageAdded(event)
     {
         let message = event.data.message;
@@ -475,8 +459,17 @@
 
     _previousMessageRepeatCountUpdated(event)
     {
-        if (this._logViewController.updatePreviousMessageRepeatCount(event.data.count) && this._lastMessageView)
-            this._markScopeBarItemForMessageLevelUnread(this._lastMessageView.message.level);
+        if (!this._logViewController.updatePreviousMessageRepeatCount(event.data.count))
+            return;
+
+        if (this._lastMessageView) {
+            if (this._isMessageVisible(this._lastMessageView.element))
+                return;
+
+            this._immediatelyHiddenMessages.add(this._lastMessageView);
+        }
+
+        this._showHiddenMessagesBannerIfNeeded();
     }
 
     _handleContextMenuEvent(event)
@@ -831,19 +824,21 @@
 
     _logCleared(event)
     {
-        for (let item of this._scopeBar.items)
-            item.element.classList.remove("unread");
-
         for (let messageElement of this._allMessageElements()) {
             if (messageElement.__messageView)
                 messageElement.__messageView.clearSessionState();
         }
 
         this._logViewController.clear();
+
         this._nestingLevel = 0;
+        this._selectedMessages = [];
+        this._immediatelyHiddenMessages.clear();
 
         if (this._currentSearchQuery)
             this.performSearch(this._currentSearchQuery);
+
+        this._showHiddenMessagesBannerIfNeeded();
     }
 
     _showConsoleTab()
@@ -884,10 +879,9 @@
         if (items.some((item) => item.id === WI.LogContentView.Scopes.AllChannels))
             items = this._messageSourceBar.items;
 
-        for (let item of items)
-            item.element.classList.remove("unread");
-
         this._filterMessageElements(this._allMessageElements());
+
+        this._showHiddenMessagesBannerIfNeeded();
     }
 
     _scopeBarSelectionDidChange(event)
@@ -896,10 +890,9 @@
         if (items.some((item) => item.id === WI.LogContentView.Scopes.All))
             items = this._scopeBar.items;
 
-        for (let item of items)
-            item.element.classList.remove("unread");
-
         this._filterMessageElements(this._allMessageElements());
+
+        this._showHiddenMessagesBannerIfNeeded();
     }
 
     _filterMessageElements(messageElements)
@@ -912,9 +905,10 @@
                 visible = this._messageShouldBeVisible(messageElement.__message);
 
             let classList = messageElement.classList;
-            if (visible)
+            if (visible) {
                 classList.remove(WI.LogContentView.FilteredOutStyleClassName);
-            else {
+                this._immediatelyHiddenMessages.delete(messageElement.__messageView);
+            } else {
                 this._selectedMessages.remove(messageElement);
                 classList.remove(WI.LogContentView.SelectedStyleClassName);
                 classList.add(WI.LogContentView.FilteredOutStyleClassName);
@@ -1236,6 +1230,41 @@
         this._startedProvisionalLoad = false;
         this._provisionalMessages = [];
     }
+
+    _showHiddenMessagesBannerIfNeeded()
+    {
+        if (!this._immediatelyHiddenMessages.size) {
+            if (this._hiddenMessagesBannerElement)
+                this._hiddenMessagesBannerElement.remove();
+            return;
+        }
+
+        if (!this._hiddenMessagesBannerElement) {
+            this._hiddenMessagesBannerElement = document.createElement("div");
+            this._hiddenMessagesBannerElement.className = "hidden-messages-banner";
+
+            this._hiddenMessagesBannerElement.appendChild(document.createTextNode(WI.UIString("There are unread messages that have been filtered")));
+
+            let clearFiltersButtonElement = this._hiddenMessagesBannerElement.appendChild(document.createElement("button"));
+            clearFiltersButtonElement.textContent = WI.UIString("Clear Filters");
+            clearFiltersButtonElement.addEventListener("click", (event) => {
+                this._findBanner.clearAndBlur();
+                this._scopeBar.resetToDefault();
+                console.assert(!this._immediatelyHiddenMessages.size);
+
+                this._hiddenMessagesBannerElement.remove();
+            });
+
+            let dismissBannerIconElement = this._hiddenMessagesBannerElement.appendChild(WI.ImageUtilities.useSVGSymbol("Images/Close.svg", "dismiss", WI.UIString("Dismiss")));
+            dismissBannerIconElement.addEventListener("click", (event) => {
+                this._immediatelyHiddenMessages.clear();
+                this._hiddenMessagesBannerElement.remove();
+            });
+        }
+
+        if (this.element.firstChild !== this._hiddenMessagesBannerElement)
+            this.element.insertAdjacentElement("afterbegin", this._hiddenMessagesBannerElement);
+    }
 };
 
 WI.LogContentView.Scopes = {