[ui] Port counter tracks to plugin tracks.

Summary:
- Each track instance has it's own state - accessed via mountState()
- Created 'CounterTrack' track impl for all counter tracks - port of
  the original controller based track.
- Added suggestTrack() to TracePluginContext which replaces
  findPotentialTracks().
- Added new "annotation" plugin for annotation counter tracks.
- Moved kind, cpu, trackIds, to PluginTrackInfo. kind is required,
  but the others are optional. Use this new interface everywhere they
  were previously extracted from config (e.g. aggregations, flows).
- Added new command "Find track by URI".

Change-Id: I6e75ee3dcf16ceb13b0cefd0a5743daa22d5e2c0
diff --git a/ui/src/frontend/track_panel.ts b/ui/src/frontend/track_panel.ts
index 8dffff1..2c2d5e7 100644
--- a/ui/src/frontend/track_panel.ts
+++ b/ui/src/frontend/track_panel.ts
@@ -18,12 +18,13 @@
 import {currentTargetOffset} from '../base/dom_utils';
 import {Icons} from '../base/semantic_icons';
 import {duration, Span, time} from '../base/time';
+import {exists} from '../base/utils';
 import {Actions} from '../common/actions';
 import {pluginManager} from '../common/plugins';
 import {RegistryError} from '../common/registry';
 import {TrackState} from '../common/state';
 import {raf} from '../core/raf_scheduler';
-import {TrackLike} from '../public';
+import {Migrate, TrackContext, TrackLike} from '../public';
 
 import {SELECTION_FILL_COLOR, TRACK_SHELL_WIDTH} from './css_constants';
 import {globals} from './globals';
@@ -68,24 +69,37 @@
   return selectedArea.tracks.includes(id);
 }
 
-interface TrackChipsAttrs {
-  config: {[k: string]: any};
+interface TrackChipAttrs {
+  text: string;
 }
 
-export class TrackChips implements m.ClassComponent<TrackChipsAttrs> {
-  view({attrs}: m.CVnode<TrackChipsAttrs>) {
-    const {config} = attrs;
-
-    const isMetric = 'namespace' in config;
-    const isDebuggable = ('isDebuggable' in config) && config.isDebuggable;
-
-    return [
-      isMetric && m('span.chip', 'metric'),
-      isDebuggable && m('span.chip', 'debuggable'),
-    ];
+class TrackChip implements m.ClassComponent<TrackChipAttrs> {
+  view({attrs}: m.CVnode<TrackChipAttrs>) {
+    return m('span.chip', attrs.text);
   }
 }
 
+export function renderChips({uri, config}: TrackState) {
+  const tagElements: m.Children = [];
+  if (exists(uri)) {
+    const trackInfo = pluginManager.resolveTrackInfo(uri);
+    const tags = trackInfo?.tags;
+    tags?.metric && tagElements.push(m(TrackChip, {text: 'metric'}));
+    tags?.debuggable && tagElements.push(m(TrackChip, {text: 'debuggable'}));
+  } else {
+    if (config && typeof config === 'object') {
+      if ('namespace' in config) {
+        tagElements.push(m(TrackChip, {text: 'metric'}));
+      }
+      if ('isDebuggable' in config && config.isDebuggable) {
+        tagElements.push(m(TrackChip, {text: 'debuggable'}));
+      }
+    }
+  }
+
+  return tagElements;
+}
+
 interface TrackShellAttrs {
   track: TrackLike;
   trackState: TrackState;
@@ -134,7 +148,7 @@
               },
             },
             attrs.trackState.name,
-            m(TrackChips, {config: attrs.trackState.config}),
+            renderChips(attrs.trackState),
             ),
         m('.track-buttons',
           attrs.track.getTrackShellButtons(),
@@ -352,8 +366,21 @@
     if (!trackState) return;
 
     const {id, uri} = trackState;
-    this.track =
-        uri ? pluginManager.createTrack(uri, id) : loadTrack(trackState, id);
+
+    const trackCtx: TrackContext = {
+      trackInstanceId: id,
+      mountStore: <T>(migrate: Migrate<T>) => {
+        const {store, state} = globals;
+        const migratedState = migrate(state.tracks[trackId].state);
+        globals.store.edit((draft) => {
+          draft.tracks[trackId].state = migratedState;
+        });
+        return store.createProxy<T>(['tracks', trackId, 'state']);
+      },
+    };
+
+    this.track = uri ? pluginManager.createTrack(uri, trackCtx) :
+                       loadTrack(trackState, id);
     this.track?.onCreate();
     this.trackState = trackState;
   }