You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ab...@apache.org on 2017/06/22 13:16:36 UTC

[09/21] ambari git commit: AMBARI-21314 Log Search UI: implement top bar. (ababiichuk)

AMBARI-21314 Log Search UI: implement top bar. (ababiichuk)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/e71ad966
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/e71ad966
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/e71ad966

Branch: refs/heads/branch-feature-logsearch-ui
Commit: e71ad9666728cd20c99c5528cdbd5b238d41f438
Parents: 8aa761f
Author: ababiichuk <ab...@hortonworks.com>
Authored: Thu May 25 13:57:40 2017 +0300
Committer: ababiichuk <ab...@hortonworks.com>
Committed: Thu Jun 22 15:28:31 2017 +0300

----------------------------------------------------------------------
 .../ambari-logsearch-web-new/.angular-cli.json  |  1 +
 .../src/app/app.component.html                  |  9 +-
 .../src/app/app.component.less                  | 26 +++++
 .../src/app/app.component.spec.ts               |  2 +-
 .../src/app/app.component.ts                    |  2 +-
 .../src/app/app.module.ts                       | 16 +++-
 .../src/app/http-client.service.spec.ts         | 57 -----------
 .../src/app/http-client.service.ts              | 97 -------------------
 .../app/login-form/login-form.component.spec.ts |  6 +-
 .../src/app/login-form/login-form.component.ts  |  2 +-
 .../app/menu-button/menu-button.component.html  | 31 ++++++
 .../app/menu-button/menu-button.component.less  | 29 ++++++
 .../menu-button/menu-button.component.spec.ts   | 87 +++++++++++++++++
 .../app/menu-button/menu-button.component.ts    | 73 +++++++++++++++
 .../src/app/mock-api-data.service.ts            | 25 -----
 .../src/app/services/actions.service.spec.ts    | 33 +++++++
 .../src/app/services/actions.service.ts         | 47 ++++++++++
 .../app/services/http-client.service.spec.ts    | 57 +++++++++++
 .../src/app/services/http-client.service.ts     | 99 ++++++++++++++++++++
 .../src/app/services/mock-api-data.service.ts   | 25 +++++
 .../src/app/top-menu/top-menu.component.html    | 18 ++++
 .../src/app/top-menu/top-menu.component.less    | 22 +++++
 .../src/app/top-menu/top-menu.component.spec.ts | 45 +++++++++
 .../src/app/top-menu/top-menu.component.ts      | 90 ++++++++++++++++++
 .../src/assets/.gitkeep                         |  0
 .../src/assets/i18n/en.json                     | 11 ++-
 26 files changed, 716 insertions(+), 194 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/.angular-cli.json
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/.angular-cli.json b/ambari-logsearch/ambari-logsearch-web-new/.angular-cli.json
index 2f90ebe..cc74739 100644
--- a/ambari-logsearch/ambari-logsearch-web-new/.angular-cli.json
+++ b/ambari-logsearch/ambari-logsearch-web-new/.angular-cli.json
@@ -26,6 +26,7 @@
       ],
       "scripts": [
         "../node_modules/jquery/dist/jquery.min.js",
+        "../node_modules/bootstrap/dist/js/bootstrap.min.js",
         "../src/vendor/js/bootstrap-logsearch.min.js"
       ],
       "environmentSource": "environments/environment.ts",

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.html
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.html b/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.html
index 8d9f6d0..9b44246 100644
--- a/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.html
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.html
@@ -15,5 +15,10 @@
   limitations under the License.
 -->
 
