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"> + <b>Role</b> {{ provider.role }}<br> + <b>Enabled</b> {{ provider.enabled }}<br> + <div> + <span> </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> </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> </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
