[status] Incorporate app-sk into status-sk.

--Basic header with login-sk and darkmode toggle.
--Left panel with navigation and collapsible AutoRoller panel
--Minor improvements to app-sk.scss (add fill where color is set,
--Minor improvments to table and navigation scss.
--content-vert-padding, and use body instead of root for variables,
so they honor darkmode.)
--Add repo-changed event to commits-table to update header.

Change-Id: Ib367e0cfe9fa9cc98f7c28dd46c99877f390c466
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/327757
Reviewed-by: Eric Boren <borenet@google.com>
Commit-Queue: Weston Tracey <westont@google.com>
diff --git a/infra-sk/modules/app-sk/app-sk.scss b/infra-sk/modules/app-sk/app-sk.scss
index 2193ef5..01cdcbf 100644
--- a/infra-sk/modules/app-sk/app-sk.scss
+++ b/infra-sk/modules/app-sk/app-sk.scss
@@ -11,12 +11,12 @@
     --sidebar-width: 250px;
   }
 
-Note that app-sk is more specific than :root so the above variables will
+Note that app-sk will inherit from body so the above variables will
 over-ride the defaults regardless of the processing order of the CSS files.
 
 */
 
-:root {
+body {
   --sidebar-width: 200px;
   --sidebar-horiz-padding: 5px;
   --sidebar-background-color: var(--on-primary, --white);
@@ -26,6 +26,7 @@
   --header-font-color: var(--on-primary, --white);
 
   --content-horiz-padding: 5px;
+  --content-vert-padding: 0px;
 
   --footer-height: 0;
 }
@@ -38,6 +39,7 @@
 
 app-sk {
   color: var(--on-background, --black);
+  fill: var(--on-background, --black);
   background: var(--background, --white);
   display: grid;
   grid-template-columns: var(--sidebar-width) 1fr;
@@ -52,6 +54,7 @@
     flex-flow: row;
     justify-content: flex-start;
     color: var(--header-font-color);
+    fill: var(--header-font-color);
 
     grid-column: 1 / span 2;
     grid-row: 1;
@@ -72,7 +75,7 @@
   }
 
   main {
-    padding: 0 var(--content-horiz-padding);
+    padding: var(--content-vert-padding) var(--content-horiz-padding);
     grid-row: 2;
   }
 
diff --git a/status/modules/commits-table-sk/commits-table-sk.scss b/status/modules/commits-table-sk/commits-table-sk.scss
index 67b2d5b..ce26550 100644
--- a/status/modules/commits-table-sk/commits-table-sk.scss
+++ b/status/modules/commits-table-sk/commits-table-sk.scss
@@ -101,6 +101,7 @@
       position: relative;
       top: 30px;
       left: 3px;
+      width: min-content;
     }
 
     select {
@@ -116,9 +117,6 @@
       input {
         width: 100px;
       }
-      .input-container {
-        width: 180px;
-      }
     }
   }
 
diff --git a/status/modules/commits-table-sk/commits-table-sk.ts b/status/modules/commits-table-sk/commits-table-sk.ts
index a0e63a9..9c40f2a 100644
--- a/status/modules/commits-table-sk/commits-table-sk.ts
+++ b/status/modules/commits-table-sk/commits-table-sk.ts
@@ -8,6 +8,8 @@
  * 'search'. To filter taskSpecs displayed.
  * @property search - a regex string with which to filter taskSpecs against for
  * display. Only used if filter == 'search'.
+ *
+ * @event repo-changed - Occurs when user selects a repo. Event has {detail: '<new repo>'}
  */
 
 import { $, $$ } from 'common-sk/modules/dom';
@@ -460,7 +462,15 @@
     >
       <div id="repoContainer">
         <div id="repoLabel">Repo:</div>
-        <select id="repoSelector" @change=${() => el.update()}>
+        <select
+          id="repoSelector"
+          @change=${(e: Event) => {
+            el.dispatchEvent(
+              new CustomEvent('repo-changed', { bubbles: true, detail: (e.target as any).value })
+            );
+            el.update();
+          }}
+        >
           ${repos().map((r) => html`<option value=${r}>${r}</option>`)}
         </select>
       </div>
