Add VE logging to floating buttons

This CL adds visual logging to the floating action buttons in the
Elements, Network, and Sources panels.

A `jslog-context` attribute was added to the `FloatingButton`
component to allow specifying a logging context. This will allow
tracking of clicks on these buttons for analytics.

The visual logging debugging documentation was also updated to
reflect the latest state of the debugging UI.

Fixed: 429381292
Change-Id: I30a3227d99fbd26aa19962a2b56be21cb949ed10
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6728038
Reviewed-by: Danil Somsikov <[email protected]>
Auto-Submit: Natallia Harshunova <[email protected]>
Reviewed-by: Ergün Erdoğmuş <[email protected]>
Commit-Queue: Danil Somsikov <[email protected]>
diff --git a/front_end/panels/elements/ElementsTreeElement.ts b/front_end/panels/elements/ElementsTreeElement.ts
index 2155f01..fc885c1 100644
--- a/front_end/panels/elements/ElementsTreeElement.ts
+++ b/front_end/panels/elements/ElementsTreeElement.ts
@@ -564,7 +564,7 @@
     const action = UI.ActionRegistry.ActionRegistry.instance().getAction('freestyler.elements-floating-button');
     if (this.contentElement && !this.aiButtonContainer) {
       this.aiButtonContainer = this.contentElement.createChild('span', 'ai-button-container');
-      const floatingButton = Buttons.FloatingButton.create('smart-assistant', action.title());
+      const floatingButton = Buttons.FloatingButton.create('smart-assistant', action.title(), 'ask-ai');
       floatingButton.addEventListener('click', ev => {
         ev.stopPropagation();
         this.select(true, false);
diff --git a/front_end/panels/network/NetworkDataGridNode.ts b/front_end/panels/network/NetworkDataGridNode.ts
index 04fc691..0ec8080 100644
--- a/front_end/panels/network/NetworkDataGridNode.ts
+++ b/front_end/panels/network/NetworkDataGridNode.ts
@@ -1538,7 +1538,7 @@
       const action = UI.ActionRegistry.ActionRegistry.instance().getAction('drjones.network-floating-button');
       const aiButtonContainer = document.createElement('span');
       aiButtonContainer.classList.add('ai-button-container');
-      const floatingButton = Buttons.FloatingButton.create('smart-assistant', action.title());
+      const floatingButton = Buttons.FloatingButton.create('smart-assistant', action.title(), 'ask-ai');
       floatingButton.addEventListener('click', ev => {
         ev.stopPropagation();
         this.select();
diff --git a/front_end/panels/sources/NavigatorView.ts b/front_end/panels/sources/NavigatorView.ts
index f96d421..b7d22fb 100644
--- a/front_end/panels/sources/NavigatorView.ts
+++ b/front_end/panels/sources/NavigatorView.ts
@@ -1453,7 +1453,7 @@
     const action = UI.ActionRegistry.ActionRegistry.instance().getAction('drjones.sources-floating-button');
     if (!this.aiButtonContainer) {
       this.aiButtonContainer = this.listItemElement.createChild('span', 'ai-button-container');
-      const floatingButton = Buttons.FloatingButton.create('smart-assistant', action.title());
+      const floatingButton = Buttons.FloatingButton.create('smart-assistant', action.title(), 'ask-ai');
       floatingButton.addEventListener('click', ev => {
         ev.stopPropagation();
         this.navigatorView.sourceSelected(this.uiSourceCode, false);
diff --git a/front_end/ui/components/buttons/FloatingButton.ts b/front_end/ui/components/buttons/FloatingButton.ts
index 13a8d16..8316d74 100644
--- a/front_end/ui/components/buttons/FloatingButton.ts
+++ b/front_end/ui/components/buttons/FloatingButton.ts
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 /* eslint-disable rulesdir/no-lit-render-outside-of-view */
-
 import '../icon_button/icon_button.js';
 
+import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
 import * as Lit from '../../lit/lit.js';
 
 import floatingButtonStyles from './floatingButton.css.js';
@@ -31,10 +31,14 @@
  *
  * @attr icon-name - The basename of the icon file (not including the `.svg`
  *                   suffix).
- * @prop {String} iconName - The `"icon-name"` attribute is reflected as property.
+ * @attr jslogcontext - The context for the `jslog` attribute. A `jslog`
+ *                      attribute is generated automatically with the
+ *                      provided context.
+ * @prop {String} iconName - The `"icon-name"` attribute is reflected as a property.
+ * @prop {String} jslogContext - The `"jslogcontext"` attribute is reflected as a property.
  */
 export class FloatingButton extends HTMLElement {
-  static readonly observedAttributes = ['icon-name'];
+  static readonly observedAttributes = ['icon-name', 'jslogcontext'];
 
   readonly #shadow = this.attachShadow({mode: 'open'});
 
@@ -67,6 +71,18 @@
     }
   }
 
+  get jslogContext(): string|null {
+    return this.getAttribute('jslogcontext');
+  }
+
+  set jslogContext(jslogContext: string|null) {
+    if (jslogContext === null) {
+      this.removeAttribute('jslogcontext');
+    } else {
+      this.setAttribute('jslogcontext', jslogContext);
+    }
+  }
+
   attributeChangedCallback(name: string, oldValue: string|null, newValue: string|null): void {
     if (oldValue === newValue) {
       return;
@@ -74,6 +90,9 @@
     if (name === 'icon-name') {
       this.#render();
     }
+    if (name === 'jslogcontext') {
+      this.#updateJslog();
+    }
   }
 
   #render(): void {
@@ -84,20 +103,32 @@
         this.#shadow, {host: this});
     // clang-format on
   }
+
+  #updateJslog(): void {
+    if (this.jslogContext) {
+      this.setAttribute('jslog', `${VisualLogging.action().track({click: true}).context(this.jslogContext)}`);
+    } else {
+      this.removeAttribute('jslog');
+    }
+  }
 }
 
 /**
  * Helper function to programmatically create a `FloatingButton` instance with a
  * given `iconName` and `title`.
  *
- * @param iconName the name of the icon to use.
+ * @param iconName the name of the icon to use
  * @param title the tooltip for the `FloatingButton`
+ * @param jslogContext the context string for the `jslog` attribute
  * @returns the newly created `FloatingButton` instance.
  */
-export const create = (iconName: string, title: string): FloatingButton => {
+export const create = (iconName: string, title: string, jslogContext?: string): FloatingButton => {
   const floatingButton = new FloatingButton();
   floatingButton.iconName = iconName;
   floatingButton.title = title;
+  if (jslogContext) {
+    floatingButton.jslogContext = jslogContext;
+  }
   return floatingButton;
 };
 
diff --git a/front_end/ui/visual_logging/KnownContextValues.ts b/front_end/ui/visual_logging/KnownContextValues.ts
index 3e2d566..d13cba8 100644
--- a/front_end/ui/visual_logging/KnownContextValues.ts
+++ b/front_end/ui/visual_logging/KnownContextValues.ts
@@ -463,6 +463,7 @@
   'arial',
   'as',
   'ascent-override',
+  'ask-ai',
   'aspect-ratio',
   'asserted-events',
   'asus-zenbook-fold',
diff --git a/front_end/ui/visual_logging/README.md b/front_end/ui/visual_logging/README.md
index 2408659..74289bd 100644
--- a/front_end/ui/visual_logging/README.md
+++ b/front_end/ui/visual_logging/README.md
@@ -202,9 +202,7 @@
 setVeDebuggingEnabled(true);
 ```
 
-in DevTools on DevTools. This will add red outline to each visual element and
-will show the details of logging config for an element and all its ancestors on
-hover.
+in DevTools on DevTools. This will show the details of logging config for an element and all its ancestors on hover.
 
 ![Visual Element debugging in DevTools on DevTools](visual_logging_debugging.png)
 
diff --git a/front_end/ui/visual_logging/visual_logging_debugging.png b/front_end/ui/visual_logging/visual_logging_debugging.png
index 541a8fd..18f2e06 100644
--- a/front_end/ui/visual_logging/visual_logging_debugging.png
+++ b/front_end/ui/visual_logging/visual_logging_debugging.png
Binary files differ