KNOX-1040 - Initial changes to support simple descriptors and provider 
configurations in the Admin UI.


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

Branch: refs/heads/master
Commit: e8ba712c8b5a102c95aa2e70d27b2fe32f9d620c
Parents: 7025086
Author: Phil Zampino <[email protected]>
Authored: Fri Jan 26 22:14:50 2018 -0500
Committer: Phil Zampino <[email protected]>
Committed: Thu Feb 1 20:27:07 2018 -0500

----------------------------------------------------------------------
 gateway-admin-ui/README.md                      |   2 +-
 gateway-admin-ui/package.json                   |  20 +-
 gateway-admin-ui/src/app/app.component.ts       |  27 ++-
 gateway-admin-ui/src/app/app.module.ts          |  60 ++++--
 .../src/app/descriptor/descriptor.component.css |   0
 .../app/descriptor/descriptor.component.html    |   3 +
 .../app/descriptor/descriptor.component.spec.ts |  41 ++++
 .../src/app/descriptor/descriptor.component.ts  |  31 +++
 .../src/app/gateway-version.service.ts          |  26 +--
 .../src/app/resource-detail/descriptor.ts       |  46 ++++
 .../src/app/resource-detail/provider-config.ts  |  23 ++
 .../resource-detail.component.css               |   0
 .../resource-detail.component.html              | 151 ++++++++++++++
 .../resource-detail.component.spec.ts           |  41 ++++
 .../resource-detail.component.ts                | 209 +++++++++++++++++++
 .../src/app/resource/resource.component.css     |   0
 .../src/app/resource/resource.component.html    |  22 ++
 .../src/app/resource/resource.component.spec.ts |  41 ++++
 .../src/app/resource/resource.component.ts      |  92 ++++++++
 .../src/app/resource/resource.service.ts        | 199 ++++++++++++++++++
 gateway-admin-ui/src/app/resource/resource.ts   |  24 +++
 gateway-admin-ui/src/app/resource/service.ts    |  22 ++
 .../resourcetypes/resourcetypes.component.css   |   0
 .../resourcetypes/resourcetypes.component.html  |  14 ++
 .../resourcetypes.component.spec.ts             |  41 ++++
 .../resourcetypes/resourcetypes.component.ts    |  44 ++++
 .../app/resourcetypes/resourcetypes.service.ts  |  37 ++++
 .../src/app/topology-detail.component.ts        | 129 ++++++------
 gateway-admin-ui/src/app/topology.component.ts  |   6 +-
 gateway-admin-ui/src/app/topology.service.ts    |  60 +++---
 gateway-admin-ui/src/index.html                 |  49 ++---
 gateway-admin-ui/src/styles.css                 |   6 +
 .../applications/admin-ui/app/index.html        |  14 +-
 .../app/inline.1b8a794b441ffd968489.bundle.js   |   1 +
 .../app/inline.b47d11937c275f76ce02.bundle.js   |   1 -
 .../app/main.10e7c17d5707ac382dbb.bundle.js     |   1 +
 .../app/main.a69408978854e3a77fb2.bundle.js     |   1 -
 .../app/scripts.2c89ed78f648df44c10f.bundle.js  |  12 --
 .../app/scripts.c50bb762c438ae0f8842.bundle.js  |   1 +
 .../app/styles.2ee5b7f4cd59a6cf015e.bundle.css  |   1 +
 .../app/styles.d41d8cd98f00b204e980.bundle.css  |   0
 .../service/admin/TopologiesResource.java       |   2 +-
 .../gateway/GatewayAdminTopologyFuncTest.java   |   8 -
 43 files changed, 1292 insertions(+), 216 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/README.md
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/README.md b/gateway-admin-ui/README.md
index c5e8a4e..7cef27b 100644
--- a/gateway-admin-ui/README.md
+++ b/gateway-admin-ui/README.md
@@ -1,7 +1,7 @@
 
 # NgKnoxUi
 