diff --git a/status/modules/navigation-sk/navigation-sk.scss b/status/modules/navigation-sk/navigation-sk.scss
index 8ad815b..ad2a8b5 100644
--- a/status/modules/navigation-sk/navigation-sk.scss
+++ b/status/modules/navigation-sk/navigation-sk.scss
@@ -2,6 +2,11 @@
 
 navigation-sk {
   color: var(--on-surface);
+
+  > div {
+    padding: 5px;
+  }
+
   a.item {
     text-decoration: none;
     color: var(--on-surface);
diff --git a/status/modules/status-sk/status-sk-demo.ts b/status/modules/status-sk/status-sk-demo.ts
index 6566a71..4c94427 100644
--- a/status/modules/status-sk/status-sk-demo.ts
+++ b/status/modules/status-sk/status-sk-demo.ts
@@ -10,7 +10,11 @@
   swarmingUrl: 'example.com/swarming',
   taskSchedulerUrl: 'example.com/ts',
   defaultRepo: 'skia',
-  repos: new Map([['skia', 'https://skia.googlesource.com/skia/+show/']]),
+  repos: new Map([
+    ['skia', 'https://skia.googlesource.com/skia/+show/'],
+    ['infra', 'https://skia.googlesource.com/buildbot/+show/'],
+    ['skcms', 'https://skia.googlesource.com/skcms/+show/'],
+  ]),
 });
 const data = document.createElement('status-sk');
 ($$('#container') as HTMLElement).appendChild(data);
