perfetto-ui: Move trace loading UI into mithril

- Remove dummy elements from index.html
- Create frontend/nav.html as a minimal nav bar.
- Move trace loading ui into frontend/home_page.ts
- Use m.route instead of m.mount.

Change-Id: I6a2acddb303d44fbe65dcbc9cf0c08864532188b
diff --git a/ui/index.html b/ui/index.html
index 9254be4..8027631 100644
--- a/ui/index.html
+++ b/ui/index.html
@@ -36,11 +36,6 @@
   </style>
 </head>
 <body>
-  <div id="console">
-    WASM output goes here
-  </div>
-  <input type="file" id="trace" name="trace"/>
-  <button id="query">Query</button>
   <div id="frontend">
     Loading...
   </div>
diff --git a/ui/src/frontend/home_page.ts b/ui/src/frontend/home_page.ts
index e6bde62..1515a2e 100644
--- a/ui/src/frontend/home_page.ts
+++ b/ui/src/frontend/home_page.ts
@@ -13,10 +13,46 @@
 // limitations under the License.
 
 import * as m from 'mithril';
-import {Frontend} from './';
 
-export const HomePage = {
-  view() {
-    return m(Frontend, {width: 1000, height: 300});
+import {Engine} from '../engine';
+import {WasmEngineProxy} from '../engine/wasm_engine_proxy';
+
+import {createPage} from './pages';
+
+function extractBlob(e: Event): Blob|null {
+  if (!(e.target instanceof HTMLInputElement)) {
+    throw new Error('Not input element');
   }
-} as m.Component;
+  if (!e.target.files) return null;
+  return e.target.files.item(0);
+}
+
+// TODO(hjd): Temporary while bringing up controller worker.
+let engine: Engine|null = null;
+
+export const HomePage = createPage({
+  view() {
+    return m(
+        'div',
+        m('input[type=file]', {
+          onchange: (e: Event) => {
+            const blob = extractBlob(e);
+            if (!blob) return;
+            engine = WasmEngineProxy.create(blob);
+          },
+        }),
+        m('button',
+          {
+            disabled: engine === null,
+            onclick: () => {
+              if (!engine) return;
+              engine
+                  .rawQuery({
+                    sqlQuery: 'select * from sched;',
+                  })
+                  .then(console.log);
+            },
+          },
+          'Query'));
+  }
+});
diff --git a/ui/src/frontend/index.ts b/ui/src/frontend/index.ts
index e573917..86ece0a 100644
--- a/ui/src/frontend/index.ts
+++ b/ui/src/frontend/index.ts
@@ -15,9 +15,10 @@
 import * as m from 'mithril';
 
 import {CanvasWrapper} from './canvas_wrapper';
+import {createPage} from './pages';
 import {Track} from './track';
 
-export const Frontend = {
+const Frontend = {
   view({attrs}) {
     return m(
         '.frontend',
@@ -32,3 +33,9 @@
         m(Track, {name: 'Track 123'}), );
   }
 } as m.Component<{width: number, height: number}>;
+
+export const FrontendPage = createPage({
+  view() {
+    return m(Frontend, {width: 1000, height: 300});
+  }
+});
diff --git a/ui/src/frontend/pages.ts b/ui/src/frontend/pages.ts
new file mode 100644
index 0000000..f38a876
--- /dev/null
+++ b/ui/src/frontend/pages.ts
@@ -0,0 +1,38 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import * as m from 'mithril';
+
+const Nav = {
+  view() {
+    return m(
+        'ul',
+        m('li', m('a[href=/]', {oncreate: m.route.link}, 'Home')),
+        m('li', m('a[href=/viewer]', {oncreate: m.route.link}, 'Viewer')), );
+  }
+} as m.Component;
+
+/**
+ * Wrap component with common UI elements (nav bar etc).
+ */
+export function createPage(component: m.Component): m.Component {
+  return {
+    view() {
+      return [
+        m(Nav),
+        m(component),
+      ];
+    },
+  };
+}
diff --git a/ui/src/main.ts b/ui/src/main.ts
index 511da1c..44479da 100644
--- a/ui/src/main.ts
+++ b/ui/src/main.ts
@@ -15,11 +15,8 @@
 import * as m from 'mithril';
 
 import {createEmptyState} from './common/state';
-import {Engine} from './engine';
-import {
-  warmupWasmEngineWorker,
-  WasmEngineProxy
-} from './engine/wasm_engine_proxy';
+import {warmupWasmEngineWorker} from './engine/wasm_engine_proxy';
+import {FrontendPage} from './frontend';
 import {gState} from './frontend/globals';
 import {HomePage} from './frontend/home_page';
 
@@ -32,36 +29,21 @@
   };
 }
 
-function main(input: Element, button: Element) {
+function main() {
   gState.set(createEmptyState());
   createController();
   warmupWasmEngineWorker();
 
-  // tslint:disable-next-line:no-any
-  input.addEventListener('change', (e: any) => {
-    const blob: Blob = e.target.files.item(0);
-    if (blob === null) return;
-    const engine: Engine = WasmEngineProxy.create(blob);
-    button.addEventListener('click', () => {
-      engine
-          .rawQuery({
-            sqlQuery: 'select * from sched;',
-          })
-          .then(result => console.log(result));
-    });
-  });
-
   const root = document.getElementById('frontend');
   if (!root) {
     console.error('root element not found.');
     return;
   }
 
-  m.mount(root, HomePage);
+  m.route(root, '/', {
+    '/': HomePage,
+    '/viewer': FrontendPage,
+  });
 }
 
-const input = document.querySelector('#trace');
-const button = document.querySelector('#query');
-if (input && button) {
-  main(input, button);
-}
+main();