-<h1>{{'common.title' | translate}}</h1>
-<login-form *ngIf="!httpClient.isAuthorized"></login-form>
\ No newline at end of file
+<nav class="navbar">
+  <div class="container-fluid">
+    <h1 [ngClass]="{'full-flex-width': !httpClient.isAuthorized, 'navbar-left': true}">{{'common.title' | translate}}</h1>
+    <top-menu *ngIf="httpClient.isAuthorized" class="navbar-right"></top-menu>
+  </div>
+</nav>
+<login-form *ngIf="!httpClient.isAuthorized"></login-form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.less
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.less b/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.less
index 2944f98..d8410cf 100644
--- a/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.less
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.less
@@ -14,3 +14,29 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+.navbar {
+  border-radius: 0;
+  background-color: #323544;
+  color: #fff;
+
+  .container-fluid {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+
+  h1 {
+    flex-basis: 70%;
+    margin-bottom: 20px;
+    text-transform: uppercase;
+
+    &.full-flex-width {
+      flex-basis: 100%;
+    }
+  }
+
+  /deep/ top-menu {
+    flex-basis: 30%;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.spec.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.spec.ts
index dfe6fbf..96cb0b4 100644
--- a/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.spec.ts
@@ -21,7 +21,7 @@ import {TestBed, async} from '@angular/core/testing';
 import {Http} from '@angular/http';
 import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
 import {TranslateHttpLoader} from '@ngx-translate/http-loader';
-import {HttpClientService} from './http-client.service';
+import {HttpClientService} from './services/http-client.service';
 
 import {AppComponent} from './app.component';
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.ts
index 79cdc5d..fb79ccb 100644
--- a/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/app.component.ts
@@ -18,7 +18,7 @@
 
 import {Component} from '@angular/core';
 import {TranslateService} from '@ngx-translate/core';
-import {HttpClientService} from './http-client.service';
+import {HttpClientService} from './services/http-client.service';
 
 @Component({
   selector: 'app-root',

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/app.module.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/app.module.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/app.module.ts
index 2d132e2..e8dee1b 100644
--- a/ambari-logsearch/ambari-logsearch-web-new/src/app/app.module.ts
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/app.module.ts
@@ -21,14 +21,17 @@ import {NgModule, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
 import {FormsModule} from '@angular/forms';
 import {HttpModule, Http} from '@angular/http';
 import {InMemoryWebApiModule} from 'angular-in-memory-web-api';
-import {mockApiDataService} from './mock-api-data.service'
+import {mockApiDataService} from './services/mock-api-data.service'
 import {AlertModule} from 'ngx-bootstrap';
 import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
 import {TranslateHttpLoader} from '@ngx-translate/http-loader';
-import {HttpClientService} from './http-client.service';
+import {HttpClientService} from './services/http-client.service';
+import {ActionsService} from './services/actions.service';
 
 import {AppComponent} from './app.component';
 import {LoginFormComponent} from './login-form/login-form.component';
+import {TopMenuComponent} from './top-menu/top-menu.component';
+import {MenuButtonComponent} from './menu-button/menu-button.component';
 
 export function HttpLoaderFactory(http: Http) {
   return new TranslateHttpLoader(http, 'assets/i18n/', '.json');
@@ -37,7 +40,9 @@ export function HttpLoaderFactory(http: Http) {
 @NgModule({
   declarations: [
     AppComponent,
-    LoginFormComponent
+    LoginFormComponent,
+    TopMenuComponent,
+    MenuButtonComponent
   ],
   imports: [
     BrowserModule,
@@ -55,7 +60,10 @@ export function HttpLoaderFactory(http: Http) {
       }
     })
   ],
-  providers: [HttpClientService],
+  providers: [
+    HttpClientService,
+    ActionsService
+  ],
   bootstrap: [AppComponent],
   schemas: [CUSTOM_ELEMENTS_SCHEMA]
 })

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/http-client.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/http-client.service.spec.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/http-client.service.spec.ts
deleted file mode 100644
index ec8596d..0000000
--- a/ambari-logsearch/ambari-logsearch-web-new/src/app/http-client.service.spec.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 {TestBed, inject} from '@angular/core/testing';
-import {HttpModule, Request} from '@angular/http';
-import {HttpClientService} from './http-client.service';
-
-describe('HttpClientService', () => {
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      imports: [HttpModule],
-      providers: [HttpClientService]
-    });
-  });
-
-  it('should create service', inject([HttpClientService], (service: HttpClientService) => {
-    expect(service).toBeTruthy();
-  }));
-
-  describe('generateUrlString()', () => {
-    it('should generate URL from presets', inject([HttpClientService], (service:HttpClientService) => {
-      expect(service.generateUrlString('status')).toEqual('api/v1/status');
-    }));
-
-    it('should return explicit URL', inject([HttpClientService], (service:HttpClientService) => {
-      expect(service.generateUrlString('login')).toEqual('login');
-    }));
-  });
-
-  describe('generateUrl()', () => {
-    it('string parameter', inject([HttpClientService], (service:HttpClientService) => {
-      expect(service.generateUrl('status')).toEqual('api/v1/status');
-    }));
-
-    it('request object parameter', inject([HttpClientService], (service:HttpClientService) => {
-      let request = new Request({
-        url: 'status'
-      });
-      expect(service.generateUrl(request).url).toEqual('api/v1/status');
-    }));
-  });
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/http-client.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/http-client.service.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/http-client.service.ts
deleted file mode 100644
index 3585600..0000000
--- a/ambari-logsearch/ambari-logsearch-web-new/src/app/http-client.service.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 {Injectable} from '@angular/core';
-import {Observable} from 'rxjs/Observable';
-import {Http, XHRBackend, Request, RequestOptions, RequestOptionsArgs, Response} from '@angular/http';
-import 'rxjs/add/operator/map';
-import 'rxjs/add/operator/catch';
-
-@Injectable()
-export class HttpClientService extends Http {
-
-  constructor(backend: XHRBackend, defaultOptions: RequestOptions) {
-    super(backend, defaultOptions);
-  }
-
-  readonly apiPrefix = 'api/v1/';
-
-  readonly urls = {
-    status: 'status'
-  };
-
-  isAuthorized: boolean;
-
-  generateUrlString(url: string): string {
-    const presetUrl = this.urls[url];
-    return presetUrl ? (this.apiPrefix + this.urls[url]) : url;
-  }
-
-  generateUrl(url: string | Request): string | Request {
-    if (typeof url === 'string') {
-      return this.generateUrlString(url);
-    }
-    if (url instanceof Request) {
-      url.url = this.generateUrlString(url.url);
-      return url;
-    }
-  }
-
-  handleError(request: Observable<Response>) {
-    request.subscribe(null, (error: any) => {
-      if ([401, 403, 419].indexOf(error.status) > -1) {
-        this.isAuthorized = false;
-      }
-    });
-  }
-
-  request(url: string | Request, options?: RequestOptionsArgs):Observable<Response> {
-    let req = super.request(this.generateUrl(url), options);
-    this.handleError(req);
-    return req;
-  }
-
-  get(url: string, options?: RequestOptionsArgs):Observable<Response> {
-    return super.get(this.generateUrlString(url), options);
-  }
-
-  post(url: string, body: any, options?: RequestOptionsArgs):Observable<Response> {
-    return super.post(this.generateUrlString(url), body, options);
-  }
-
-  put(url: string, body: any, options?: RequestOptionsArgs):Observable<Response> {
-    return super.put(this.generateUrlString(url), body, options);
-  }
-
-  delete(url: string, options?: RequestOptionsArgs):Observable<Response> {
-    return super.delete(this.generateUrlString(url), options);
-  }
-
-  patch(url: string, body: any, options?: RequestOptionsArgs):Observable<Response> {
-    return super.patch(this.generateUrlString(url), body, options);
-  }
-
-  head(url: string, options?: RequestOptionsArgs):Observable<Response> {
-    return super.head(this.generateUrlString(url), options);
-  }
-
-  options(url: string, options?: RequestOptionsArgs):Observable<Response> {
-    return super.options(this.generateUrlString(url), options);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/login-form/login-form.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/login-form/login-form.component.spec.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/login-form/login-form.component.spec.ts
index b58e834..55d125a 100644
--- a/ambari-logsearch/ambari-logsearch-web-new/src/app/login-form/login-form.component.spec.ts
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/login-form/login-form.component.spec.ts
@@ -21,7 +21,7 @@ import {FormsModule} from '@angular/forms';
 import {HttpModule, Http} from '@angular/http';
 import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
 import {TranslateHttpLoader} from '@ngx-translate/http-loader';
-import {HttpClientService} from '../http-client.service';
+import {HttpClientService} from '../services/http-client.service';
 
 import {LoginFormComponent} from './login-form.component';
 
@@ -84,8 +84,8 @@ describe('LoginFormComponent', () => {
     expect(component).toBeTruthy();
   });
 
-  describe('login()', () => {
-    let cases = [
+  describe('#login()', () => {
+    const cases = [
       {
         isError: true,
         isLoginAlertDisplayed: true,

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/login-form/login-form.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/login-form/login-form.component.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/login-form/login-form.component.ts
index 8dfa344..bffa412 100644
--- a/ambari-logsearch/ambari-logsearch-web-new/src/app/login-form/login-form.component.ts
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/login-form/login-form.component.ts
@@ -18,7 +18,7 @@
 
 import {Component, OnInit} from '@angular/core';
 import 'rxjs/add/operator/finally';
-import {HttpClientService} from '../http-client.service';
+import {HttpClientService} from '../services/http-client.service';
 
 @Component({
   selector: 'login-form',

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.html
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.html b/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.html
new file mode 100644
index 0000000..6bdbac4
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.html
@@ -0,0 +1,31 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+-->
+
+<div #dropdown [ngClass]="{'dropdown': hasSubItems, 'text-center': true}">
+  <span (mousedown)="onMouseDown()" (mouseup)="onMouseUp($event)" (click)="$event.stopPropagation()">
+    <a *ngIf="title" class="icon" [ngClass]="iconClassNames"></a>
+    <span *ngIf="!title" class="icon" [ngClass]="iconClassNames"></span>
+  </span>
+  <a #dropdownToggle [ngClass]="{'dropdown-toggle': hasSubItems, 'caret': true}" [attr.data-toggle]="hasSubItems ? 'dropdown': null" *ngIf="hasSubItems"></a>
+  <br>
+  <span class="icon-title" *ngIf="title" (mousedown)="onMouseDown()" (mouseup)="onMouseUp($event)" (click)="$event.stopPropagation()">{{title | translate}}</span>
+  <ul class="dropdown-menu" *ngIf="hasSubItems">
+    <li *ngFor="let item of subItems">
+      <a href="#">{{item.title}}</a>
+    </li>
+  </ul>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.less
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.less b/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.less
new file mode 100644
index 0000000..16b06c4
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.less
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+:host {
+  display: inline-block;
+  cursor: pointer;
+
+  a:hover, a:focus {
+    text-decoration: none;
+  }
+
+  .icon {
+    padding: 5px;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.spec.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.spec.ts
new file mode 100644
index 0000000..62afe07
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.spec.ts
@@ -0,0 +1,87 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import {Http} from '@angular/http';
+import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
+import {TranslateHttpLoader} from '@ngx-translate/http-loader';
+import {ActionsService} from '../services/actions.service';
+
+import {MenuButtonComponent} from './menu-button.component';
+
+export function HttpLoaderFactory(http: Http) {
+  return new TranslateHttpLoader(http, 'assets/i18n/', '.json');
+}
+
+describe('MenuButtonComponent', () => {
+  let component: MenuButtonComponent;
+  let fixture: ComponentFixture<MenuButtonComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [MenuButtonComponent],
+      imports: [
+        TranslateModule.forRoot({
+        provide: TranslateLoader,
+        useFactory: HttpLoaderFactory,
+        deps: [Http]
+      })],
+      providers: [ActionsService]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MenuButtonComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create component', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('#hasSubItems', () => {
+
+    const cases = [
+      {
+        subItems: null,
+        hasSubItems: false,
+        title: 'no sub-items'
+      },
+      {
+        subItems: [],
+        hasSubItems: false,
+        title: 'empty sub-items array'
+      },
+      {
+        subItems: [{}],
+        hasSubItems: true,
+        title: 'sub-items present'
+      }
+    ];
+
+    cases.forEach((test) => {
+      it(test.title, () => {
+        component.subItems = test.subItems;
+        expect(component.hasSubItems).toEqual(test.hasSubItems);
+      });
+    });
+
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.ts
new file mode 100644
index 0000000..7a967ad
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/menu-button/menu-button.component.ts
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 {Component, AfterViewInit, Input, ViewChild, ElementRef} from '@angular/core';
+import {ActionsService} from '../services/actions.service';
+
+@Component({
+  selector: 'menu-button',
+  templateUrl: './menu-button.component.html',
+  styleUrls: ['./menu-button.component.less']
+})
+export class MenuButtonComponent implements AfterViewInit {
+
+  constructor(private actions: ActionsService) {
+  }
+
+  ngAfterViewInit() {
+  }
+
+  @ViewChild('dropdown')
+  dropdown: ElementRef;
+
+  @Input()
+  title?: string;
+
+  @Input()
+  action: string;
+
+  @Input()
+  iconClassNames: string[];
+
+  @Input()
+  subItems?: any[];
+
+  @Input()
+  get hasSubItems(): boolean {
+    return Boolean(this.subItems && this.subItems.length);
+  }
+
+  private clickStartTime: number;
+
+  private readonly longClickInterval = 1000;
+
+  onMouseDown() {
+    this.clickStartTime = (new Date()).getTime();
+  }
+
+  onMouseUp(event: Event) {
+    const clickEndTime = (new Date()).getTime();
+    if (this.hasSubItems && clickEndTime - this.clickStartTime >= this.longClickInterval) {
+      this.dropdown.nativeElement.classList.add('open');
+    } else {
+      this.actions[this.action]();
+    }
+    event.stopPropagation();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/mock-api-data.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/mock-api-data.service.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/mock-api-data.service.ts
deleted file mode 100644
index da32c7e..0000000
--- a/ambari-logsearch/ambari-logsearch-web-new/src/app/mock-api-data.service.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 {InMemoryDbService} from 'angular-in-memory-web-api';
-
-export class mockApiDataService implements InMemoryDbService {
-  createDb() {
-    return {};
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/services/actions.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/actions.service.spec.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/actions.service.spec.ts
new file mode 100644
index 0000000..a14e0db
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/actions.service.spec.ts
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 {TestBed, inject} from '@angular/core/testing';
+
+import {ActionsService} from './actions.service';
+
+describe('ActionsService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [ActionsService]
+    });
+  });
+
+  it('should create service', inject([ActionsService], (service: ActionsService) => {
+    expect(service).toBeTruthy();
+  }));
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/services/actions.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/actions.service.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/actions.service.ts
new file mode 100644
index 0000000..2bcd909
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/actions.service.ts
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 {Injectable} from '@angular/core';
+
+@Injectable()
+export class ActionsService {
+
+  constructor() {
+  }
+
+  //TODO implement actions
+
+  undo() {
+  }
+
+  redo() {
+  }
+
+  refresh() {
+  }
+
+  openHistory() {
+  }
+
+  openAlerts() {
+  }
+
+  openUserDetails() {
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/services/http-client.service.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/http-client.service.spec.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/http-client.service.spec.ts
new file mode 100644
index 0000000..083ea23
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/http-client.service.spec.ts
@@ -0,0 +1,57 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 {TestBed, inject} from '@angular/core/testing';
+import {HttpModule, Request} from '@angular/http';
+import {HttpClientService} from './http-client.service';
+
+describe('HttpClientService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      imports: [HttpModule],
+      providers: [HttpClientService]
+    });
+  });
+
+  it('should create service', inject([HttpClientService], (service: HttpClientService) => {
+    expect(service).toBeTruthy();
+  }));
+
+  describe('#generateUrlString()', () => {
+    it('should generate URL from presets', inject([HttpClientService], (service: HttpClientService) => {
+      expect(service.generateUrlString('status')).toEqual('api/v1/status');
+    }));
+
+    it('should return explicit URL', inject([HttpClientService], (service: HttpClientService) => {
+      expect(service.generateUrlString('login')).toEqual('login');
+    }));
+  });
+
+  describe('#generateUrl()', () => {
+    it('string parameter', inject([HttpClientService], (service: HttpClientService) => {
+      expect(service.generateUrl('status')).toEqual('api/v1/status');
+    }));
+
+    it('request object parameter', inject([HttpClientService], (service: HttpClientService) => {
+      let request = new Request({
+        url: 'status'
+      });
+      expect(service.generateUrl(request).url).toEqual('api/v1/status');
+    }));
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/services/http-client.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/http-client.service.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/http-client.service.ts
new file mode 100644
index 0000000..2aa87f9
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/http-client.service.ts
@@ -0,0 +1,99 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 {Injectable} from '@angular/core';
+import {Observable} from 'rxjs/Observable';
+import {Http, XHRBackend, Request, RequestOptions, RequestOptionsArgs, Response} from '@angular/http';
+import 'rxjs/add/operator/map';
+import 'rxjs/add/operator/catch';
+
+@Injectable()
+export class HttpClientService extends Http {
+
+  constructor(backend: XHRBackend, defaultOptions: RequestOptions) {
+    super(backend, defaultOptions);
+  }
+
+  private readonly apiPrefix = 'api/v1/';
+
+  private readonly urls = {
+    status: 'status'
+  };
+
+  private readonly unauthorizedStatuses = [401, 403, 419];
+
+  isAuthorized: boolean;
+
+  generateUrlString(url: string): string {
+    const presetUrl = this.urls[url];
+    return presetUrl ? (this.apiPrefix + this.urls[url]) : url;
+  }
+
+  generateUrl(url: string | Request): string | Request {
+    if (typeof url === 'string') {
+      return this.generateUrlString(url);
+    }
+    if (url instanceof Request) {
+      url.url = this.generateUrlString(url.url);
+      return url;
+    }
+  }
+
+  handleError(request: Observable<Response>) {
+    request.subscribe(null, (error: any) => {
+      if (this.unauthorizedStatuses.indexOf(error.status) > -1) {
+        this.isAuthorized = false;
+      }
+    });
+  }
+
+  request(url: string | Request, options?: RequestOptionsArgs):Observable<Response> {
+    let req = super.request(this.generateUrl(url), options);
+    this.handleError(req);
+    return req;
+  }
+
+  get(url: string, options?: RequestOptionsArgs):Observable<Response> {
+    return super.get(this.generateUrlString(url), options);
+  }
+
+  post(url: string, body: any, options?: RequestOptionsArgs):Observable<Response> {
+    return super.post(this.generateUrlString(url), body, options);
+  }
+
+  put(url: string, body: any, options?: RequestOptionsArgs):Observable<Response> {
+    return super.put(this.generateUrlString(url), body, options);
+  }
+
+  delete(url: string, options?: RequestOptionsArgs):Observable<Response> {
+    return super.delete(this.generateUrlString(url), options);
+  }
+
+  patch(url: string, body: any, options?: RequestOptionsArgs):Observable<Response> {
+    return super.patch(this.generateUrlString(url), body, options);
+  }
+
+  head(url: string, options?: RequestOptionsArgs):Observable<Response> {
+    return super.head(this.generateUrlString(url), options);
+  }
+
+  options(url: string, options?: RequestOptionsArgs):Observable<Response> {
+    return super.options(this.generateUrlString(url), options);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/services/mock-api-data.service.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/services/mock-api-data.service.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/mock-api-data.service.ts
new file mode 100644
index 0000000..da32c7e
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/services/mock-api-data.service.ts
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 {InMemoryDbService} from 'angular-in-memory-web-api';
+
+export class mockApiDataService implements InMemoryDbService {
+  createDb() {
+    return {};
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.html
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.html b/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.html
new file mode 100644
index 0000000..82ab60a
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.html
@@ -0,0 +1,18 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+-->
+
+<menu-button *ngFor="let item of items" [title]="item.title" [action]="item.action" [iconClassNames]="item.iconClassNames" [subItems]="item.subItems"></menu-button>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.less
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.less b/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.less
new file mode 100644
index 0000000..c992c9e
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.less
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+:host {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.spec.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.spec.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.spec.ts
new file mode 100644
index 0000000..1649a50
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.spec.ts
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {TopMenuComponent} from './top-menu.component';
+
+describe('TopMenuComponent', () => {
+  let component: TopMenuComponent;
+  let fixture: ComponentFixture<TopMenuComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [TopMenuComponent],
+      schemas: [CUSTOM_ELEMENTS_SCHEMA]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(TopMenuComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create component', () => {
+    expect(component).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.ts
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.ts b/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.ts
new file mode 100644
index 0000000..d5f05875
--- /dev/null
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/app/top-menu/top-menu.component.ts
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 {Component, OnInit} from '@angular/core';
+
+@Component({
+  selector: 'top-menu',
+  templateUrl: './top-menu.component.html',
+  styleUrls: ['./top-menu.component.less']
+})
+export class TopMenuComponent implements OnInit {
+
+  constructor() {
+  }
+
+  ngOnInit() {
+  }
+
+  //TODO implement loading of real data into subItems
+  readonly items = [
+    {
+      iconClassNames: ['fa', 'fa-arrow-left'],
+      title: 'topMenu.undo',
+      action: 'undo',
+      subItems: [
+        {
+          title: 'Item 1'
+        },
+        {
+          title: 'Item 2'
+        }
+      ]
+    },
+    {
+      iconClassNames: ['fa', 'fa-arrow-right'],
+      title: 'topMenu.redo',
+      action: 'redo',
+      subItems: [
+        {
+          title: 'Item 1'
+        },
+        {
+          title: 'Item 2'
+        }
+      ]
+    },
+    {
+      iconClassNames: ['fa', 'fa-refresh'],
+      title: 'topMenu.refresh',
+      action: 'refresh'
+    },
+    {
+      iconClassNames: ['fa', 'fa-clock-o'],
+      title: 'topMenu.history',
+      action: 'openHistory',
+      subItems: [
+        {
+          title: 'Item 1'
+        },
+        {
+          title: 'Item 2'
+        }
+      ]
+    },
+    {
+      iconClassNames: ['fa', 'fa-bell'],
+      action: 'openAlerts'
+    },
+    {
+      iconClassNames: ['fa', 'fa-user'],
+      action: 'openUserDetails'
+    }
+  ];
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/assets/.gitkeep
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/assets/.gitkeep b/ambari-logsearch/ambari-logsearch-web-new/src/assets/.gitkeep
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/ambari/blob/e71ad966/ambari-logsearch/ambari-logsearch-web-new/src/assets/i18n/en.json
----------------------------------------------------------------------
diff --git a/ambari-logsearch/ambari-logsearch-web-new/src/assets/i18n/en.json b/ambari-logsearch/ambari-logsearch-web-new/src/assets/i18n/en.json
index 13c3805..dea8120 100644
--- a/ambari-logsearch/ambari-logsearch-web-new/src/assets/i18n/en.json
+++ b/ambari-logsearch/ambari-logsearch-web-new/src/assets/i18n/en.json
@@ -1,8 +1,13 @@
 {
-  "common.title": "Ambari Log Search",
+  "common.title": "Log Search",
 
   "authorization.name": "Username",
   "authorization.password": "Password",
   "authorization.signIn": "Sign In",
-  "authorization.error": "<strong>Error!</strong> Invalid User credentials.<br>Please try again."
-}
\ No newline at end of file
+  "authorization.error": "<strong>Error!</strong> Invalid User credentials.<br>Please try again.",
+
+  "topMenu.undo": "Undo",
+  "topMenu.redo": "Redo",
+  "topMenu.refresh": "Refresh",
+  "topMenu.history": "History"
+}