diff --git a/status/modules/status-sk/status-sk.scss b/status/modules/status-sk/status-sk.scss
index c8fdbc2..fd920f2 100644
--- a/status/modules/status-sk/status-sk.scss
+++ b/status/modules/status-sk/status-sk.scss
@@ -1,9 +1,26 @@
 @import '../styles.scss';
 
 status-sk {
-  autoroller-status-sk {
-    // TODO(westont): Temporary, this will be going into a fixed panel.
-    float: left;
-    margin: 10px;
+  app-sk {
+    --sidebar-width: auto;
+    --sidebar-horiz-padding: 0;
+    --content-horiz-padding: 5px;
+    --content-vert-padding: 5px;
+    aside {
+      z-index: 2;
+      > * {
+        border: 1px solid var(--primary);
+        padding: 1px;
+        margin: 5px;
+      }
+
+      .collapser {
+        width: 100%;
+        text-transform: none;
+        padding: 0 0.5em 0 0;
+        margin: 0;
+        height: auto;
+      }
+    }
   }
 }
diff --git a/status/modules/status-sk/status-sk.ts b/status/modules/status-sk/status-sk.ts
index 2c388d0..f79ae95 100644
--- a/status/modules/status-sk/status-sk.ts
+++ b/status/modules/status-sk/status-sk.ts
@@ -5,22 +5,67 @@
  * The majority of the Status page.
  */
 import { define } from 'elements-sk/define';
-import { html } from 'lit-html';
+import { html, TemplateResult } from 'lit-html';
 import { ElementSk } from '../../../infra-sk/modules/ElementSk';
 
 import '../../../infra-sk/modules/theme-chooser-sk';
-import '../commits-table-sk';
+import '../../../infra-sk/modules/app-sk';
+import '../../../infra-sk/modules/login-sk';
 import '../autoroller-status-sk';
+import '../commits-table-sk';
+import '../navigation-sk';
+import 'elements-sk/collapse-sk';
 import 'elements-sk/error-toast-sk';
+import 'elements-sk/icon/expand-less-icon-sk';
+import 'elements-sk/icon/expand-more-icon-sk';
+import { defaultRepo } from '../settings';
+
+function collapsableTemplate(content: TemplateResult): TemplateResult {
+  return html` <div>${content}</div> `;
+}
 
 export class StatusSk extends ElementSk {
-  private static template = (ele: StatusSk) =>
+  private repo: string = defaultRepo();
+  private autorollersOpen: boolean = true;
+  private static template = (el: StatusSk) =>
     html`
-      <h2>lit-html/TS/Twirp Status Page Under Development</h2>
-      <theme-chooser-sk></theme-chooser-sk>
-      <autoroller-status-sk></autoroller-status-sk>
-      <commits-table-sk></commits-table-sk>
-      <error-toast-sk></error-toast-sk>
+      <app-sk>
+        <header>
+          <h1>Status: ${el.repo}</h1>
+          <div class="spacer"></div>
+          <login-sk></login-sk>
+          <theme-chooser-sk></theme-chooser-sk>
+        </header>
+        <aside>
+          <div><navigation-sk></navigation-sk></div>
+          <div>
+            <button
+              class="collapser"
+              @click=${(e: Event) => {
+                el.autorollersOpen = !el.autorollersOpen;
+                el.toggle((<HTMLButtonElement>e.target).nextElementSibling);
+              }}
+            >
+              ${el.autorollersOpen
+                ? html`<expand-less-icon-sk></expand-less-icon-sk>`
+                : html`<expand-more-icon-sk></expand-more-icon-sk>`}
+              AutoRollers
+            </button>
+            <collapse-sk>
+              <autoroller-status-sk></autoroller-status-sk>
+            </collapse-sk>
+          </div>
+        </aside>
+
+        <main>
+          <commits-table-sk
+            @repo-changed=${(e: CustomEvent) => el.updateRepo(e.detail)}
+          ></commits-table-sk>
+          <error-toast-sk></error-toast-sk>
+        </main>
+
+        <footer><error-toast-sk></error-toast-sk></footer>
+      </app-sk>
     `;
 
   constructor() {
@@ -29,6 +74,16 @@
 
   connectedCallback() {
     super.connectedCallback();
+    this.updateRepo(defaultRepo());
+  }
+
+  private toggle(collapseSk: any) {
+    collapseSk.closed = !collapseSk.closed;
+    this._render();
+  }
+
+  private updateRepo(r: string) {
+    this.repo = r.charAt(0).toUpperCase() + r.slice(1);
     this._render();
   }
 }
diff --git a/status/modules/status-sk/status-sk_puppeteer_test.ts b/status/modules/status-sk/status-sk_puppeteer_test.ts
index 7fa2cc9..5937c4e 100644
--- a/status/modules/status-sk/status-sk_puppeteer_test.ts
+++ b/status/modules/status-sk/status-sk_puppeteer_test.ts
@@ -1,9 +1,6 @@
 import * as path from 'path';
 import { expect } from 'chai';
-import {
-  setUpPuppeteerAndDemoPageServer,
-  takeScreenshot,
-} from '../../../puppeteer-tests/util';
+import { setUpPuppeteerAndDemoPageServer, takeScreenshot } from '../../../puppeteer-tests/util';
 
 describe('status-sk', () => {
   const testBed = setUpPuppeteerAndDemoPageServer(
@@ -23,5 +20,9 @@
     it('shows the default view', async () => {
       await takeScreenshot(testBed.page, 'status', 'status-sk');
     });
+    it('changes repos', async () => {
+      testBed.page.select('#repoSelector', 'infra');
+      await takeScreenshot(testBed.page, 'status', 'status-sk_repo_change');
+    });
   });
 });
diff --git a/status/modules/status-sk/status-sk_test.ts b/status/modules/status-sk/status-sk_test.ts
new file mode 100644
index 0000000..f773946
--- /dev/null
+++ b/status/modules/status-sk/status-sk_test.ts
@@ -0,0 +1,42 @@
+import './index';
+import { StatusSk } from './status-sk';
+
+import { eventPromise, setUpElementUnderTest } from '../../../infra-sk/modules/test_util';
+import { expect } from 'chai';
+import { $, $$ } from 'common-sk/modules/dom';
+import { incrementalResponse0, SetupMocks } from '../rpc-mock';
+import fetchMock from 'fetch-mock';
+import { SetTestSettings } from '../settings';
+
+describe('status-sk', () => {
+  const newInstance = setUpElementUnderTest<StatusSk>('status-sk');
+
+  let element: StatusSk;
+  beforeEach(async () => {
+    SetTestSettings({
+      swarmingUrl: 'example.com/swarming',
+      taskSchedulerUrl: 'example.com/ts',
+      defaultRepo: 'skia',
+      repos: new Map([
+        ['skia', 'https://skia.googlesource.com/skia/+show/'],
+        ['infra', 'https://skia.googlesource.com/buildbot/+show/'],
+        ['skcms', 'https://skia.googlesource.com/skcms/+show/'],
+      ]),
+    });
+    fetchMock.getOnce('path:/loginstatus/', {});
+    SetupMocks().expectGetIncrementalCommits(incrementalResponse0);
+    const ep = eventPromise('end-task');
+    element = newInstance();
+    await ep;
+  });
+
+  it('reacts to repo-changed', async () => {
+    expect($$('h1', element)).to.have.property('innerText', 'Status: Skia');
+    const repoSelector = $$('#repoSelector', element) as HTMLSelectElement;
+    repoSelector.value = 'infra';
+    const ep = eventPromise('end-task');
+    repoSelector.dispatchEvent(new Event('change', { bubbles: true }));
+    await ep;
+    expect($$('h1', element)).to.have.property('innerText', 'Status: Infra');
+  });
+});