http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/gateway-admin-ui/src/app/provider-config-wizard/provider-config-wizard.component.ts ---------------------------------------------------------------------- diff --git a/gateway-admin-ui/src/app/provider-config-wizard/provider-config-wizard.component.ts b/gateway-admin-ui/src/app/provider-config-wizard/provider-config-wizard.component.ts new file mode 100644 index 0000000..8cb4fb9 --- /dev/null +++ b/gateway-admin-ui/src/app/provider-config-wizard/provider-config-wizard.component.ts @@ -0,0 +1,254 @@ +/* + * 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, ViewChild} from '@angular/core'; +import {ResourceTypesService} from "../resourcetypes/resourcetypes.service"; +import {ResourceService} from "../resource/resource.service"; +import {BsModalComponent} from "ng2-bs3-modal"; +import {ProviderConfig} from "../resource-detail/provider-config"; +import {AuthenticationWizard} from "./authentication-wizard"; +import {CategoryWizard} from "./category-wizard"; +import {AuthorizationWizard} from "./authorization-wizard"; +import {IdentityAssertionWizard} from "./identity-assertion-wizard"; +import {HaWizard} from "./ha-wizard"; +import {Resource} from "../resource/resource"; +import {DisplayBindingProviderConfig} from "./display-binding-provider-config"; + +@Component({ + selector: 'app-provider-config-wizard', + templateUrl: './provider-config-wizard.component.html', + styleUrls: ['./provider-config-wizard.component.css'] +}) +export class ProviderConfigWizardComponent implements OnInit { + + private static CATEGORY_STEP = 1; + private static TYPE_STEP = 2; + private static PARAMS_STEP = 3; + + // Provider Categories + private static CATEGORY_AUTHENTICATION: string = 'Authentication'; + private static CATEGORY_AUTHORIZATION: string = 'Authorization'; + private static CATEGORY_ID_ASSERTION: string = 'Identity Assertion'; + private static CATEGORY_HA: string = 'HA'; + private static providerCategories: string[] = [ ProviderConfigWizardComponent.CATEGORY_AUTHENTICATION, + ProviderConfigWizardComponent.CATEGORY_AUTHORIZATION, + ProviderConfigWizardComponent.CATEGORY_ID_ASSERTION, + ProviderConfigWizardComponent.CATEGORY_HA + ]; + + private static CATEGORY_TYPES: Map<string, CategoryWizard> = + new Map([ + [ProviderConfigWizardComponent.CATEGORY_AUTHENTICATION, new AuthenticationWizard() as CategoryWizard], + [ProviderConfigWizardComponent.CATEGORY_AUTHORIZATION, new AuthorizationWizard() as CategoryWizard], + [ProviderConfigWizardComponent.CATEGORY_ID_ASSERTION, new IdentityAssertionWizard() as CategoryWizard], + [ProviderConfigWizardComponent.CATEGORY_HA, new HaWizard() as CategoryWizard] + ]); + + @ViewChild('newProviderConfigModal') + childModal: BsModalComponent; + + private step: number = 0; + + name: String = ''; + + providers: Array<ProviderConfig> = []; + + selectedCategory: string; + + constructor(private resourceTypesService: ResourceTypesService, private resourceService: ResourceService) { } + + ngOnInit() { + this.selectedCategory = ProviderConfigWizardComponent.CATEGORY_AUTHENTICATION; // Default to authentication + } + + open(size?: string) { + this.reset(); + this.childModal.open(size ? size : 'lg'); + } + + reset() { + this.step = 0; + this.name = ''; + this.providers = []; + this.selectedCategory = ProviderConfigWizardComponent.CATEGORY_AUTHENTICATION; + } + + onFinishAdd() { + console.debug('Selected provider category: ' + this.selectedCategory); + + let catWizard = this.getCategoryWizard(this.selectedCategory); + let type = catWizard ? catWizard.getSelectedType() : 'undefined'; + console.debug('Selected provider type: ' + type); + + if (catWizard) { + let pc: ProviderConfig = catWizard.getProviderConfig(); + if (pc) { + this.providers.push(pc); + console.debug('\tProvider Name: ' + pc.name); + console.debug('\tProvider Role: ' + pc.role); + console.debug('\tProvider Enabled: ' + pc.enabled); + if (pc.params) { + for (let name of Object.getOwnPropertyNames(pc.params)) { + console.debug('\t\tParam: ' + name + ' = ' + pc.params[name]); + } + } else { + console.debug('\tNo Params'); + } + } + } + + this.step = 0; // Return to the beginning + } + + onClose() { + console.debug('Provider Configuration: ' + this.name); + + for (let pc of this.providers) { + console.debug('\tProvider: ' + pc.name + ' (' + pc.role + ')'); + } + + // Identify the new resource + let newResource = new Resource(); + newResource.name = this.name + '.json'; + + // Persist the new provider configuration + this.resourceService.createResource('Provider Configurations', + newResource, + this.resourceService.serializeProviderConfiguration(this.providers, 'json')) + .then(() => { + // Reload the resource list presentation + this.resourceTypesService.selectResourceType('Provider Configurations'); + + // Set the new descriptor as the selected resource + this.resourceService.getProviderConfigResources().then(resources => { + for (let res of resources) { + if (res.name === newResource.name) { + this.resourceService.selectedResource(res); + break; + } + } + }); + }); + } + + getStep(): number { + return this.step; + } + + onNextStep() { + ++this.step; + } + + onPreviousStep() { + --this.step; + } + + hasMoreSteps(): boolean { + let result = false; + let catWizard = this.getCategoryWizard(this.selectedCategory); + if (catWizard) { + result = (this.step < (catWizard.getSteps() - 1)); + } + return result; + } + + isRootStep(): boolean { + return (this.step === 0); + } + + isProviderCategoryStep(): boolean { + return (this.step === ProviderConfigWizardComponent.CATEGORY_STEP); + } + + isProviderTypeStep(): boolean { + return (this.step === ProviderConfigWizardComponent.TYPE_STEP); + } + + isProviderParamsStep(): boolean { + return (this.step === ProviderConfigWizardComponent.PARAMS_STEP); + } + + getProviderCategories() : string[] { + return ProviderConfigWizardComponent.providerCategories; + } + + getCategoryWizard(category?: string): CategoryWizard { + return ProviderConfigWizardComponent.CATEGORY_TYPES.get(category ? category : this.selectedCategory); + } + + getProviderTypes(category?: string) : string[] { + let catWizard = this.getCategoryWizard(category); + if (catWizard) { + return catWizard.getTypes(); + } else { + console.debug('Unresolved category wizard for ' + (category ? category : this.selectedCategory)); + } + return []; + } + + getProviderParams(): string[] { + let catWizard = this.getCategoryWizard(); + if (catWizard) { + let pc = catWizard.getProviderConfig(); + if (pc) { + if (pc instanceof DisplayBindingProviderConfig) { + let dispPC = pc as DisplayBindingProviderConfig; + return dispPC.getDisplayPropertyNames(); + } else { + console.debug('Got Vanilla ProviderConfig'); + return []; + } + } else { + console.log('No provider config from category wizard ' + typeof(catWizard)); + } + } else { + console.debug('Unresolved category wizard for ' + this.selectedCategory); + } + return []; + } + + setProviderParamBinding(name: string, value: string) { + let catWizard = this.getCategoryWizard(); + if (catWizard) { + let pc = catWizard.getProviderConfig(); + if (pc) { + if (pc instanceof DisplayBindingProviderConfig) { + let dispPC = pc as DisplayBindingProviderConfig; + let property = dispPC.getDisplayNamePropertyBinding(name); + pc.setParam(property, value); + console.debug('Set ProviderConfig param value: ' + property + '=' + value); + } + } + } + } + + getProviderParamBinding(name: string): string { + let catWizard = this.getCategoryWizard(); + if (catWizard) { + let pc = catWizard.getProviderConfig(); + if (pc) { + if (pc instanceof DisplayBindingProviderConfig) { + let dispPC = pc as DisplayBindingProviderConfig; + let value = pc.getParam(dispPC.getDisplayNamePropertyBinding(name)); + return (value ? value : ''); + } + } + } + return ''; + } + +}
http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/gateway-admin-ui/src/app/provider-config-wizard/regex-idassertion-provider-config.ts ---------------------------------------------------------------------- diff --git a/gateway-admin-ui/src/app/provider-config-wizard/regex-idassertion-provider-config.ts b/gateway-admin-ui/src/app/provider-config-wizard/regex-idassertion-provider-config.ts new file mode 100644 index 0000000..a3a4e9b --- /dev/null +++ b/gateway-admin-ui/src/app/provider-config-wizard/regex-idassertion-provider-config.ts @@ -0,0 +1,53 @@ +/* + * 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 {IdentityAssertionProviderConfig} from "./identity-assertion-provider-config"; + +export class RegexAssertionProviderConfig extends IdentityAssertionProviderConfig { + + static INPUT = 'Input'; + static OUTPUT = 'Output'; + static LOOKUP = "Lookup"; + static ORIG_ON_FAIL = "User Original Lookup on Failure"; + + private static displayPropertyNames = [ RegexAssertionProviderConfig.INPUT, + RegexAssertionProviderConfig.OUTPUT, + RegexAssertionProviderConfig.LOOKUP, + RegexAssertionProviderConfig.ORIG_ON_FAIL + ]; + + private static displayPropertyNameBindings: Map<string, string> = + new Map([ + [RegexAssertionProviderConfig.INPUT, 'input'], + [RegexAssertionProviderConfig.OUTPUT, 'output'], + [RegexAssertionProviderConfig.LOOKUP, 'lookup'], + [RegexAssertionProviderConfig.ORIG_ON_FAIL, 'use.original.on.lookup.failure'] + ]); + + constructor() { + super('Regex'); + } + + getDisplayPropertyNames(): string[] { + return RegexAssertionProviderConfig.displayPropertyNames; + } + + getDisplayNamePropertyBinding(name: string) { + return RegexAssertionProviderConfig.displayPropertyNameBindings.get(name); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/gateway-admin-ui/src/app/provider-config-wizard/saml-provider-config.ts ---------------------------------------------------------------------- diff --git a/gateway-admin-ui/src/app/provider-config-wizard/saml-provider-config.ts b/gateway-admin-ui/src/app/provider-config-wizard/saml-provider-config.ts new file mode 100644 index 0000000..c9cffc1 --- /dev/null +++ b/gateway-admin-ui/src/app/provider-config-wizard/saml-provider-config.ts @@ -0,0 +1,70 @@ +/* + * 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 {AuthenticationProviderConfig} from "./authentication-provider-config"; + +export class SAMLProviderConfig extends AuthenticationProviderConfig { + + static CALLBACK_URL = 'Callback URL'; + static KEYSTORE_PATH = 'Keystore Path'; + static KEYSTORE_PASS = 'Keystore Password'; + static PK_PASS = 'Private Key Password'; + static ID_PROVIDER_META = 'Identity Provider Metadata Path'; + static MAX_AUTH_LIFETIME = 'Maximum Authentication Lifetime'; + static SERVICE_PROVIDER_ID = 'Service Provider Identity'; + static SERVICE_PROVIDER_META = 'Service Provider Metadata Path'; + static COOKIE_DOMAIN_SUFFIX = 'Cookie Domain Suffix'; + + + private static displayPropertyNames = [ SAMLProviderConfig.CALLBACK_URL, + SAMLProviderConfig.KEYSTORE_PATH, + SAMLProviderConfig.KEYSTORE_PASS, + SAMLProviderConfig.PK_PASS, + SAMLProviderConfig.ID_PROVIDER_META, + SAMLProviderConfig.MAX_AUTH_LIFETIME, + SAMLProviderConfig.SERVICE_PROVIDER_ID, + SAMLProviderConfig.SERVICE_PROVIDER_META, + SAMLProviderConfig.COOKIE_DOMAIN_SUFFIX + ]; + + private static displayPropertyNameBindings: Map<string, string> = + new Map([ + [SAMLProviderConfig.CALLBACK_URL, 'pac4j.callbackUrl'], + [SAMLProviderConfig.COOKIE_DOMAIN_SUFFIX, 'pac4j.cookie.domain.suffix'], + [SAMLProviderConfig.KEYSTORE_PATH, 'saml.keystorePath'], + [SAMLProviderConfig.KEYSTORE_PASS, 'saml.keystorePassword'], + [SAMLProviderConfig.PK_PASS, 'saml.privateKeyPassword'], + [SAMLProviderConfig.ID_PROVIDER_META, 'saml.identityProviderMetadataPath'], + [SAMLProviderConfig.MAX_AUTH_LIFETIME, 'saml.maximumAuthenticationLifetime'], + [SAMLProviderConfig.SERVICE_PROVIDER_ID, 'saml.serviceProviderEntityId'], + [SAMLProviderConfig.SERVICE_PROVIDER_META, 'saml.serviceProviderMetadataPath'] + ]); + + + constructor() { + super('pac4j', AuthenticationProviderConfig.FEDERATION_ROLE); + } + + getDisplayPropertyNames(): string[] { + return SAMLProviderConfig.displayPropertyNames; + } + + getDisplayNamePropertyBinding(name: string) { + return SAMLProviderConfig.displayPropertyNameBindings.get(name); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/gateway-admin-ui/src/app/provider-config-wizard/sso-cookie-provider-config.ts ---------------------------------------------------------------------- diff --git a/gateway-admin-ui/src/app/provider-config-wizard/sso-cookie-provider-config.ts b/gateway-admin-ui/src/app/provider-config-wizard/sso-cookie-provider-config.ts new file mode 100644 index 0000000..bc54e6a --- /dev/null +++ b/gateway-admin-ui/src/app/provider-config-wizard/sso-cookie-provider-config.ts @@ -0,0 +1,43 @@ +/* + * 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 {AuthenticationProviderConfig} from "./authentication-provider-config"; + +export class SSOCookieProviderConfig extends AuthenticationProviderConfig { + + static PROVIDER_URL = 'Provider URL'; + + private static displayPropertyNames = [ SSOCookieProviderConfig.PROVIDER_URL ]; + + private static displayPropertyNameBindings: Map<string, string> = + new Map([ [SSOCookieProviderConfig.PROVIDER_URL, 'sso.authentication.provider.url'] ]); + + + constructor() { + console.debug('new SSOCookieProviderConfig()'); + super('SSOCookieProvider', AuthenticationProviderConfig.FEDERATION_ROLE); + } + + getDisplayPropertyNames(): string[] { + return SSOCookieProviderConfig.displayPropertyNames; + } + + getDisplayNamePropertyBinding(name: string) { + return SSOCookieProviderConfig.displayPropertyNameBindings.get(name); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/gateway-admin-ui/src/app/provider-config-wizard/switchcase-idassertion-provider-config.ts ---------------------------------------------------------------------- diff --git a/gateway-admin-ui/src/app/provider-config-wizard/switchcase-idassertion-provider-config.ts b/gateway-admin-ui/src/app/provider-config-wizard/switchcase-idassertion-provider-config.ts new file mode 100644 index 0000000..5284f13 --- /dev/null +++ b/gateway-admin-ui/src/app/provider-config-wizard/switchcase-idassertion-provider-config.ts @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {IdentityAssertionProviderConfig} from "./identity-assertion-provider-config"; + +export class SwitchCaseAssertionProviderConfig extends IdentityAssertionProviderConfig { + + static PRINCIPAL_CASE = 'Principal Case'; + static GROUP_PRINCIPAL_CASE = 'Group Principal Case'; + + private static displayPropertyNames = [ SwitchCaseAssertionProviderConfig.PRINCIPAL_CASE, + SwitchCaseAssertionProviderConfig.GROUP_PRINCIPAL_CASE + ]; + + private static displayPropertyNameBindings: Map<string, string> = + new Map([ + [SwitchCaseAssertionProviderConfig.PRINCIPAL_CASE, 'principal.case'], + [SwitchCaseAssertionProviderConfig.GROUP_PRINCIPAL_CASE, 'group.principal.case'] + ]); + + constructor() { + super('SwitchCase'); + } + + getDisplayPropertyNames(): string[] { + return SwitchCaseAssertionProviderConfig.displayPropertyNames; + } + + getDisplayNamePropertyBinding(name: string) { + return SwitchCaseAssertionProviderConfig.displayPropertyNameBindings.get(name); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/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 index fc8d1d7..27a09b6 100644 --- a/gateway-admin-ui/src/app/resource-detail/resource-detail.component.html +++ b/gateway-admin-ui/src/app/resource-detail/resource-detail.component.html @@ -46,8 +46,8 @@ <div class="panel-body" *ngIf="isShowProvider(provider)"> <strong>Role</strong> {{ provider.role }}<br> <strong>Enabled</strong> <input type="checkbox" - [checked]="isProviderEnabled(provider)" - (click)="onProviderEnabled(provider)"><br> + [checked]="isProviderEnabled(provider)" + (click)="onProviderEnabled(provider)"><br> <div> <span [class]="'clickable inline-glyph glyhpicon glyphicon-' + (isShowProviderParams(provider) ? 'minus' : 'plus')" (click)="toggleShowProviderParams(provider)"></span> @@ -137,7 +137,7 @@ <div class="panel panel-default col-md-12"> <span class="col-md-12 pull-left"> <span class="col-md-sm"><strong>Provider Configuration</strong> </span> - <span class="col-md-sm inline-editable" (click)="editModePC=true" *ngIf="!editModePC">{{ descriptor.providerConfig}}</span> + <span class="col-md-sm inline-editable" (click)="editModePC=true" *ngIf="!editModePC">{{descriptor.providerConfig}}</span> <span class="col-md-sm inline-editor inlineEditForm" *ngIf="editModePC"> <input type="text" size="40" [(ngModel)]="descriptor.providerConfig"> <button class="btn btn-xs" (click)="editModePC=false;descriptor.setDirty()"> http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/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 index 14a5213..2ffaf77 100644 --- a/gateway-admin-ui/src/app/resource-detail/resource-detail.component.ts +++ b/gateway-admin-ui/src/app/resource-detail/resource-detail.component.ts @@ -79,6 +79,7 @@ export class ResourceDetailComponent implements OnInit { setResource(res: Resource) { //console.debug('ResourceDetailComponent --> setResource() --> ' + ((res) ? res.name : 'null')); + this.referencedProviderConfigError = false; this.resource = res; this.providers = []; this.changedProviders = null; @@ -201,12 +202,12 @@ export class ResourceDetailComponent implements OnInit { let ext = this.resource.name.split('.').pop(); switch(ext) { case 'json': { - content = this.serializeProviderConfiguration(this.providers, 'json'); + content = this.resourceService.serializeProviderConfiguration(this.providers, 'json'); break; } case 'yaml': case 'yml': { - content = this.serializeProviderConfiguration(this.providers, 'yaml'); + content = this.resourceService.serializeProviderConfiguration(this.providers, 'yaml'); break; } case 'xml': { @@ -215,7 +216,7 @@ export class ResourceDetailComponent implements OnInit { console.debug('Replacing XML provider configuration ' + this.resource.name + ' with JSON...'); // Generate the JSON representation of the updated provider configuration - content = this.serializeProviderConfiguration(this.providers, 'json'); + content = this.resourceService.serializeProviderConfiguration(this.providers, 'json'); let replacementResource = new Resource(); replacementResource.name = this.resource.name.slice(0, -4) + '.json'; @@ -259,12 +260,12 @@ export class ResourceDetailComponent implements OnInit { let ext = this.resource.name.split('.').pop(); switch(ext) { case 'json': { - content = this.serializeDescriptor(this.descriptor, 'json'); + content = this.resourceService.serializeDescriptor(this.descriptor, 'json'); break; } case 'yaml': case 'yml': { - content = this.serializeDescriptor(this.descriptor, 'yaml'); + content = this.resourceService.serializeDescriptor(this.descriptor, 'yaml'); break; } } @@ -281,82 +282,6 @@ export class ResourceDetailComponent implements OnInit { } - serializeDescriptor(desc: Descriptor, format: string): string { - let serialized: string; - - let tmp = {}; - if (desc.discoveryAddress) { - tmp['discovery-address'] = desc.discoveryAddress; - } - if (desc.discoveryUser) { - tmp['discovery-user'] = desc.discoveryUser; - } - if (desc.discoveryPassAlias) { - tmp['discovery-pwd-alias'] = desc.discoveryPassAlias; - } - if (desc.discoveryCluster) { - tmp['cluster'] = desc.discoveryCluster; - } - tmp['provider-config-ref'] = desc.providerConfig; - tmp['services'] = desc.services; - - switch(format) { - case 'json': { - serialized = - JSON.stringify(tmp, - (key, value) => { - let result = value; - switch(typeof value) { - case 'string': // Don't serialize empty string value properties - result = (value.length > 0) ? value : undefined; - break; - case 'object': - if (Array.isArray(value)) { - // Don't serialize empty array value properties - result = (value.length) > 0 ? value : undefined; - } else { - // Don't serialize object value properties - result = (Object.getOwnPropertyNames(value).length > 0) ? value : undefined; - } - break; - } - return result; - }, 2); - break; - } - case 'yaml': { - let yaml = require('js-yaml'); - serialized = '---\n' + yaml.safeDump(tmp); - break; - } - } - - return serialized; - } - - - serializeProviderConfiguration(providers: Array<ProviderConfig>, format: string): string { - let serialized: string; - - let tmp = {}; - tmp['providers'] = providers; - - switch(format) { - case 'json': { - serialized = JSON.stringify(tmp, null, 2); - break; - } - case 'yaml': { - let yaml = require('js-yaml'); - serialized = '---\n' + yaml.dump(tmp); - break; - } - } - - return serialized; - } - - discardChanges() { this.resourceService.selectedResource(this.resource); } http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/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 index e964edf..5e41a3b 100644 --- a/gateway-admin-ui/src/app/resource/resource.component.html +++ b/gateway-admin-ui/src/app/resource/resource.component.html @@ -3,7 +3,22 @@ <table class="table table-hover"> <thead> <tr> - <th>{{ getResourceTypeSingularDisplayName(resourceType) }}</th> + <th> + <span> + {{ getResourceTypeSingularDisplayName(resourceType) }} + </span> + <span class="clickable inline-glyph glyphicon glyphicon-plus-sign btn btn-xs pull-right" + *ngIf="resourceType === 'Provider Configurations'" + (click)="newProviderConfigModal.open()" + title="Create New Provider Configuration" + data-toggle="tooltip"></span> + <span class="clickable inline-glyph glyphicon glyphicon-plus-sign btn btn-xs pull-right" + (click)="isAddingService=true" + *ngIf="resourceType === 'Descriptors'" + (click)="newDescriptorModal.open()" + title="Create New Descriptor" + data-toggle="tooltip"></span> + </th> <th *ngIf="resourceType === 'Topologies'">Timestamp</th> </tr> </thead> @@ -19,4 +34,8 @@ </tbody> </table> </div> + <div> + <app-new-desc-wizard #newDescriptorModal></app-new-desc-wizard> + <app-provider-config-wizard #newProviderConfigModal></app-provider-config-wizard> + </div> </div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/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 index 1b36823..88b8de5 100644 --- a/gateway-admin-ui/src/app/resource/resource.service.ts +++ b/gateway-admin-ui/src/app/resource/resource.service.ts @@ -20,6 +20,7 @@ import 'rxjs/add/operator/toPromise'; import { Subject } from 'rxjs/Subject'; import { Resource } from './resource'; import {ProviderConfig} from "../resource-detail/provider-config"; +import {Descriptor} from "../resource-detail/descriptor"; @Injectable() @@ -136,7 +137,7 @@ export class ResourceService { headers = this.addCsrfHeaders(headers); //this.logHeaders(headers); - let url = ((resType === 'Descriptors') ? this.descriptorsUrl : this.providersUrl) + '/' + name; + let url = ((resType === 'Descriptors') ? this.descriptorsUrl : this.providersUrl) + '/' + resource.name; return this.http.put(url, content, {headers: headers}) .toPromise() .then(() => content) @@ -160,6 +161,83 @@ export class ResourceService { }); } + + serializeDescriptor(desc: Descriptor, format: string): string { + let serialized: string; + + let tmp = {}; + if (desc.discoveryAddress) { + tmp['discovery-address'] = desc.discoveryAddress; + } + if (desc.discoveryUser) { + tmp['discovery-user'] = desc.discoveryUser; + } + if (desc.discoveryPassAlias) { + tmp['discovery-pwd-alias'] = desc.discoveryPassAlias; + } + if (desc.discoveryCluster) { + tmp['cluster'] = desc.discoveryCluster; + } + tmp['provider-config-ref'] = desc.providerConfig; + tmp['services'] = desc.services; + + switch(format) { + case 'json': { + serialized = + JSON.stringify(tmp, + (key, value) => { + let result = value; + switch(typeof value) { + case 'string': // Don't serialize empty string value properties + result = (value.length > 0) ? value : undefined; + break; + case 'object': + if (Array.isArray(value)) { + // Don't serialize empty array value properties + result = (value.length) > 0 ? value : undefined; + } else { + // Don't serialize object value properties + result = (Object.getOwnPropertyNames(value).length > 0) ? value : undefined; + } + break; + } + return result; + }, 2); + break; + } + case 'yaml': { + let yaml = require('js-yaml'); + serialized = '---\n' + yaml.safeDump(tmp); + break; + } + } + + return serialized; + } + + + serializeProviderConfiguration(providers: Array<ProviderConfig>, format: string): string { + let serialized: string; + + let tmp = {}; + tmp['providers'] = providers; + + switch(format) { + case 'json': { + serialized = JSON.stringify(tmp, null, 2); + break; + } + case 'yaml': { + let yaml = require('js-yaml'); + serialized = '---\n' + yaml.dump(tmp); + break; + } + } + + return serialized; + } + + addHeaders(headers: HttpHeaders, resName: string): HttpHeaders { let ext = resName.split('.').pop(); switch(ext) { @@ -200,6 +278,7 @@ export class ResourceService { } selectedResourceType(value: string) { + //console.debug('ResourceService --> selectedResourceType(\'' + value +'\')') this.selectedResourceTypeSource.next(value); } http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/gateway-applications/src/main/resources/applications/admin-ui/app/index.html ---------------------------------------------------------------------- diff --git a/gateway-applications/src/main/resources/applications/admin-ui/app/index.html b/gateway-applications/src/main/resources/applications/admin-ui/app/index.html index 6f5a825..aae1ecd 100644 --- a/gateway-applications/src/main/resources/applications/admin-ui/app/index.html +++ b/gateway-applications/src/main/resources/applications/admin-ui/app/index.html @@ -11,4 +11,4 @@ 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. ---><!doctype html><html><head><meta charset="utf-8"><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"><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script><!-- Latest compiled and minified JavaScript --><scr ipt 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><link href="styles.2ee5b7f4cd59a6cf015e.bundle.css" rel="stylesheet"/></head><body><div class="navbar-wrapper"><div class="container-fluid"><nav class="navbar navbar-inverse navbar-static-top"><div class="container-fluid"><div class="navbar-header"><button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"><span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span></button> <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></nav></div><!-- Content --><resource-management></res ource-management><footer class="footer"><div>Knox Manager Version 0.1.0</div><gateway-version></gateway-version></footer><script type="text/javascript" src="inline.49efa231bf249ddc231a.bundle.js"></script><script type="text/javascript" src="scripts.c50bb762c438ae0f8842.bundle.js"></script><script type="text/javascript" src="main.511817c8d904b468f742.bundle.js"></script></div></body></html> \ No newline at end of file +--><!doctype html><html><head><meta charset="utf-8"><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"><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script><!-- Latest compiled and minified JavaScript --><scr ipt 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><link href="styles.2ee5b7f4cd59a6cf015e.bundle.css" rel="stylesheet"/></head><body><div class="navbar-wrapper"><div class="container-fluid"><nav class="navbar navbar-inverse navbar-static-top"><div class="container-fluid"><div class="navbar-header"><button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"><span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span></button> <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></nav></div><!-- Content --><resource-management></res ource-management><footer class="footer"><div>Knox Manager Version 0.1.0</div><gateway-version></gateway-version></footer><script type="text/javascript" src="inline.01f49f7d13670ad68dea.bundle.js"></script><script type="text/javascript" src="scripts.c50bb762c438ae0f8842.bundle.js"></script><script type="text/javascript" src="main.db638922a84cdef35de7.bundle.js"></script></div></body></html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/gateway-applications/src/main/resources/applications/admin-ui/app/inline.01f49f7d13670ad68dea.bundle.js ---------------------------------------------------------------------- diff --git a/gateway-applications/src/main/resources/applications/admin-ui/app/inline.01f49f7d13670ad68dea.bundle.js b/gateway-applications/src/main/resources/applications/admin-ui/app/inline.01f49f7d13670ad68dea.bundle.js new file mode 100644 index 0000000..7cbd9f2 --- /dev/null +++ b/gateway-applications/src/main/resources/applications/admin-ui/app/inline.01f49f7d13670ad68dea.bundle.js @@ -0,0 +1 @@ +!function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,c,u){for(var a,i,f,l=0,s=[];l<r.length;l++)t[i=r[l]]&&s.push(t[i][0]),t[i]=0;for(a in c)Object.prototype.hasOwnProperty.call(c,a)&&(e[a]=c[a]);for(n&&n(r,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=o(o.s=u[l]);return f};var r={},t={2:0};function o(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.e=function(e){var n=t[e];if(0===n)return new Promise(function(e){e()});if(n)return n[2];var r=new Promise(function(r,o){n=t[e]=[r,o]});n[2]=r;var c=document.getElementsByTagName("head")[0],u=document.createElement("script");u.type="text/javascript",u.charset="utf-8",u.async=!0,u.timeout=12e4,o.nc&&u.setAttribute("nonce",o.nc),u.src=o.p+""+e+"."+{0:"db638922a84cdef35de7",1:"aed76669724804835353"}[e]+".chunk.js";var a=setTimeout(i,12e4);function i(){u.onerror=u.onload=null,clearTimeout(a);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chu nk "+e+" failed.")),t[e]=void 0)}return u.onerror=u.onload=i,c.appendChild(u),r},o.m=e,o.c=r,o.d=function(e,n,r){o.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="",o.oe=function(e){throw console.error(e),e}}([]); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/167053bd/gateway-applications/src/main/resources/applications/admin-ui/app/inline.49efa231bf249ddc231a.bundle.js ---------------------------------------------------------------------- diff --git a/gateway-applications/src/main/resources/applications/admin-ui/app/inline.49efa231bf249ddc231a.bundle.js b/gateway-applications/src/main/resources/applications/admin-ui/app/inline.49efa231bf249ddc231a.bundle.js deleted file mode 100644 index 965479e..0000000 --- a/gateway-applications/src/main/resources/applications/admin-ui/app/inline.49efa231bf249ddc231a.bundle.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,c,u){for(var a,i,f,l=0,s=[];l<r.length;l++)t[i=r[l]]&&s.push(t[i][0]),t[i]=0;for(a in c)Object.prototype.hasOwnProperty.call(c,a)&&(e[a]=c[a]);for(n&&n(r,c,u);s.length;)s.shift()();if(u)for(l=0;l<u.length;l++)f=o(o.s=u[l]);return f};var r={},t={2:0};function o(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.e=function(e){var n=t[e];if(0===n)return new Promise(function(e){e()});if(n)return n[2];var r=new Promise(function(r,o){n=t[e]=[r,o]});n[2]=r;var c=document.getElementsByTagName("head")[0],u=document.createElement("script");u.type="text/javascript",u.charset="utf-8",u.async=!0,u.timeout=12e4,o.nc&&u.setAttribute("nonce",o.nc),u.src=o.p+""+e+"."+{0:"511817c8d904b468f742",1:"aed76669724804835353"}[e]+".chunk.js";var a=setTimeout(i,12e4);function i(){u.onerror=u.onload=null,clearTimeout(a);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chu nk "+e+" failed.")),t[e]=void 0)}return u.onerror=u.onload=i,c.appendChild(u),r},o.m=e,o.c=r,o.d=function(e,n,r){o.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="",o.oe=function(e){throw console.error(e),e}}([]); \ No newline at end of file