-This project was generated with [Angular CLI](https://cli.angular.io/) version 
1.5.3.
+This project was generated with [Angular CLI](https://cli.angular.io/) version 
1.6.5.
 
 ## Development server
 Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app 
will automatically reload if you change any of the source files.

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/package.json
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/package.json b/gateway-admin-ui/package.json
index 4218fd5..9f6548c 100644
--- a/gateway-admin-ui/package.json
+++ b/gateway-admin-ui/package.json
@@ -12,9 +12,9 @@
   },
   "private": true,
   "dependencies": {
-    "@angular/common": "^5.0.0",
-    "@angular/compiler": "^5.0.0",
-    "@angular/core": "^5.0.0",
+    "@angular/common": "^5.2.0",
+    "@angular/compiler": "^5.2.0",
+    "@angular/core": "^5.2.0",
     "@angular/forms": "^5.0.0",
     "@angular/http": "^5.0.0",
     "@angular/platform-browser": "^5.0.0",
@@ -24,17 +24,21 @@
     "rxjs": "^5.5.2",
     "zone.js": "^0.8.14",
     "ng2-ace-editor": "0.3.3",
-    "ng2-bs3-modal": "^0.10.4",
-    "ts-helpers": "^1.1.1"
+    "ng2-bs3-modal": "^0.13.0",
+    "ts-helpers": "^1.1.1",
+    "jquery": "^1.12.4",
+    "js-yaml": "^3.10.0",
+    "popper.js": "^1.12.9"
   },
   "devDependencies": {
-    "@angular/cli": "1.5.3",
-    "@angular/compiler-cli": "^5.0.0",
+    "@angular/cli": "^1.6.5",
+    "@angular/compiler-cli": "^5.2.0",
     "@angular/language-service": "^5.0.0",
     "@types/jasmine": "~2.5.53",
     "@types/jasminewd2": "~2.0.2",
     "@types/node": "~6.0.60",
-    "codelyzer": "~3.2.0",
+    "codelyzer": "^4.1.0",
+    "bootstrap": "^3.3.7",
     "jasmine-core": "~2.6.2",
     "jasmine-spec-reporter": "~4.1.0",
     "karma": "~1.7.0",

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/app.component.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/app.component.ts 
b/gateway-admin-ui/src/app/app.component.ts
index cee1178..bff7ec8 100644
--- a/gateway-admin-ui/src/app/app.component.ts
+++ b/gateway-admin-ui/src/app/app.component.ts
@@ -15,26 +15,31 @@
  * limitations under the License.
  */
 import { Component } from '@angular/core';
-import {TopologyService} from "./topology.service";
+import { TopologyService } from './topology.service';
+import { ResourceTypesService } from './resourcetypes/resourcetypes.service'
 
 @Component({
-    selector: 'topology-management',
+    selector: 'resource-management',
     template: `
-      <div class="container">
+      <div class="container-fluid">
         <div class="row">
-          <div class="col-md-5">
-            <topology></topology>
-         </div>
-          <div class="col-md-7">
-            <topology-detail></topology-detail>
+          <div class="col-md-2 col-lg-2">
+            <app-resourcetypes></app-resourcetypes>
+          </div>
+          <div class="col-md-3 col-lg-3">
+            <app-resource></app-resource>
+          </div>
+          <div class="col-md-7 col-lg-7">
+            <app-resource-detail></app-resource-detail>
           </div>
         </div>
       </div>
-  `,
-    providers: [TopologyService]
+     `,
+    providers: [TopologyService, ResourceTypesService]
 })
 
 export class AppComponent {
-    constructor(private topologyService : TopologyService) {
+    constructor(private topologyService : TopologyService,
+                private resourcetypesService: ResourceTypesService) {
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/app.module.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/app.module.ts 
b/gateway-admin-ui/src/app/app.module.ts
index a081ead..173a638 100644
--- a/gateway-admin-ui/src/app/app.module.ts
+++ b/gateway-admin-ui/src/app/app.module.ts
@@ -16,41 +16,57 @@
  */
 import { NgModule }      from '@angular/core';
 import { BrowserModule } from '@angular/platform-browser';
-import { HttpModule }    from '@angular/http';
+import { HttpClientModule } from "@angular/common/http";
 import { FormsModule } from '@angular/forms';
 
 import { AppComponent }  from './app.component';
-import {TopologyService} from "./topology.service";
-import {GatewayVersionService} from "./gateway-version.service";
-import {GatewayVersionComponent} from "./gateway-version.component";
-import {TopologyComponent} from "./topology.component";
-import {TopologyDetailComponent} from "./topology-detail.component";
-import {XmlPipe} from "./utils/xml.pipe";
-import {JsonPrettyPipe} from "./utils/json-pretty.pipe";
+import { TopologyService } from './topology.service';
+import { GatewayVersionService } from "./gateway-version.service";
+import { GatewayVersionComponent } from "./gateway-version.component";
+import { TopologyComponent } from "./topology.component";
+import { TopologyDetailComponent } from "./topology-detail.component";
+import { XmlPipe } from './utils/xml.pipe';
+import { JsonPrettyPipe } from './utils/json-pretty.pipe';
 import { TabComponent } from './utils/tab.component';
 import { TabsComponent } from './utils/tabs.component';
 
 import { AceEditorModule } from 'ng2-ace-editor';
-import { Ng2Bs3ModalModule } from 'ng2-bs3-modal/ng2-bs3-modal'
+import { BsModalModule } from 'ng2-bs3-modal/ng2-bs3-modal';
+import { ResourcetypesComponent } from 
'./resourcetypes/resourcetypes.component';
+import { ResourceTypesService } from './resourcetypes/resourcetypes.service';
+import { ResourceComponent } from './resource/resource.component';
+import { ResourceService } from './resource/resource.service';
+import { DescriptorComponent } from './descriptor/descriptor.component';
+import { ResourceDetailComponent } from 
'./resource-detail/resource-detail.component'
 
 @NgModule({
   imports: [ BrowserModule,
-    HttpModule,
-    FormsModule,
-    Ng2Bs3ModalModule,
-    AceEditorModule
+             HttpClientModule,
+             FormsModule,
+             BsModalModule,
+             AceEditorModule
     ],
   declarations: [ AppComponent,
-    TopologyComponent,
-      TopologyDetailComponent,
-    GatewayVersionComponent,
-    XmlPipe,
-    JsonPrettyPipe,
-    TabsComponent,
-    TabComponent ],
+                  TopologyComponent,
+                  TopologyDetailComponent,
+                  GatewayVersionComponent,
+                  XmlPipe,
+                  JsonPrettyPipe,
+                  TabsComponent,
+                  TabComponent,
+                  ResourcetypesComponent,
+                  ResourceComponent,
+                  DescriptorComponent,
+                  ResourceDetailComponent
+    ],
   providers: [ TopologyService,
-    GatewayVersionService ],
+               GatewayVersionService,
+               ResourceComponent,
+               ResourceTypesService,
+               ResourceService
+    ],
   bootstrap: [ AppComponent,
-    GatewayVersionComponent]
+               GatewayVersionComponent
+    ]
 })
 export class AppModule { }

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/descriptor/descriptor.component.css
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/descriptor/descriptor.component.css 
b/gateway-admin-ui/src/app/descriptor/descriptor.component.css
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/descriptor/descriptor.component.html
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/descriptor/descriptor.component.html 
b/gateway-admin-ui/src/app/descriptor/descriptor.component.html
new file mode 100644
index 0000000..938689f
--- /dev/null
+++ b/gateway-admin-ui/src/app/descriptor/descriptor.component.html
@@ -0,0 +1,3 @@
+<p>
+  descriptor works!
+</p>

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/descriptor/descriptor.component.spec.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/descriptor/descriptor.component.spec.ts 
b/gateway-admin-ui/src/app/descriptor/descriptor.component.spec.ts
new file mode 100644
index 0000000..8ecf460
--- /dev/null
+++ b/gateway-admin-ui/src/app/descriptor/descriptor.component.spec.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 { DescriptorComponent } from './descriptor.component';
+
+describe('DescriptorComponent', () => {
+  let component: DescriptorComponent;
+  let fixture: ComponentFixture<DescriptorComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ DescriptorComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(DescriptorComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/descriptor/descriptor.component.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/descriptor/descriptor.component.ts 
b/gateway-admin-ui/src/app/descriptor/descriptor.component.ts
new file mode 100644
index 0000000..211d7bd
--- /dev/null
+++ b/gateway-admin-ui/src/app/descriptor/descriptor.component.ts
@@ -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.
+ */
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-descriptor',
+  templateUrl: './descriptor.component.html',
+  styleUrls: ['./descriptor.component.css']
+})
+export class DescriptorComponent implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/gateway-version.service.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/gateway-version.service.ts 
b/gateway-admin-ui/src/app/gateway-version.service.ts
index cdd7679..38b247c 100644
--- a/gateway-admin-ui/src/app/gateway-version.service.ts
+++ b/gateway-admin-ui/src/app/gateway-version.service.ts
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 import { Injectable }    from '@angular/core';
-import { Headers, Http } from '@angular/http';
+import { HttpHeaders, HttpClient } from '@angular/common/http';
 
 import 'rxjs/add/operator/toPromise';
 
@@ -26,22 +26,22 @@ export class GatewayVersionService {
 
     private apiUrl = '/gateway/manager/api/v1/version';
 
-    constructor(private http: Http) { }
+    constructor(private http: HttpClient) { }
 
     getVersion(): Promise<GatewayVersion> {
-        let headers = new Headers();
-        this.addHeaders(headers);
-        return this.http.get(this.apiUrl, {
-            headers: headers
-        } )
-            .toPromise()
-            .then(response => response.json().ServerVersion as GatewayVersion)
-            .catch(this.handleError);
+        let headers = new HttpHeaders();
+        headers = this.addHeaders(headers);
+        return this.http.get(this.apiUrl, { headers: headers } )
+                        .toPromise()
+                        .then(response => {
+                            return response['ServerVersion'] as GatewayVersion;
+                        })
+                        .catch(this.handleError);
     }
 
-    addHeaders(headers: Headers) {
-        headers.append('Accept', 'application/json');
-        headers.append('Content-Type', 'application/json');
+    addHeaders(headers: HttpHeaders) {
+        return headers.append('Accept', 'application/json')
+                      .append('Content-Type', 'application/json');
     }
 
     private handleError(error: any): Promise<any> {

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource-detail/descriptor.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resource-detail/descriptor.ts 
b/gateway-admin-ui/src/app/resource-detail/descriptor.ts
new file mode 100644
index 0000000..c407f96
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource-detail/descriptor.ts
@@ -0,0 +1,46 @@
+/*
+ * 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 {Service} from "../resource/service";
+
+
+export class Descriptor {
+    discoveryAddress: string;
+    discoveryUser: string;
+    discoveryPassAlias: string;
+    discoveryCluster: string;
+    providerConfig: string;
+    services: Service[];
+
+    getServiceParamKeys(service: Service): string[] {
+        let result = [];
+        for(let key in service.params){
+            if (service.params.hasOwnProperty(key)){
+                result.push(key);
+            }
+        }
+        return result;
+    }
+
+    getServiceParamValue(service: Service, name: string): string {
+       return  service.params[name];
+    }
+
+    setProviderConfig(providerConfigRef: string) {
+        this.providerConfig = providerConfigRef;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource-detail/provider-config.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resource-detail/provider-config.ts 
b/gateway-admin-ui/src/app/resource-detail/provider-config.ts
new file mode 100644
index 0000000..0811b9a
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource-detail/provider-config.ts
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+export class ProviderConfig {
+    name: string;
+    role: string;
+    enabled: string;
+    params: Object;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource-detail/resource-detail.component.css
----------------------------------------------------------------------
diff --git 
a/gateway-admin-ui/src/app/resource-detail/resource-detail.component.css 
b/gateway-admin-ui/src/app/resource-detail/resource-detail.component.css
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource-detail/resource-detail.component.html
----------------------------------------------------------------------
diff --git 
a/gateway-admin-ui/src/app/resource-detail/resource-detail.component.html 
b/gateway-admin-ui/src/app/resource-detail/resource-detail.component.html
new file mode 100644
index 0000000..79d3ba8
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource-detail/resource-detail.component.html
@@ -0,0 +1,151 @@
+<div *ngIf="resourceType && resourceType !== 'Topologies'" class="panel 
panel-default">
+  <div class="panel-heading">
+    <h4 class="panel-title">
+      {{ getTitleSubject() }} Detail <span *ngIf="hasSelectedResource()" 
class="pull-right">{{resourceService.getResourceDisplayName(resource)}}</span>
+    </h4>
+  </div>
+
+  <!-- Provider Configuration Details -->
+  <div class="panel-body" *ngIf="hasSelectedResource() && resourceType === 
'Provider Configurations'">
+    <div *ngIf="hasSelectedResource()">
+      <div class="panel panel-default" *ngFor="let provider of providers">
+        <span [class]="'clickable glyhpicon glyphicon-' + (provider.show ? 
'minus' : 'plus')"
+                 (click)="provider.show = !provider.show"></span>
+        <span><b>{{ provider.name }}</b></span>
+        <span class="glyphicon glyphicon-remove-sign pull-right" 
data-toggle="tooltip" [title]="'Remove ' + provider.name"></span>
+        <div *ngIf="provider.show">
+          &nbsp;&nbsp;&nbsp;<b>Role</b> {{ provider.role }}<br>
+          &nbsp;&nbsp;&nbsp;<b>Enabled</b> {{ provider.enabled }}<br>
+          <div>
+            <span>&nbsp;&nbsp;&nbsp;</span>
+            <span [class]="'clickable glyhpicon glyphicon-' + 
(provider.paramDetails ? 'minus' : 'plus')"
+                  (click)="provider.paramDetails = 
!provider.paramDetails"></span>
+            <span><b>Params</b></span>
+            <span class="glyphicon glyphicon-plus-sign pull-right" 
data-toggle="tooltip" title="Add Param"></span>
+
+            <div class="panel panel-default table-responsive" 
*ngIf="provider.paramDetails">
+              <table class="table table-sm">
+                <tr *ngFor="let key of getParamKeys(provider)">
+                  <td>
+                    <span class="glyphicon glyphicon-remove-sign"></span>
+                  </td>
+                  <td><b>{{ key }}</b></td>
+                  <td>{{ provider.params[key] }}</td>
+                </tr>
+              </table>
+            </div>
+          </div>
+        </div>
+        <br><br>
+      </div>
+    </div>
+  </div>
+
+  <!-- Descriptor Details -->
+  <div class="panel-body" *ngIf="hasSelectedResource() && resourceType === 
'Descriptors'">
+    <!-- The resource name is undefined if it's the empty descriptor because 
none has been selected yet. -->
+    <div *ngIf="hasSelectedResource()">
+      <div>
+        <div class="panel panel-default col-md-12">
+          <span class="col-md-4"><b>Provider Configuration</b></span>
+          <span class="col-md-7">
+            <input type="text" class="col-md-sm form-control input-sm" 
[(ngModel)]="descriptor.providerConfig" id="textbox"/>
+          </span>
+          <span class="col-md-1 pull-left">
+            <button id="chooseProviderConfig" 
(click)="chooseProviderConfigModal.open('sm')" class="btn btn-default btn-xs 
glyphicon glyphicon-edit" type="submit">
+              <!--            <span class="glyphicon glyphicon-edit"></span>-->
+            </button>
+          </span>
+        </div>
+        <bs-modal 
(onClose)="descriptor.setProviderConfig(newProviderConfigRef)" 
#chooseProviderConfigModal>
+          <!--<bs-modal-header [show-close]="true">-->
+          <bs-modal-header>
+            <label class="modal-title">Choose a Provider Configuration</label>
+          </bs-modal-header>
+          <bs-modal-body>
+            <div class="form-group">
+              <select autofocus required class="md-select form-control" 
required [(ngModel)]="newProviderConfigRef" id="select" >
+                <option *ngFor="let pc of availableProviderConfigs"
+                        class="md-option"
+                        [value]="pc.name"
+                        [selected]="pc.name === 
descriptor.providerConfig">{{pc.name}}</option>
+              </select>
+            </div>
+          </bs-modal-body>
+          <bs-modal-footer>
+            <button type="button" class="btn btn-default btn-sm" 
data-dismiss="chooseProviderConfigModal" 
(click)="chooseProviderConfigModal.dismiss()">Cancel</button>
+            <button type="button" class="btn btn-primary btn-sm" 
[disabled]="!newProviderConfigRef" 
(click)="chooseProviderConfigModal.close()">Ok</button>
+          </bs-modal-footer>
+        </bs-modal>
+      </div>
+
+      <br><br>
+
+      <div class="panel panel-default col-md-12">
+        <span [class]="'clickable glyhpicon glyphicon-' + (showServiceDetails 
? 'minus' : 'plus')"
+              (click)="showServiceDetails = !showServiceDetails"></span>
+        <span><b>Services</b></span>
+        <span class="glyphicon glyphicon-plus-sign pull-right" 
data-toggle="tooltip" title="Add Service"></span>
+      <div class="col-md-12 table-responsive" *ngIf="showServiceDetails">
+        <table class="table table-striped table-sm">
+          <tr *ngFor="let service of descriptor.services">
+            <td>
+              <div>
+                <span><b>{{ service.name }}</b></span>
+                <span class="glyphicon glyphicon-remove-sign pull-right"  
data-toggle="tooltip" [title]="'Remove ' + service.name"></span>
+              </div>
+              <div>
+                <span [class]="'clickable glyhpicon glyphicon-' + 
(service.showParams ? 'minus' : 'plus')"
+                      (click)="service.showParams = 
!service.showParams"></span>
+                <span>Params</span><span>&nbsp;</span><span class="glyphicon 
glyphicon-plus-sign" data-toggle="tooltip" title="Add param"></span>
+                <!--<span class="btn btn-default btn-xs" data-toggle="tooltip" 
title="Add param">add</span>-->
+              </div>
+              <div class="table-responsive" *ngIf="service.showParams">
+                <table class="table table-sm" 
*ngIf="descriptor.getServiceParamKeys(service).length > 0">
+                  <tr *ngFor="let paramKey of 
descriptor.getServiceParamKeys(service)">
+                    <td width="5%"><span class="glyphicon 
glyphicon-remove-sign"></span></td>
+                    <td width="30%"><b>{{ paramKey }}</b></td>
+                    <td width="65%" align="left">{{ 
descriptor.getServiceParamValue(service, paramKey) }}</td>
+                  </tr>
+                </table>
+              </div>
+              <div>
+                <span [class]="'clickable glyhpicon glyphicon-' + 
(service.showUrls ? 'minus' : 'plus')"
+                      (click)="service.showUrls = !service.showUrls"></span>
+                <span>URLs</span><span>&nbsp;</span><span class="glyphicon 
glyphicon-plus-sign" data-toggle="tooltip" title="Add URL"></span>
+              </div>
+              <div class="table-responsive" *ngIf="service.showUrls">
+                <table class="table table-sm" *ngIf="service.urls && 
service.urls.length > 0">
+                  <tr *ngFor="let url of service.urls">
+                    <td width="5%"><span class="glyphicon 
glyphicon-remove-sign"></span></td>
+                    <td width="95%">{{ url }}</td>
+                  </tr>
+                </table>
+              </div>
+            </td>
+          </tr>
+        </table>
+      </div>
+    </div>
+      <br><br>
+      <div class="panel panel-default col-md-12">
+        <span [class]="'clickable glyhpicon glyphicon-' + (showDiscDetails ? 
'minus' : 'plus')"
+              (click)="showDiscDetails = !showDiscDetails"></span>
+        <span><b>Discovery Details</b></span>
+        <div class="col-md-12" *ngIf="showDiscDetails">
+          <table class="table table-sm">
+            <tr><td>Discovery Address</td><td>{{ descriptor.discoveryAddress 
}}</td></tr>
+            <tr><td>Discovery User</td><td>{{ descriptor.discoveryUser 
}}</td></tr>
+            <tr><td>Discovery Password Alias</td><td>{{ 
descriptor.discoveryPassAlias }}</td></tr>
+            <tr><td>Discovery Cluster</td><td>{{ descriptor.discoveryCluster 
}}</td></tr>
+          </table>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<!-- Topology Details -->
+<div *ngIf="resourceType === 'Topologies'">
+  <topology-detail></topology-detail>
+</div>

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource-detail/resource-detail.component.spec.ts
----------------------------------------------------------------------
diff --git 
a/gateway-admin-ui/src/app/resource-detail/resource-detail.component.spec.ts 
b/gateway-admin-ui/src/app/resource-detail/resource-detail.component.spec.ts
new file mode 100644
index 0000000..9503223
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource-detail/resource-detail.component.spec.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 { ResourceDetailComponent } from './resource-detail.component';
+
+describe('ResourceDetailComponent', () => {
+  let component: ResourceDetailComponent;
+  let fixture: ComponentFixture<ResourceDetailComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ResourceDetailComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ResourceDetailComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource-detail/resource-detail.component.ts
----------------------------------------------------------------------
diff --git 
a/gateway-admin-ui/src/app/resource-detail/resource-detail.component.ts 
b/gateway-admin-ui/src/app/resource-detail/resource-detail.component.ts
new file mode 100644
index 0000000..acbe71b
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource-detail/resource-detail.component.ts
@@ -0,0 +1,209 @@
+/*
+ * 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';
+import { ResourceService } from '../resource/resource.service';
+import { Resource } from '../resource/resource';
+import { ProviderConfig } from './provider-config';
+import { Descriptor } from "./descriptor";
+import { Service } from "../resource/service";
+import { parseString } from 'xml2js';
+
+import 'brace/theme/monokai';
+import 'brace/mode/xml';
+
+@Component({
+  selector: 'app-resource-detail',
+  templateUrl: './resource-detail.component.html',
+  styleUrls: ['./resource-detail.component.css']
+})
+export class ResourceDetailComponent implements OnInit {
+
+  // Static "empty" Resource used for clearing the display between resource 
selections
+  private static emptyResource: Resource = new Resource();
+
+  private static emptyDescriptor: Descriptor = new Descriptor();
+
+  title: string;
+
+  resourceType: string;
+  resource: Resource;
+  resourceContent: string;
+
+  providers: Array<ProviderConfig>;
+
+  descriptor: Descriptor;
+
+  availableProviderConfigs: Resource[];
+
+  constructor(private resourceService: ResourceService) {
+  }
+
+  ngOnInit() {
+      this.resourceService.getResources('Provider Configurations').then(pcs => 
{
+          this.availableProviderConfigs = pcs;
+      });
+
+      this.resourceService.selectedResourceType$.subscribe(type => 
this.setResourceType(type));
+      this.resourceService.selectedResource$.subscribe(value => 
this.setResource(value));
+  }
+
+  get self() {
+      return this;
+  }
+
+  setResourceType(resType: string) {
+      if (resType !== this.resourceType) {
+
+        if (resType === 'Descriptors') {
+          // Update the available provider configurations if we're dealing 
with descriptors
+          this.resourceService.getResources("Provider 
Configurations").then(result => this.availableProviderConfigs = result);
+        }
+
+        // Clear the current resource details
+        if (this.resource) {this.resource.name = '';} // This clears the 
details title when the type context changes
+        this.resource = ResourceDetailComponent.emptyResource;
+        this.providers = null;
+        this.descriptor = ResourceDetailComponent.emptyDescriptor;
+        this.resourceContent = ''; // Clear the content area
+        this.resourceType = resType;
+      }
+  }
+
+  setResource(res: Resource) {
+      this.resource = res;
+      this.providers = [];
+      this.resourceService.getResource(this.resourceType, res).then(content => 
this.setResourceContent(res, content));
+  }
+
+  setResourceContent(res: Resource, content: string) {
+      switch(this.resourceType) {
+          case 'Provider Configurations': {
+              this.setProviderConfigContent(res, content);
+              break;
+          }
+          case 'Descriptors': {
+              this.setDescriptorContent(res, content);
+              break;
+          }
+      }
+  }
+
+  setProviderConfigContent(res: Resource, content: string) {
+      this.resourceContent = content;
+      if (this.resourceContent) {
+          try {
+            let contentObj;
+            if (res.name.endsWith('json')) {
+                // Parse the JSON representation
+                contentObj = JSON.parse(this.resourceContent);
+                this.providers = contentObj['providers'];
+            } else if (res.name.endsWith('yaml') || res.name.endsWith('yml')) {
+                // Parse the YAML representation
+                let yaml = require('js-yaml');
+                contentObj = yaml.load(this.resourceContent);
+                this.providers = contentObj['providers'];
+            } else if (res.name.endsWith('xml')) {
+                // Parse the XML representation
+                parseString(this.resourceContent, (err, result) => {
+                    let tempProviders = new Array<ProviderConfig>();
+                    result['gateway'].provider.forEach(entry => {
+                       let providerConfig: ProviderConfig = entry;
+                       let params = {};
+                       entry.param.forEach(param => {
+                           params[param.name] = param.value;
+                       });
+                       providerConfig.params = params;
+                       tempProviders.push(providerConfig);
+                    });
+                    this.providers = tempProviders;
+                });
+            }
+          } catch (e) {
+            console.log('Error parsing resource content: ' + e);
+          }
+      }
+  }
+
+  setDescriptorContent(res: Resource, content: string) {
+    this.resourceContent = content;
+    if (this.resourceContent) {
+      try {
+        console.log('Parsing descriptor ' + res.name);
+        let contentObj;
+        if (res.name.endsWith('json')) {
+          contentObj = JSON.parse(this.resourceContent);
+        } else if (res.name.endsWith('yaml') || res.name.endsWith('yml')) {
+          let yaml = require('js-yaml');
+          contentObj = yaml.load(this.resourceContent);
+        }
+        let tempDesc = new Descriptor();
+        if (contentObj) {
+          tempDesc.discoveryAddress = contentObj['discovery-address'];
+          tempDesc.discoveryUser = contentObj['discovery-user'];
+          tempDesc.discoveryPassAlias = contentObj['discovery-pwd-alias'];
+          tempDesc.discoveryCluster = contentObj['cluster'];
+          tempDesc.providerConfig = contentObj['provider-config-ref'];
+          tempDesc.services = contentObj['services'];
+        }
+        this.descriptor = tempDesc;
+      } catch (e) {
+        console.log('Error parsing resource content: ' + e);
+      }
+    }
+  }
+
+  getParamKeys(provider: ProviderConfig): string[] {
+    let result = [];
+    for(let key in provider.params){
+      if (provider.params.hasOwnProperty(key)){
+          result.push(key);
+      }
+    }
+    return result;
+  }
+
+
+  getServiceParamKeys(service: Service): string[] {
+    let result = [];
+    for(let key in service.params){
+      if (service.params.hasOwnProperty(key)){
+        result.push(key);
+      }
+    }
+    return result;
+  }
+
+  hasSelectedResource(): boolean {
+    return Boolean(this.resource) && Boolean(this.resource.name);
+  }
+
+  getTitleSubject(): string {
+      switch(this.resourceType) {
+          case 'Topologies': {
+              return 'Topology';
+          }
+          case 'Provider Configurations':
+          case 'Descriptors': {
+              return this.resourceType.substring(0, this.resourceType.length - 
1);
+          }
+          default: {
+              return 'Resource';
+          }
+      }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource/resource.component.css
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resource/resource.component.css 
b/gateway-admin-ui/src/app/resource/resource.component.css
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource/resource.component.html
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resource/resource.component.html 
b/gateway-admin-ui/src/app/resource/resource.component.html
new file mode 100644
index 0000000..f0bdeb2
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource/resource.component.html
@@ -0,0 +1,22 @@
+<div>
+  <div class="table-responsive" style="max-height: 400px; width:100%; 
overflow: auto;">
+    <table class="table table-hover">
+      <thead>
+      <tr>
+        <th>{{ getResourceTypeSingularDisplayName(resourceType) }}</th>
+        <th *ngIf="resourceType === 'Topologies'">Timestamp</th>
+      </tr>
+      </thead>
+      <tbody>
+      <tr *ngFor="let resource of resources"
+          [class.selected]="resource === selectedResource"
+          [class.active]="resource === selectedResource"
+          (click)="onSelect(resource)"
+          class="clickable">
+        <td>{{resourceService.getResourceDisplayName(resource)}}</td>
+        <td *ngIf="resourceType === 'Topologies'">{{resource.timestamp | 
date:'medium'}}</td>
+      </tr>
+      </tbody>
+    </table>
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource/resource.component.spec.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resource/resource.component.spec.ts 
b/gateway-admin-ui/src/app/resource/resource.component.spec.ts
new file mode 100644
index 0000000..fa69cd0
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource/resource.component.spec.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 { ResourceComponent } from './resource.component';
+
+describe('ResourceComponent', () => {
+  let component: ResourceComponent;
+  let fixture: ComponentFixture<ResourceComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ResourceComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ResourceComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource/resource.component.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resource/resource.component.ts 
b/gateway-admin-ui/src/app/resource/resource.component.ts
new file mode 100644
index 0000000..c46b732
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource/resource.component.ts
@@ -0,0 +1,92 @@
+/*
+ * 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';
+import { ResourceTypesService } from '../resourcetypes/resourcetypes.service';
+import { ResourceService } from './resource.service';
+import { Resource } from './resource';
+import {TopologyService} from "../topology.service";
+import {Topology} from "../topology";
+
+
+@Component({
+  selector: 'app-resource',
+  templateUrl: './resource.component.html',
+  styleUrls: ['./resource.component.css']
+})
+export class ResourceComponent implements OnInit {
+
+  resourceType: string;
+
+  value: any;
+  resources: Resource[];
+  selectedResource: Resource;
+
+  constructor(private resourceTypesService: ResourceTypesService,
+              private resourceService: ResourceService,
+              private topologyService: TopologyService) { }
+
+
+  ngOnInit() {
+    this.resourceTypesService.selectedResourceType$.subscribe(value => 
this.setResourceType(value));
+  }
+
+
+  setResourceType(resType: string) {
+    this.resourceType = resType;
+    this.resourceService.selectedResourceType(this.resourceType);
+    this.resources = []; // Clear the table before loading the new resources
+    this.resourceService.getResources(resType).then(resources => {
+        this.resources = resources;
+        console.log('Found ' + resources.length + ' ' + this.resourceType + ' 
resources');
+        for (let resource of resources) {
+            console.log('Resource: ' + resource.name);
+        }
+    });
+  }
+
+  onSelect(resource: Resource) {
+    this.selectedResource = resource;
+
+    // If it's a topology resource, notify the topology service
+    if (this.resourceType === 'Topologies') {
+        let topology = new Topology();
+        topology.name = resource.name;
+        topology.href = resource.href;
+        this.topologyService.selectedTopology(topology);
+    } else {
+        // Otherwise, notify the resource service
+        this.resourceService.selectedResource(resource);
+    }
+  }
+
+
+  getResourceTypeSingularDisplayName(resType: string): string {
+      switch(resType) {
+          case 'Topologies': {
+              return 'Topology';
+          }
+          case 'Provider Configurations':
+          case 'Descriptors': {
+              return resType.substring(0, resType.length - 1);
+          }
+          default: {
+              return 'Resource';
+          }
+      }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource/resource.service.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resource/resource.service.ts 
b/gateway-admin-ui/src/app/resource/resource.service.ts
new file mode 100644
index 0000000..009ca2a
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource/resource.service.ts
@@ -0,0 +1,199 @@
+/*
+ * 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 { HttpHeaders, HttpClient} from '@angular/common/http';
+import 'rxjs/add/operator/toPromise';
+import { Subject } from 'rxjs/Subject';
+import { Resource } from './resource';
+
+
+@Injectable()
+export class ResourceService {
+
+    apiUrl = '/gateway/manager/api/v1/';
+    providersUrl = this.apiUrl + 'providerconfig';
+    descriptorsUrl = this.apiUrl + 'descriptors';
+    topologiesUrl = this.apiUrl + 'topologies';
+
+    selectedResourceTypeSource = new Subject<string>();
+    selectedResourceType$ = this.selectedResourceTypeSource.asObservable();
+
+    selectedResourceSource = new Subject<Resource>();
+    selectedResource$ = this.selectedResourceSource.asObservable();
+
+    changedResourceSource = new Subject<string>();
+    changedResource$ = this.changedResourceSource.asObservable();
+
+    constructor(private http: HttpClient) { }
+
+    getResources(resType: string): Promise<Resource[]> {
+        switch(resType) {
+          case 'Provider Configurations': {
+            return this.getProviderConfigResources();
+          }
+          case 'Descriptors': {
+            return this.getDescriptorResources();
+          }
+          case 'Topologies': {
+            return this.getTopologyResources();
+          }
+        }
+    }
+
+    getProviderConfigResources(): Promise<Resource[]> {
+        let headers = new HttpHeaders();
+        headers = this.addJsonHeaders(headers);
+        return this.http.get(this.providersUrl, { headers: headers })
+                        .toPromise()
+                        .then(response => response['items'] as Resource[])
+                        .catch(this.handleError);
+    }
+
+    getDescriptorResources(): Promise<Resource[]> {
+        let headers = new HttpHeaders();
+        headers = this.addJsonHeaders(headers);
+        return this.http.get(this.descriptorsUrl, { headers: headers })
+                        .toPromise()
+                        .then(response => response['items'] as Resource[])
+                        .catch(this.handleError);
+    }
+
+    getTopologyResources(): Promise<Resource[]> {
+        let headers = new HttpHeaders();
+        headers = this.addJsonHeaders(headers);
+        return this.http.get(this.topologiesUrl, { headers: headers })
+                        .toPromise()
+                        .then(response => response['topologies'].topology as 
Resource[])
+                        .catch(this.handleError);
+    }
+
+    getResource(resType: string, res : Resource): Promise<string> {
+        let headers = new HttpHeaders();
+        headers = (resType === 'Topologies') ? this.addXmlHeaders(headers) : 
this.addHeaders(headers, res.name);
+
+        return this.http.get(res.href, { headers: headers, responseType: 
'text' })
+                        .toPromise()
+                        .then(response => { return response; })
+                        .catch(this.handleError);
+    }
+
+    saveResource(url: string, xml : string): Promise<string> {
+        let xheaders = new HttpHeaders();
+        this.addXmlHeaders(xheaders);
+        this.addCsrfHeaders(xheaders);
+        return this.http.put(url, xml, {headers: xheaders})
+                        .toPromise()
+                        .then(() => xml)
+                        .catch(this.handleError);
+    }
+
+    createResource(name: string, xml : string): Promise<string> {
+        let xheaders = new HttpHeaders();
+        this.addXmlHeaders(xheaders);
+        this.addCsrfHeaders(xheaders);
+        let url = this.topologiesUrl + "/" + name;
+        return this.http.put(url, xml, {headers: xheaders})
+                        .toPromise()
+                        .then(() => xml)
+                        .catch(this.handleError);
+    }
+
+    deleteResource(href: string): Promise<string> {
+        let headers = new HttpHeaders();
+        this.addJsonHeaders(headers);
+        this.addCsrfHeaders(headers);
+        return this.http.delete(href, { headers: headers } )
+                        .toPromise()
+                        .then(response => response)
+                        .catch(this.handleError);
+    }
+
+    addHeaders(headers: HttpHeaders, resName: string): HttpHeaders {
+        let ext = resName.split('.').pop();
+        switch(ext) {
+          case 'xml': {
+              headers = this.addXmlHeaders(headers);
+              break;
+          }
+          case 'json': {
+              headers = this.addJsonHeaders(headers);
+              break;
+          }
+          case 'yaml':
+          case 'yml': {
+              headers = this.addTextPlainHeaders(headers);
+              break;
+          }
+        }
+        return headers;
+    }
+
+    addTextPlainHeaders(headers: HttpHeaders) {
+        return headers.append('Accept', 'text/plain')
+                      .append('Content-Type', 'text/plain');
+    }
+
+    addJsonHeaders(headers: HttpHeaders): HttpHeaders {
+        return headers.append('Accept', 'application/json')
+                      .append('Content-Type', 'application/json');
+    }
+
+    addXmlHeaders(headers: HttpHeaders): HttpHeaders {
+        return headers.append('Accept', 'application/xml')
+                      .append('Content-Type', 'application/xml');
+    }
+
+    addCsrfHeaders(headers: HttpHeaders): HttpHeaders {
+        return headers.append('X-XSRF-Header', 'admin-ui');
+    }
+
+    selectedResourceType(value: string) {
+        this.selectedResourceTypeSource.next(value);
+    }
+
+    selectedResource(value: Resource) {
+        this.selectedResourceSource.next(value);
+    }
+
+    changedResource(value: string) {
+        this.changedResourceSource.next(value);
+    }
+
+
+    public getResourceDisplayName(res: Resource): string {
+        if (res.name) {
+            let idx = res.name.lastIndexOf('.');
+            return idx >0 ? res.name.substring(0, res.name.lastIndexOf('.')) : 
res.name;
+        } else {
+            return null;
+        }
+    }
+
+    private handleError(error: any): Promise<any> {
+        console.error('An error occurred', error); // for demo purposes only
+        return Promise.reject(error.message || error);
+    }
+
+    private logHeaders(headers: HttpHeaders) {
+        console.log('Header count: ' + headers.keys().length);
+        headers.keys().forEach(key => {
+            console.log('Header: ' + key + '=' + headers.get(key));
+        });
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource/resource.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resource/resource.ts 
b/gateway-admin-ui/src/app/resource/resource.ts
new file mode 100644
index 0000000..cb5ba6f
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource/resource.ts
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+export class Resource {
+    timestamp: number;
+    name: string;
+    uri: string;
+    href: string;
+    content: string;
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resource/service.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resource/service.ts 
b/gateway-admin-ui/src/app/resource/service.ts
new file mode 100644
index 0000000..3997290
--- /dev/null
+++ b/gateway-admin-ui/src/app/resource/service.ts
@@ -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.
+ */
+
+export class Service {
+    name: string;
+    params: Object;
+    urls: string[]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.css
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.css 
b/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.css
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.html
----------------------------------------------------------------------
diff --git 
a/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.html 
b/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.html
new file mode 100644
index 0000000..8909df3
--- /dev/null
+++ b/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.html
@@ -0,0 +1,14 @@
+<div class="table-responsive" style="max-height: 400px; width:100%; overflow: 
auto;">
+  <table class="table table-hover">
+    <thead><tr><th>Resource Types</th></tr></thead>
+    <tbody>
+    <tr *ngFor="let type of resourceTypes"
+        [class.selected]="type === selectedResourceType"
+        [class.active]="type === selectedResourceType"
+        (click)="onSelect(type)"
+        class="clickable">
+        <td>{{type}}</td>
+    </tr>
+    </tbody>
+  </table>
+</div>

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.spec.ts
----------------------------------------------------------------------
diff --git 
a/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.spec.ts 
b/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.spec.ts
new file mode 100644
index 0000000..43bdf40
--- /dev/null
+++ b/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.spec.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 { ResourcetypesComponent } from './resourcetypes.component';
+
+describe('ResourcetypesComponent', () => {
+    let component: ResourcetypesComponent;
+    let fixture: ComponentFixture<ResourcetypesComponent>;
+
+    beforeEach(async(() => {
+    TestBed.configureTestingModule({
+        declarations: [ ResourcetypesComponent ]
+    })
+    .compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(ResourcetypesComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.ts 
b/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.ts
new file mode 100644
index 0000000..ae98b5d
--- /dev/null
+++ b/gateway-admin-ui/src/app/resourcetypes/resourcetypes.component.ts
@@ -0,0 +1,44 @@
+/*
+ * 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, Injectable, OnInit } from '@angular/core';
+import { ResourceTypesService } from '../resourcetypes/resourcetypes.service';
+
+@Component({
+    selector: 'app-resourcetypes',
+    templateUrl: './resourcetypes.component.html',
+    styleUrls: ['./resourcetypes.component.css']
+})
+
+@Injectable()
+export class ResourcetypesComponent implements OnInit {
+
+    resourceTypes = [];
+    selectedResourceType;
+
+    constructor(private resourceTypeService: ResourceTypesService) {
+    }
+
+    ngOnInit() {
+        this.resourceTypes = this.resourceTypeService.getResourceTypes();
+    }
+
+    onSelect(resType: string) {
+        this.selectedResourceType = resType;
+        this.resourceTypeService.selectResourceType(resType);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/resourcetypes/resourcetypes.service.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/resourcetypes/resourcetypes.service.ts 
b/gateway-admin-ui/src/app/resourcetypes/resourcetypes.service.ts
new file mode 100644
index 0000000..456d22f
--- /dev/null
+++ b/gateway-admin-ui/src/app/resourcetypes/resourcetypes.service.ts
@@ -0,0 +1,37 @@
+/*
+ * 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, OnInit } from '@angular/core';
+import { Subject } from 'rxjs/Subject';
+
+@Injectable()
+export class ResourceTypesService {
+
+    resourceTypes = ['Provider Configurations', 'Descriptors', 'Topologies'];
+    selectedResourceTypeSource = new Subject<string>();
+    public selectedResourceType$ = 
this.selectedResourceTypeSource.asObservable();
+
+    constructor() {
+    }
+
+    getResourceTypes(): string[] {
+        return this.resourceTypes;
+    }
+
+    selectResourceType(resType: string) {
+      this.selectedResourceTypeSource.next(resType);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/topology-detail.component.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/topology-detail.component.ts 
b/gateway-admin-ui/src/app/topology-detail.component.ts
index e93aaaa..a4e4713 100644
--- a/gateway-admin-ui/src/app/topology-detail.component.ts
+++ b/gateway-admin-ui/src/app/topology-detail.component.ts
@@ -14,11 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { Component, OnInit, ViewChild, ViewEncapsulation} from '@angular/core';
+import { Component, OnInit, ViewChild } from '@angular/core';
 import { Topology } from './topology';
-import {TopologyService} from "./topology.service";
-import { ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
-import { ViewChildren } from '@angular/core/src/metadata/di';
+import { TopologyService } from "./topology.service";
+import { BsModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
+import { ResourceService } from "./resource/resource.service";
 
 import 'brace/theme/monokai';
 import 'brace/mode/xml';
@@ -27,59 +27,62 @@ import 'brace/mode/xml';
     selector: 'topology-detail',
     template: `
      <div class="panel panel-default">
-        <div class="panel-heading">
-            <h4 class="panel-title">{{title}} <span *ngIf="showEditOptions == 
false" style="padding-left: 15%;" class="text-danger text-center" > Ready Only 
(generated file) </span> <span class="label label-default 
pull-right">{{titleSuffix}}</span></h4>
-         </div>
-     <div *ngIf="topologyContent" class="panel-body">
-      <ace-editor
-        [(text)]="topologyContent" 
-        [mode]="'xml'" 
-        [options]="options" 
-        [theme]="theme"
-        style="min-height: 430px; width:100%; overflow: auto;" 
-        (textChanged)="onChange($event)">
-      </ace-editor>
-       <div *ngIf="showEditOptions" class="panel-footer">
-        <button id="duplicateTopology" (click)="duplicateModal.open('sm')" 
class="btn btn-default btn-sm" type="submit" >
-            <span class="glyphicon glyphicon-duplicate" 
aria-hidden="true"></span>
-        </button>
-        <button id="deleteTopology" (click)="deleteConfirmModal.open('sm')" 
class="btn btn-default btn-sm" type="submit" >
-            <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
-        </button>
-       <button id="saveTopology" (click)="saveTopology()" class="btn 
btn-default btn-sm pull-right" [disabled]="!changedTopology" type="submit" >
-            <span class="glyphicon glyphicon-floppy-disk" 
aria-hidden="true"></span>
-        </button>
+       <div class="panel-heading">
+         <h4 class="panel-title">{{title}} <span *ngIf="showEditOptions == 
false" style="padding-left: 15%;" class="text-danger text-center" > Ready Only 
(generated file) </span> <span class="pull-right">{{titleSuffix}}</span></h4>
        </div>
+       <div *ngIf="topologyContent" class="panel-body">
+         <ace-editor
+            [(text)]="topologyContent" 
+            [mode]="'xml'" 
+            [options]="options" 
+            [theme]="theme"
+            [readOnly]="!showEditOptions"
+            style="min-height: 430px; width:100%; overflow: auto;" 
+            (textChanged)="onChange($event)">
+         </ace-editor>
+         <div *ngIf="showEditOptions" class="panel-footer">
+           <button id="duplicateTopology" (click)="duplicateModal.open('sm')" 
class="btn btn-default btn-sm" type="submit" >
+             <span class="glyphicon glyphicon-duplicate" 
aria-hidden="true"></span>
+           </button>
+           <button id="deleteTopology" (click)="deleteConfirmModal.open('sm')" 
class="btn btn-default btn-sm" type="submit" >
+             <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
+           </button>
+           <button id="saveTopology" (click)="saveTopology()" class="btn 
btn-default btn-sm pull-right" [disabled]="!changedTopology" type="submit" >
+             <span class="glyphicon glyphicon-floppy-disk" 
aria-hidden="true"></span>
+           </button>
+         </div>
          
-    </div>
-    <modal (onClose)="createTopology()" #duplicateModal>
-
-        <modal-header [show-close]="true">
-            <h4 class="modal-title">Create a copy</h4>
-        </modal-header>
-        <modal-body>
-            <div class="form-group">
-                <label for="textbox">Name the new topology</label>
-                <input autofocus type="text" class="form-control" required 
[(ngModel)]="newTopologyName" id="textbox">
-            </div> 
-        </modal-body>
-        <modal-footer>
-            <button type="button" class="btn btn-default btn-sm" 
data-dismiss="duplicateModal" (click)="duplicateModal.dismiss()">Cancel</button>
-            <button type="button" class="btn btn-primary btn-sm" 
[disabled]="!newTopologyName" (click)="duplicateModal.close()">Ok</button>
-        </modal-footer>
-    </modal>
-    <modal (onClose)="deleteTopology()" #deleteConfirmModal>
-        <modal-header [show-close]="true">
-            <h4 class="modal-title">Deleting Topology {{titleSuffix}}</h4>
-        </modal-header>
-        <modal-body>
-            Are you sure you want to delete the topology?
-        </modal-body>
-        <modal-footer>
-            <button type="button" class="btn btn-default btn-sm" 
data-dismiss="deleteConfirmModal" 
(click)="deleteConfirmModal.dismiss()">Cancel</button>
-            <button type="button" class="btn btn-primary btn-sm" 
(click)="deleteConfirmModal.close()">Ok</button>
-        </modal-footer>
-    </modal>
+       </div>
+       <bs-modal (onClose)="createTopology()" #duplicateModal>
+         <!--<bs-modal-header [show-close]="true">-->
+         <bs-modal-header>
+           <h4 class="modal-title">Create a copy</h4>
+         </bs-modal-header>
+         <bs-modal-body>
+           <div class="form-group">
+             <label for="textbox">Name the new topology</label>
+             <input autofocus type="text" class="form-control" required 
[(ngModel)]="newTopologyName" id="textbox">
+           </div> 
+         </bs-modal-body>
+         <bs-modal-footer>
+           <button type="button" class="btn btn-default btn-sm" 
data-dismiss="duplicateModal" (click)="duplicateModal.dismiss()">Cancel</button>
+           <button type="button" class="btn btn-primary btn-sm" 
[disabled]="!newTopologyName" (click)="duplicateModal.close()">Ok</button>
+         </bs-modal-footer>
+       </bs-modal>
+       <bs-modal (onClose)="deleteTopology()" #deleteConfirmModal>
+         <!--<bs-modal-header [show-close]="true">-->
+         <bs-modal-header>
+           <h4 class="modal-title">Deleting Topology {{titleSuffix}}</h4>
+         </bs-modal-header>
+         <bs-modal-body>
+           Are you sure you want to delete the topology?
+         </bs-modal-body>
+         <bs-modal-footer>
+           <button type="button" class="btn btn-default btn-sm" 
data-dismiss="deleteConfirmModal" 
(click)="deleteConfirmModal.dismiss()">Cancel</button>
+           <button type="button" class="btn btn-primary btn-sm" 
(click)="deleteConfirmModal.close()">Ok</button>
+         </bs-modal-footer>
+       </bs-modal>
+     </div>
    `
 })
 export class TopologyDetailComponent implements OnInit {
@@ -96,14 +99,14 @@ export class TopologyDetailComponent implements OnInit {
     options:any = {useWorker: false, printMargin: false};
 
     @ViewChild('duplicateModal')
-    duplicateModal: ModalComponent;
+    duplicateModal: BsModalComponent;
 
     @ViewChild('deleteConfirmModal')
-    deleteConfirmModal: ModalComponent;
+    deleteConfirmModal: BsModalComponent;
 
     @ViewChild('editor') editor;
 
-    constructor(private topologyService : TopologyService) {
+    constructor(private topologyService : TopologyService, private 
resourceService: ResourceService) {
     }
 
     ngOnInit(): void {
@@ -152,12 +155,12 @@ export class TopologyDetailComponent implements OnInit {
     * provided tag value make the editor read only
     */
     makeReadOnly(text, tag) {
-        var parser = new DOMParser();
-        var parsed = parser.parseFromString(text,"text/xml");
+        let parser = new DOMParser();
+        let parsed = parser.parseFromString(text,"text/xml");
+
+        let tagValue = parsed.getElementsByTagName(tag);
+        let result = tagValue[0].childNodes[0].nodeValue;
 
-        var tagValue = parsed.getElementsByTagName(tag);
-        var result = tagValue[0].childNodes[0].nodeValue;
-        
         if(result === 'true') {
             this.showEditOptions = false;
             this.options = {readOnly: true, useWorker: false, printMargin: 
false, highlightActiveLine: false, highlightGutterLine: false}; 

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/topology.component.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/topology.component.ts 
b/gateway-admin-ui/src/app/topology.component.ts
index d0d17a6..3d6b7a2 100644
--- a/gateway-admin-ui/src/app/topology.component.ts
+++ b/gateway-admin-ui/src/app/topology.component.ts
@@ -14,9 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {Component, OnInit} from '@angular/core';
-import {Topology} from './topology';
-import {TopologyService} from "./topology.service";
+import { Component, OnInit } from '@angular/core';
+import { Topology } from './topology';
+import { TopologyService } from './topology.service';
 import { Subscription }   from 'rxjs/Subscription';
 
 

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/app/topology.service.ts
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/app/topology.service.ts 
b/gateway-admin-ui/src/app/topology.service.ts
index 15d9986..dc2559f 100644
--- a/gateway-admin-ui/src/app/topology.service.ts
+++ b/gateway-admin-ui/src/app/topology.service.ts
@@ -15,12 +15,10 @@
  * limitations under the License.
  */
 import { Injectable }    from '@angular/core';
-import { Headers, Http } from '@angular/http';
+import { HttpHeaders, HttpClient } from '@angular/common/http';
 
 import 'rxjs/add/operator/toPromise';
 import { Subject }    from 'rxjs/Subject';
-import { Observable }    from 'rxjs/Observable';
-
 import { Topology } from './topology';
 
 @Injectable()
@@ -33,37 +31,37 @@ export class TopologyService {
     changedTopologySource = new Subject<string>();
     changedTopology$ = this.changedTopologySource.asObservable();
 
-    constructor(private http: Http) { }
+    constructor(private http: HttpClient) { }
 
     getTopologies(): Promise<Topology[]> {
-        let headers = new Headers();
+        let headers = new HttpHeaders();
         this.addJsonHeaders(headers);
         return this.http.get(this.topologiesUrl, {
             headers: headers
         } )
             .toPromise()
-            .then(response => response.json().topologies.topology as 
Topology[])
+            .then(response => response['topologies'].topology as Topology[])
             .catch(this.handleError);
     }
 
     getTopology(href : string): Promise<string> {
-        let headers = new Headers();
-        this.addXmlHeaders(headers);
+        let headers = new HttpHeaders();
+        headers = this.addXmlHeaders(headers);
         return this.http.get(href, {
-            headers: headers
+            headers: headers, responseType: 'text'
         } )
             .toPromise()
-            .then(response => response.text())
+            .then(response => response)
             .catch(this.handleError);
 
     }
 
     saveTopology(url: string, xml : string): Promise<string> {
-        let xheaders = new Headers();
-        this.addXmlHeaders(xheaders);
-        this.addCsrfHeaders(xheaders);
+        let xheaders = new HttpHeaders();
+        xheaders = this.addXmlHeaders(xheaders);
+        xheaders = this.addCsrfHeaders(xheaders);
         return this.http
-            .put(url, xml, {headers: xheaders})
+            .put(url, xml, { headers: xheaders, responseType: 'text' })
             .toPromise()
             .then(() => xml)
             .catch(this.handleError);
@@ -71,41 +69,41 @@ export class TopologyService {
     }
 
     createTopology(name: string, xml : string): Promise<string> {
-        let xheaders = new Headers();
-        this.addXmlHeaders(xheaders);
-        this.addCsrfHeaders(xheaders);
+        let xheaders = new HttpHeaders();
+        xheaders = this.addXmlHeaders(xheaders);
+        xheaders = this.addCsrfHeaders(xheaders);
         let url = this.topologiesUrl + "/" + name;
         return this.http
-            .put(url, xml, {headers: xheaders})
+            .put(url, xml, { headers: xheaders, responseType: 'text' })
             .toPromise()
             .then(() => xml)
             .catch(this.handleError);
     }
 
     deleteTopology(href: string): Promise<string> {
-        let headers = new Headers();
-        this.addJsonHeaders(headers);
-        this.addCsrfHeaders(headers);
+        let headers = new HttpHeaders();
+        headers = this.addJsonHeaders(headers);
+        headers = this.addCsrfHeaders(headers);
         return this.http.delete(href, {
-            headers: headers
+            headers: headers, responseType: 'text'
         } )
             .toPromise()
-            .then(response => response.text())
+            .then(response => response)
             .catch(this.handleError);
     }
 
-    addJsonHeaders(headers: Headers) {
-        headers.append('Accept', 'application/json');
-        headers.append('Content-Type', 'application/json');
+    addJsonHeaders(headers: HttpHeaders): HttpHeaders {
+        return headers.append('Accept', 'application/json')
+                      .append('Content-Type', 'application/json');
     }
 
-    addXmlHeaders(headers: Headers) {
-        headers.append('Accept', 'application/xml');
-        headers.append('Content-Type', 'application/xml');
+    addXmlHeaders(headers: HttpHeaders): HttpHeaders {
+        return headers.append('Accept', 'application/xml')
+                      .append('Content-Type', 'application/xml');
     }
 
-    addCsrfHeaders(headers: Headers) {
-        headers.append('X-XSRF-Header', 'admin-ui');
+    addCsrfHeaders(headers: HttpHeaders): HttpHeaders {
+        return headers.append('X-XSRF-Header', 'admin-ui');
     }
 
     selectedTopology(value: Topology) {

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/index.html
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/index.html b/gateway-admin-ui/src/index.html
index 02bc3bd..e2b3be4 100644
--- a/gateway-admin-ui/src/index.html
+++ b/gateway-admin-ui/src/index.html
@@ -19,20 +19,23 @@
   <title>Apache Knox Manager</title>
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
-      <meta name="viewport" content="width=device-width, initial-scale=1">
-    <!-- Latest compiled and minified CSS -->
-    <link rel="stylesheet" 
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"; 
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
 crossorigin="anonymous">
-
-    <!-- Optional theme -->
-    <link rel="stylesheet" 
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css";
 
integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp"
 crossorigin="anonymous">
-    <!-- Custom styles for this template -->
-    <link href="assets/sticky-footer.css" rel="stylesheet">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <!-- Latest compiled and minified CSS -->
+  <link rel="stylesheet" 
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"; 
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
 crossorigin="anonymous">
 
-    <script 
src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js";></script>
-    <!-- Latest compiled and minified JavaScript -->
-    <script 
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"; 
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
 crossorigin="anonymous"></script>
-    <script src="assets/vkbeautify.js"></script>
+  <!-- Optional theme -->
+  <link rel="stylesheet" 
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css";
 
integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp"
 crossorigin="anonymous">
+  <!-- Custom styles for this template -->
+  <link href="assets/sticky-footer.css" rel="stylesheet">
 
+  <script 
src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js";></script>
+  <!-- Latest compiled and minified JavaScript -->
+  <script 
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"; 
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
 crossorigin="anonymous"></script>
+  <script src="assets/vkbeautify.js"></script>
+  <!--
+  <script src="assets/esprima.js"></script>
+  <script src="assets/js-yaml.min.js"></script>
+  -->
 </head>
 <body>
   <div class="navbar-wrapper">
@@ -47,34 +50,18 @@
               <span class="icon-bar"></span>
               <span class="icon-bar"></span>
             </button>
-            <a class="navbar-brand" href="#"> <img style="max-width:100px; 
margin-top: -9px;" src="assets/knox-logo-transparent.gif" alt="Apache Knox 
Manager"> </a>
+            <a class="navbar-brand" href="#"> <img style="max-width:200px; 
margin-top: -9px;" src="assets/knox-logo-transparent.gif" alt="Apache Knox 
Manager"> </a>
           </div>
-          <!--<div id="navbar" class="navbar-collapse collapse">
-            <ul class="nav navbar-nav  navbar-right">
-              <li><a href="./">Logout</a></li>
-            </ul>
-          </div>-->
         </div>
       </nav>
 
   </div>
-  <div class="container">
-
-    <!-- Main component for a primary marketing message or call to action -->
-    <!--
-    <div class="jumbotron">
-      <h3>Topology Management</h3>
-      <p>Resource Access Management</p>
-    </div>
-    -->
-  </div>
-
 
   <!-- Content -->
-  <topology-management></topology-management>
+  <resource-management></resource-management>
 
   <footer class="footer">
-    <div>Knox Manager Version 0.0.1</div>
+    <div>Knox Manager Version 0.1.0</div>
     <gateway-version></gateway-version>
   </footer>
 </body>

http://git-wip-us.apache.org/repos/asf/knox/blob/e8ba712c/gateway-admin-ui/src/styles.css
----------------------------------------------------------------------
diff --git a/gateway-admin-ui/src/styles.css b/gateway-admin-ui/src/styles.css
index 90d4ee0..b6aa3e6 100644
--- a/gateway-admin-ui/src/styles.css
+++ b/gateway-admin-ui/src/styles.css
@@ -1 +1,7 @@
 /* You can add global styles to this file, and also import other style files */
+
+.navbar-static-top {
+    min-height: 110px;
+}
+
+.clickable { cursor: pointer; }
\ No newline at end of file

Reply via email to