You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by sm...@apache.org on 2026/07/04 18:58:40 UTC
(knox) 32/46: KNOX-3234: Upgrade Admin UI Angular to 21+, bootstrap to 5+ (#1249)
This is an automated email from the ASF dual-hosted git repository.
smolnar82 pushed a commit to branch knox_idf
in repository https://gitbox.apache.org/repos/asf/knox.git
commit 9563c06367bf9ddc3266e76d7e0a429b5c7ba49f
Author: hanicz <ha...@users.noreply.github.com>
AuthorDate: Tue Jun 23 14:08:40 2026 +0200
KNOX-3234: Upgrade Admin UI Angular to 21+, bootstrap to 5+ (#1249)
* KNOX-3234: Upgrade Admin UI Angular to 21+, bootstrap to 5+
* KNOX-3234: Fixed editor scroll, separated components into ts,html and css
(cherry picked from commit aca611f1c603f77ee0a73997d4a9eee2409fd795)
---
gateway-admin-ui/.eslintrc.json | 98 ---
gateway-admin-ui/admin-ui/app/app.component.html | 16 +-
.../admin-ui/app/app.component.spec.ts | 53 --
gateway-admin-ui/admin-ui/app/app.component.ts | 28 +-
gateway-admin-ui/admin-ui/app/app.module.ts | 97 ---
.../app/descriptor/descriptor.component.css | 0
.../app/descriptor/descriptor.component.html | 3 -
.../app/descriptor/descriptor.component.spec.ts | 41 -
.../gateway-version/gateway-version.component.css | 18 +
.../gateway-version/gateway-version.component.html | 5 +
.../gateway-version.component.ts | 14 +-
gateway-admin-ui/admin-ui/app/index.ts | 18 -
gateway-admin-ui/admin-ui/app/main.ts | 21 -
.../app/{resource-detail => model}/descriptor.ts | 2 +-
.../admin-ui/app/{ => model}/gateway-version.ts | 0
.../{resource-detail => model}/provider-config.ts | 0
.../admin-ui/app/{resource => model}/resource.ts | 2 -
.../admin-ui/app/{resource => model}/service.ts | 0
.../servicedefinition.ts | 4 -
.../session-information.ts} | 3 -
.../admin-ui/app/{ => model}/topology.ts | 0
.../new-desc-wizard/new-desc-wizard.component.css | 23 +
.../new-desc-wizard/new-desc-wizard.component.html | 244 +++---
.../new-desc-wizard.component.spec.ts | 41 -
.../new-desc-wizard/new-desc-wizard.component.ts | 24 +-
.../provider-config-selector.component.html | 39 +-
.../provider-config-selector.component.spec.ts | 41 -
.../provider-config-selector.component.ts | 25 +-
.../AnonymousProviderConfig.ts | 2 +-
.../authentication-wizard.ts | 3 +-
.../provider-config-wizard/authorization-wizard.ts | 3 +-
.../app/provider-config-wizard/category-wizard.ts | 2 +-
.../provider-config-wizard/csrf-provider-config.ts | 3 +-
.../display-binding-provider-config.ts | 6 +-
.../app/provider-config-wizard/ha-wizard.ts | 2 +-
.../hostmap-provider-wizard.ts | 2 +-
.../identity-assertion-wizard.ts | 5 +-
.../provider-config-wizard.component.html | 249 +++---
.../provider-config-wizard.component.spec.ts | 41 -
.../provider-config-wizard.component.ts | 24 +-
.../provider-contributor-wizard.ts | 2 +-
.../webappsec-provider-config.ts | 2 +-
.../app/provider-config-wizard/webappsec-wizard.ts | 5 +-
.../resource-detail/resource-detail.component.css | 14 +-
.../resource-detail/resource-detail.component.html | 956 +++++++++++----------
.../resource-detail.component.spec.ts | 41 -
.../resource-detail/resource-detail.component.ts | 79 +-
.../admin-ui/app/resource/resource.component.css | 58 ++
.../admin-ui/app/resource/resource.component.html | 88 +-
.../app/resource/resource.component.spec.ts | 41 -
.../admin-ui/app/resource/resource.component.ts | 52 +-
.../app/resourcetypes/resourcetypes.component.css | 45 +
.../app/resourcetypes/resourcetypes.component.html | 28 +-
.../resourcetypes/resourcetypes.component.spec.ts | 41 -
.../app/resourcetypes/resourcetypes.component.ts | 4 +-
.../new-service-definition.component.css | 24 +-
.../new-service-definition.component.html | 40 +-
.../new-service-definition.component.ts | 44 +-
.../app/service-definition/rewrite.rules.ts | 21 -
.../servicedefinition-detail.component.css | 76 ++
.../servicedefinition-detail.component.html | 65 ++
.../servicedefinition-detail.component.ts | 93 +-
.../app/{ => service}/gateway-version.service.ts | 19 +-
.../app/{resource => service}/resource.service.ts | 100 +--
.../resourcetypes.service.ts | 4 +-
.../servicedefinition.service.ts | 95 +-
.../session.information.service.ts | 19 +-
.../admin-ui/app/{ => service}/topology.service.ts | 68 +-
.../session.information.component.html | 0
.../session.information.component.ts | 11 +-
.../admin-ui/app/topology-detail.component.ts | 209 -----
.../topology-detail/topology-detail.component.css | 80 ++
.../topology-detail/topology-detail.component.html | 77 ++
.../topology-detail/topology-detail.component.ts | 118 +++
.../admin-ui/app/topology/topology.component.html | 19 +
.../app/{ => topology}/topology.component.ts | 30 +-
.../admin-ui/app/utils/json-pretty.pipe.ts | 4 +-
.../admin-ui/app/utils/modal.component.html | 10 +
.../modal.component.ts} | 27 +-
.../admin-ui/app/utils/tab.component.css | 3 +
.../admin-ui/app/utils/tab.component.html | 2 +
.../admin-ui/app/utils/tab.component.ts | 11 +-
.../admin-ui/app/utils/tabs.component.html | 7 +
.../admin-ui/app/utils/tabs.component.ts | 15 +-
.../admin-ui/app/utils/validation-utils.ts | 2 +-
gateway-admin-ui/admin-ui/app/utils/xml.pipe.ts | 4 +-
gateway-admin-ui/admin-ui/assets/sticky-footer.css | 24 -
gateway-admin-ui/admin-ui/index.html | 50 +-
gateway-admin-ui/admin-ui/main.ts | 28 +-
.../rewrite.rule.ts => material-theme.scss} | 11 +-
gateway-admin-ui/admin-ui/polyfills.ts | 20 +-
gateway-admin-ui/admin-ui/styles.css | 9 -
gateway-admin-ui/admin-ui/styles.scss | 354 ++++++++
gateway-admin-ui/admin-ui/tsconfig.json | 11 +-
gateway-admin-ui/admin-ui/typings.d.ts | 18 -
gateway-admin-ui/angular.json | 45 +-
gateway-admin-ui/eslint.config.js | 76 ++
gateway-admin-ui/package.json | 75 +-
gateway-admin-ui/pom.xml | 8 +-
.../session.information.component.html | 1 -
.../session.information.component.html | 1 -
101 files changed, 2344 insertions(+), 2342 deletions(-)
diff --git a/gateway-admin-ui/.eslintrc.json b/gateway-admin-ui/.eslintrc.json
deleted file mode 100644
index 71378a09f..000000000
--- a/gateway-admin-ui/.eslintrc.json
+++ /dev/null
@@ -1,98 +0,0 @@
-{
- "root": true,
- "overrides": [
- {
- "files": [
- "*.ts"
- ],
- "parserOptions": {
- "project": [
- "admin-ui/tsconfig.json"
- ],
- "createDefaultProgram": true
- },
- "extends": [
- "plugin:@angular-eslint/recommended",
- "plugin:@angular-eslint/template/process-inline-templates"
- ],
- "rules": {
- "@typescript-eslint/naming-convention": [
- "error",
- {
- "selector": ["class"],
- "format": ["PascalCase"]
- }
- ],
- "spaced-comment": "error",
- "curly": "error",
- "eol-last": "error",
- "guard-for-in": "error",
- "no-unused-labels": "error",
- "max-len": [
- "error",
- { "code": 140 }
- ],
- "@typescript-eslint/explicit-member-accessibility": [
- "off",
- {"accessibility": "no-public"}
- ],
- "@typescript-eslint/member-ordering": [
- "error",
- { "default": ["static-field", "instance-field", "field", "method"] }
- ],
- "no-caller": "error",
- "no-bitwise": "error",
- "no-console": "off",
- "no-new-wrappers": "error",
- "no-debugger": "error",
- "no-redeclare": "off",
- "no-empty": "error",
- "no-eval": "error",
- "@typescript-eslint/no-inferrable-types": "error",
- "no-shadow": "error",
- "dot-notation": "off",
- "no-fallthrough": "error",
- "no-trailing-spaces": "error",
- "no-unused-expressions": "error",
- "no-var": "error",
- "sort-keys": "off",
- "brace-style": ["error","1tbs", { "allowSingleLine": true }],
- "quotes": ["error", "single"],
- "radix": "error",
- "@typescript-eslint/semi": "error",
- "eqeqeq": ["error", "always", {"null": "ignore"}],
- "@typescript-eslint/type-annotation-spacing": "error",
- "@angular-eslint/directive-selector": [
- "error",
- {
- "type": "attribute",
- "prefix": "app",
- "style": "camelCase"
- }
- ],
- "@angular-eslint/component-selector": [
- "error",
- {
- "type": "element",
- "prefix": "app",
- "style": "kebab-case"
- }
- ],
- "@angular-eslint/no-input-rename": "off",
- "@angular-eslint/no-output-rename": "error",
- "@angular-eslint/use-pipe-transform-interface": "error",
- "@angular-eslint/component-class-suffix": "error",
- "@angular-eslint/directive-class-suffix": "error"
- }
- },
- {
- "files": [
- "*.html"
- ],
- "extends": [
- "plugin:@angular-eslint/template/recommended"
- ],
- "rules": {}
- }
- ]
-}
diff --git a/gateway-admin-ui/admin-ui/app/app.component.html b/gateway-admin-ui/admin-ui/app/app.component.html
index f40042c11..b96560ee9 100644
--- a/gateway-admin-ui/admin-ui/app/app.component.html
+++ b/gateway-admin-ui/admin-ui/app/app.component.html
@@ -1,3 +1,13 @@
-<h1>
- {{title}}
-</h1>
+<div class="container-fluid" style="padding-top: 15px;">
+ <div class="row">
+ <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>
diff --git a/gateway-admin-ui/admin-ui/app/app.component.spec.ts b/gateway-admin-ui/admin-ui/app/app.component.spec.ts
deleted file mode 100644
index f34160586..000000000
--- a/gateway-admin-ui/admin-ui/app/app.component.spec.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/* tslint:disable:no-unused-variable */
-import {AppComponent} from './app.component';
-
-import {TestBed} from '@angular/core/testing';
-
-import {By} from '@angular/platform-browser';
-
-// SPECS
-
-// Delete this
-describe('Smoke test', () => {
- it('should run a passing test', () => {
- expect(true).toEqual(true, 'should pass');
- });
-});
-
-describe('AppComponent with TCB', function () {
- beforeEach(() => {
- TestBed.configureTestingModule({declarations: [AppComponent]});
- });
-
- it('should instantiate component', () => {
- let fixture = TestBed.createComponent(AppComponent);
- expect(fixture.componentInstance instanceof AppComponent).toBe(true, 'should create AppComponent');
- });
-
- it('should have expected <h1> text', () => {
- let fixture = TestBed.createComponent(AppComponent);
- fixture.detectChanges();
-
- let h1 = fixture.debugElement.query(el => el.name === 'h1').nativeElement; // it works
-
- h1 = fixture.debugElement.query(By.css('h1')).nativeElement; // preferred
-
- expect(h1.innerText).toMatch(/angular 2 app/i, '<h1> should say something about "Angular 2 App"');
- });
-});
diff --git a/gateway-admin-ui/admin-ui/app/app.component.ts b/gateway-admin-ui/admin-ui/app/app.component.ts
index 63fd7e777..73374693f 100644
--- a/gateway-admin-ui/admin-ui/app/app.component.ts
+++ b/gateway-admin-ui/admin-ui/app/app.component.ts
@@ -15,33 +15,15 @@
* limitations under the License.
*/
import {Component} from '@angular/core';
-import {TopologyService} from './topology.service';
-import {ServiceDefinitionService} from './service-definition/servicedefinition.service';
-import {ResourceTypesService} from './resourcetypes/resourcetypes.service';
+import {ResourcetypesComponent} from './resourcetypes/resourcetypes.component';
+import {ResourceComponent} from './resource/resource.component';
+import {ResourceDetailComponent} from './resource-detail/resource-detail.component';
@Component({
selector: 'app-resource-management',
- template: `
- <div class="container-fluid">
- <div class="row">
- <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, ServiceDefinitionService, ResourceTypesService]
+ templateUrl: './app.component.html',
+ imports: [ResourcetypesComponent, ResourceComponent, ResourceDetailComponent]
})
export class AppComponent {
- constructor(private topologyService: TopologyService,
- private serviceDefinitionService: ServiceDefinitionService,
- private resourcetypesService: ResourceTypesService) {
- }
}
diff --git a/gateway-admin-ui/admin-ui/app/app.module.ts b/gateway-admin-ui/admin-ui/app/app.module.ts
deleted file mode 100644
index bc51ea9e9..000000000
--- a/gateway-admin-ui/admin-ui/app/app.module.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {NgModule} from '@angular/core';
-import {DataTableModule} from 'angular2-datatable';
-import {BrowserModule} from '@angular/platform-browser';
-import {HttpClientModule, HttpClientXsrfModule} from '@angular/common/http';
-import {FormsModule} from '@angular/forms';
-import {CustomFormsModule} from 'ng2-validation';
-import {APP_BASE_HREF} from '@angular/common';
-
-import {AppComponent} from './app.component';
-import {TopologyService} from './topology.service';
-import {ServiceDefinitionService} from './service-definition/servicedefinition.service';
-import {ServiceDefinitionDetailComponent} from './service-definition/servicedefinition-detail.component';
-import {NewServiceDefinitionComponent} from './service-definition/new-service-definition.component';
-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 {BsModalModule} from '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';
-import {ProviderConfigSelectorComponent} from './provider-config-selector/provider-config-selector.component';
-import {NewDescWizardComponent} from './new-desc-wizard/new-desc-wizard.component';
-import {ProviderConfigWizardComponent} from './provider-config-wizard/provider-config-wizard.component';
-import {SessionInformationComponent} from './sessionInformation/session.information.component';
-import {SafeHtmlPipe} from './sessionInformation/session.information.component';
-
-@NgModule({
- imports: [BrowserModule,
- HttpClientModule,
- HttpClientXsrfModule,
- FormsModule,
- CustomFormsModule,
- BsModalModule,
- AceEditorModule,
- DataTableModule
- ],
- declarations: [AppComponent,
- TopologyComponent,
- TopologyDetailComponent,
- ServiceDefinitionDetailComponent,
- NewServiceDefinitionComponent,
- GatewayVersionComponent,
- XmlPipe,
- JsonPrettyPipe,
- TabsComponent,
- TabComponent,
- ResourcetypesComponent,
- ResourceComponent,
- DescriptorComponent,
- ResourceDetailComponent,
- ProviderConfigSelectorComponent,
- NewDescWizardComponent,
- ProviderConfigWizardComponent,
- SessionInformationComponent,
- SafeHtmlPipe
- ],
- providers: [TopologyService,
- ServiceDefinitionService,
- GatewayVersionService,
- ResourceComponent,
- ResourceTypesService,
- ResourceService,
- {provide: APP_BASE_HREF, useValue: '/'}
- ],
- bootstrap: [AppComponent,
- GatewayVersionComponent,
- SessionInformationComponent
- ]
-})
-export class AppModule {
-}
diff --git a/gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.css b/gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.css
deleted file mode 100644
index e69de29bb..000000000
diff --git a/gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.html b/gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.html
deleted file mode 100644
index c4e7fc1ef..000000000
--- a/gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<p>
- descriptor works!
-</p>
diff --git a/gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.spec.ts b/gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.spec.ts
deleted file mode 100644
index 850d7064b..000000000
--- a/gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.spec.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {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();
- });
-});
diff --git a/gateway-admin-ui/admin-ui/app/gateway-version/gateway-version.component.css b/gateway-admin-ui/admin-ui/app/gateway-version/gateway-version.component.css
new file mode 100644
index 000000000..d13b8581c
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/gateway-version/gateway-version.component.css
@@ -0,0 +1,18 @@
+:host {
+ display: inline;
+}
+
+.version-item {
+ font-size: 12px;
+ color: #888;
+}
+
+.version-item strong {
+ color: #555;
+ margin-right: 3px;
+}
+
+.version-divider {
+ margin: 0 8px;
+ color: #ccc;
+}
diff --git a/gateway-admin-ui/admin-ui/app/gateway-version/gateway-version.component.html b/gateway-admin-ui/admin-ui/app/gateway-version/gateway-version.component.html
new file mode 100644
index 000000000..a25005fc0
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/gateway-version/gateway-version.component.html
@@ -0,0 +1,5 @@
+@if (gatewayVersion) {
+ <span class="version-item"><strong>Version</strong> {{gatewayVersion.version}}</span>
+ <span class="version-divider">|</span>
+ <span class="version-item"><strong>Hash</strong> {{gatewayVersion.hash}}</span>
+}
diff --git a/gateway-admin-ui/admin-ui/app/gateway-version.component.ts b/gateway-admin-ui/admin-ui/app/gateway-version/gateway-version.component.ts
similarity index 76%
rename from gateway-admin-ui/admin-ui/app/gateway-version.component.ts
rename to gateway-admin-ui/admin-ui/app/gateway-version/gateway-version.component.ts
index 602e889e6..ca8bb0afe 100644
--- a/gateway-admin-ui/admin-ui/app/gateway-version.component.ts
+++ b/gateway-admin-ui/admin-ui/app/gateway-version/gateway-version.component.ts
@@ -15,17 +15,14 @@
* limitations under the License.
*/
import {Component, OnInit} from '@angular/core';
-import {GatewayVersion} from './gateway-version';
-import {GatewayVersionService} from './gateway-version.service';
+import {GatewayVersion} from '../model/gateway-version';
+import {GatewayVersionService} from '../service/gateway-version.service';
+
@Component({
selector: 'app-gateway-version',
- template: `
- <div *ngIf="gatewayVersion">
- <span class="small"><cite>Version</cite> {{this.gatewayVersion.version}}</span>
- <span class="small"><cite>Hash</cite> {{this.gatewayVersion.hash}}</span>
- </div>`,
- providers: [GatewayVersionService]
+ templateUrl: './gateway-version.component.html',
+ styleUrls: ['./gateway-version.component.css']
})
export class GatewayVersionComponent implements OnInit {
@@ -42,4 +39,3 @@ export class GatewayVersionComponent implements OnInit {
this.getVersion();
}
}
-
diff --git a/gateway-admin-ui/admin-ui/app/index.ts b/gateway-admin-ui/admin-ui/app/index.ts
deleted file mode 100644
index d7b550ca9..000000000
--- a/gateway-admin-ui/admin-ui/app/index.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-export * from './app.component';
-export * from './app.module';
diff --git a/gateway-admin-ui/admin-ui/app/main.ts b/gateway-admin-ui/admin-ui/app/main.ts
deleted file mode 100644
index 03ea8874f..000000000
--- a/gateway-admin-ui/admin-ui/app/main.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
-
-import {AppModule} from './app.module';
-
-platformBrowserDynamic().bootstrapModule(AppModule);
diff --git a/gateway-admin-ui/admin-ui/app/resource-detail/descriptor.ts b/gateway-admin-ui/admin-ui/app/model/descriptor.ts
similarity index 98%
rename from gateway-admin-ui/admin-ui/app/resource-detail/descriptor.ts
rename to gateway-admin-ui/admin-ui/app/model/descriptor.ts
index 85d90ae02..e9ee90cad 100644
--- a/gateway-admin-ui/admin-ui/app/resource-detail/descriptor.ts
+++ b/gateway-admin-ui/admin-ui/app/model/descriptor.ts
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {Service} from '../resource/service';
+import {Service} from './service';
export class Descriptor {
discoveryType: string;
diff --git a/gateway-admin-ui/admin-ui/app/gateway-version.ts b/gateway-admin-ui/admin-ui/app/model/gateway-version.ts
similarity index 100%
rename from gateway-admin-ui/admin-ui/app/gateway-version.ts
rename to gateway-admin-ui/admin-ui/app/model/gateway-version.ts
diff --git a/gateway-admin-ui/admin-ui/app/resource-detail/provider-config.ts b/gateway-admin-ui/admin-ui/app/model/provider-config.ts
similarity index 100%
rename from gateway-admin-ui/admin-ui/app/resource-detail/provider-config.ts
rename to gateway-admin-ui/admin-ui/app/model/provider-config.ts
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.ts b/gateway-admin-ui/admin-ui/app/model/resource.ts
similarity index 95%
rename from gateway-admin-ui/admin-ui/app/resource/resource.ts
rename to gateway-admin-ui/admin-ui/app/model/resource.ts
index 1cdc2e8ba..b8774ce19 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.ts
+++ b/gateway-admin-ui/admin-ui/app/model/resource.ts
@@ -18,8 +18,6 @@
export class Resource {
timestamp: number;
name: string;
- uri: string;
href: string;
- content: string;
service: string;
}
diff --git a/gateway-admin-ui/admin-ui/app/resource/service.ts b/gateway-admin-ui/admin-ui/app/model/service.ts
similarity index 100%
rename from gateway-admin-ui/admin-ui/app/resource/service.ts
rename to gateway-admin-ui/admin-ui/app/model/service.ts
diff --git a/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.ts b/gateway-admin-ui/admin-ui/app/model/servicedefinition.ts
similarity index 89%
rename from gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.ts
rename to gateway-admin-ui/admin-ui/app/model/servicedefinition.ts
index 8a71e6a49..456914855 100644
--- a/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.ts
+++ b/gateway-admin-ui/admin-ui/app/model/servicedefinition.ts
@@ -14,11 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {RewriteRules} from './rewrite.rules';
-import {Service} from './service';
-
export class ServiceDefinition {
- name: string;
service: string;
role: string;
version: string;
diff --git a/gateway-admin-ui/admin-ui/app/sessionInformation/session.information.ts b/gateway-admin-ui/admin-ui/app/model/session-information.ts
similarity index 91%
rename from gateway-admin-ui/admin-ui/app/sessionInformation/session.information.ts
rename to gateway-admin-ui/admin-ui/app/model/session-information.ts
index 8bdefe3d7..98a8dbcfb 100644
--- a/gateway-admin-ui/admin-ui/app/sessionInformation/session.information.ts
+++ b/gateway-admin-ui/admin-ui/app/model/session-information.ts
@@ -17,8 +17,5 @@
export class SessionInformation {
user: string;
- logoutUrl: string;
- logoutPageUrl: string;
- globalLgoutPageUrl: string;
bannerText: string;
}
diff --git a/gateway-admin-ui/admin-ui/app/topology.ts b/gateway-admin-ui/admin-ui/app/model/topology.ts
similarity index 100%
rename from gateway-admin-ui/admin-ui/app/topology.ts
rename to gateway-admin-ui/admin-ui/app/model/topology.ts
diff --git a/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.css b/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.css
index 0cc494ab8..1bd97a818 100644
--- a/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.css
+++ b/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.css
@@ -2,4 +2,27 @@ td {
border-collapse: collapse;
padding: 8px;
vertical-align: top;
+}
+
+.services-table {
+ table-layout: fixed;
+ width: 100%;
+}
+
+.service-checkbox {
+ display: flex;
+ align-items: baseline;
+ gap: 6px;
+ margin: 4px 0;
+ cursor: pointer;
+ font-weight: normal;
+}
+
+.service-checkbox input[type="checkbox"] {
+ flex-shrink: 0;
+}
+
+.service-checkbox span {
+ overflow: hidden;
+ text-overflow: ellipsis;
}
\ No newline at end of file
diff --git a/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.html b/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.html
index 1c9a9770a..4872dcf6e 100644
--- a/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.html
+++ b/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.html
@@ -1,149 +1,157 @@
-<bs-modal #newDescriptorModal xmlns="http://www.w3.org/1999/html">
- <bs-modal-header [showDismiss]="true">
+<app-modal #newDescriptorModal size="lg">
+ <div class="modal-header">
<label class="modal-title">Create a New Descriptor</label>
- </bs-modal-header>
- <bs-modal-body>
+ <button type="button" class="btn-close" (click)="newDescriptorModal.dismiss()"></button>
+ </div>
+ <div class="modal-body">
<div class="panel-body">
<div> <!-- Descriptor Name -->
<span>
- <strong>Name</strong> <input type="text" [(ngModel)]="descriptorName">
+ <strong>Name <span class="required-marker">*</span></strong> <input type="text" [(ngModel)]="descriptorName">
</span>
- <span *ngIf="isMissingDescriptorName()" style="color: red">required</span>
- <span *ngIf="!isMissingDescriptorName() && !isValidDescriptorName()"
- style="color: red">invalid</span>
- <span *ngIf="isExistingReadOnlyTopology()"
- style="color: red">Cannot overwrite existing read-only topology</span>
+ @if (!isMissingDescriptorName() && !isValidDescriptorName()) {
+ <span class="validation-error">Invalid name</span>
+ }
+ @if (isExistingReadOnlyTopology()) {
+ <span class="validation-error">Cannot overwrite existing read-only topology</span>
+ }
</div> <!-- Descriptor Name -->
<br>
<div> <!-- Provider Config reference -->
- <span class="col-md-sm pull-left"><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-editor inlineEditForm" *ngIf="editModePC">
- <input type="text" size="40" [(ngModel)]="descriptor.providerConfig">
- <button class="btn btn-xs" (click)="editModePC=false;descriptor.setDirty()">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs" (click)="editModePC=false">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
+ <span class="col-md-sm pull-left"><strong>Provider Configuration <span class="required-marker">*</span></strong> </span>
+ @if (!editModePC) {
+ <span class="col-md-sm inline-editable" (click)="editModePC=true">{{descriptor.providerConfig}}</span>
+ }
+ @if (editModePC) {
+ <span class="col-md-sm inline-editor inlineEditForm">
+ <input type="text" size="40" [(ngModel)]="descriptor.providerConfig">
+ <button class="btn btn-xs" (click)="editModePC=false;descriptor.setDirty()">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs" (click)="editModePC=false">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
- <button id="chooseProviderConfig"
- class="btn btn-xs"
- (click)="chooseProviderConfigModal.open(descriptor, 'sm')"
- [disabled]="editModePC"
- type="submit"
- data-toggle="tooltip"
- title="Choose Provider Configuration">
- <span class="glyphicon glyphicon-edit"></span>
- </button>
+ <span class="clickable inline-glyph btn btn-xs"
+ (click)="chooseProviderConfigModal.open(descriptor)"
+ [class.disabled]="editModePC"
+ data-toggle="tooltip"
+ title="Choose Provider Configuration">
+ <span class="material-icons">edit</span>
+ </span>
<app-provider-config-selector #choosePC></app-provider-config-selector>
- <span *ngIf="isMissingProviderConfig()" style="color: red">required</span>
- <span *ngIf="!isMissingProviderConfig() && !isValidProviderConfig()"
- style="color: red">invalid</span>
+ @if (!isMissingProviderConfig() && !isValidProviderConfig()) {
+ <span class="validation-error">Invalid provider configuration</span>
+ }
</div> <!-- Provider Config reference -->
<br>
<!-- Services -->
<div>
- <span [class]="'clickable inline-glyph glyhpicon glyphicon-' + (this['showServices'] ? 'minus' : 'plus')"
- (click)="toggleBoolean('showServices')"></span>
+ <span class="clickable inline-glyph material-icons"
+ (click)="toggleBoolean('showServices')">{{this['showServices'] ? 'expand_more' : 'chevron_right'}}</span>
<span (click)="toggleBoolean('showServices')"><strong>Services</strong></span>
</div>
- <div class="panel panel-default col-md-12" *ngIf="this['showServices']">
- <table>
- <tr>
- <td *ngFor="let col of getServiceDisplayColumns()">
- <div *ngFor="let supportedService of col">
- <input type="checkbox"
- [checked]="isSelected(supportedService)"
- (click)="toggleServiceSelected(supportedService)">
- {{ supportedService }}
- </div>
- </td>
- </tr>
- </table>
- </div> <!-- Services -->
+ @if (this['showServices']) {
+ <div class="panel panel-default col-md-12">
+ <table class="services-table">
+ <tr>
+ @for (col of getServiceDisplayColumns(); track $index) {
+ <td>
+ @for (supportedService of col; track supportedService) {
+ <label class="service-checkbox">
+ <input type="checkbox"
+ [checked]="isSelected(supportedService)"
+ (click)="toggleServiceSelected(supportedService)">
+ <span>{{ supportedService }}</span>
+ </label>
+ }
+ </td>
+ }
+ </tr>
+ </table>
+ </div> <!-- Services -->
+ }
<br>
<!-- Discovery -->
<div>
- <span [class]="'clickable inline-glyph glyhpicon glyphicon-' + (this['showDiscovery'] ? 'minus' : 'plus')"
- (click)="toggleBoolean('showDiscovery')"></span>
+ <span class="clickable inline-glyph material-icons"
+ (click)="toggleBoolean('showDiscovery')">{{this['showDiscovery'] ? 'expand_more' : 'chevron_right'}}</span>
<span (click)="toggleBoolean('showDiscovery')"><strong>Discovery</strong></span>
</div>
- <div class="panel panel-default col-md-12" *ngIf="this['showDiscovery']">
- <div>
- <table>
- <tr>
- <td><strong>Type</strong></td>
- <td>
- <span>
- <select id="select" autofocus required class="md-select form-control"
- [(ngModel)]="descriptor.discoveryType" (change)="descriptor.setDirty()">
- <option *ngFor="let typeOption of resourceService.discoveryTypes"
- class="md-option"
- [value]="typeOption">{{typeOption}}</option>
- </select>
- </span>
- </td>
- </tr>
- <tr>
- <td><strong>Address</strong></td>
- <td>
- <span>
- <input type="text" [(ngModel)]="descriptor.discoveryAddress">
- </span>
- <span *ngIf="!isValidDiscoveryAddress()"
- style="color: red">invalid</span>
- </td>
- </tr>
- <tr>
- <td><strong>Cluster</strong></td>
- <td>
- <span>
- <input type="text" [(ngModel)]="descriptor.discoveryCluster">
- </span>
- </td>
- </tr>
- <tr>
- <td><strong>Username</strong></td>
- <td>
- <span>
- <input type="text" [(ngModel)]="descriptor.discoveryUser">
- </span>
- </td>
- </tr>
- <tr>
- <td><strong>Password Alias</strong></td>
- <td>
- <span>
- <input type="text" [(ngModel)]="descriptor.discoveryPassAlias">
- </span>
- </td>
- </tr>
- </table>
- </div>
- </div> <!-- Discovery -->
+ @if (this['showDiscovery']) {
+ <div class="panel panel-default col-md-12">
+ <div>
+ <table>
+ <tr>
+ <td><strong>Type</strong></td>
+ <td>
+ <span>
+ <select id="select" autofocus required class="md-select form-control"
+ [(ngModel)]="descriptor.discoveryType" (change)="descriptor.setDirty()">
+ @for (typeOption of resourceService.discoveryTypes; track typeOption) {
+ <option class="md-option" [value]="typeOption">{{typeOption}}</option>
+ }
+ </select>
+ </span>
+ </td>
+ </tr>
+ <tr>
+ <td><strong>Address</strong></td>
+ <td>
+ <span>
+ <input type="text" [(ngModel)]="descriptor.discoveryAddress">
+ </span>
+ @if (!isValidDiscoveryAddress()) {
+ <span class="validation-error">Invalid address</span>
+ }
+ </td>
+ </tr>
+ <tr>
+ <td><strong>Cluster</strong></td>
+ <td>
+ <span>
+ <input type="text" [(ngModel)]="descriptor.discoveryCluster">
+ </span>
+ </td>
+ </tr>
+ <tr>
+ <td><strong>Username</strong></td>
+ <td>
+ <span>
+ <input type="text" [(ngModel)]="descriptor.discoveryUser">
+ </span>
+ </td>
+ </tr>
+ <tr>
+ <td><strong>Password Alias</strong></td>
+ <td>
+ <span>
+ <input type="text" [(ngModel)]="descriptor.discoveryPassAlias">
+ </span>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div> <!-- Discovery -->
+ }
</div>
- </bs-modal-body>
- <bs-modal-footer>
- <button type="button"
- class="btn btn-default btn-sm"
- data-dismiss="newDescriptorModal"
- (click)="newDescriptorModal.dismiss()">Cancel
- </button>
- <button type="button"
- class="btn btn-primary btn-sm"
+ </div>
+ <div class="modal-footer">
+ <span class="pull-left required-footnote">Required field</span>
+ <button type="button" class="btn btn-default btn-sm"
+ (click)="newDescriptorModal.dismiss()">Cancel</button>
+ <button type="button" class="btn btn-primary btn-sm"
[disabled]="!validate()"
- (click)="save()">Ok
- </button>
- </bs-modal-footer>
-</bs-modal>
+ (click)="save()">Ok</button>
+ </div>
+</app-modal>
diff --git a/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.spec.ts b/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.spec.ts
deleted file mode 100644
index 5222c23a7..000000000
--- a/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.spec.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {async, ComponentFixture, TestBed} from '@angular/core/testing';
-
-import {NewDescWizardComponent} from './new-desc-wizard.component';
-
-describe('NewDescWizardComponent', () => {
- let component: NewDescWizardComponent;
- let fixture: ComponentFixture<NewDescWizardComponent>;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- declarations: [NewDescWizardComponent]
- })
- .compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(NewDescWizardComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.ts b/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.ts
index 4794b26a3..022122ea1 100644
--- a/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.ts
+++ b/gateway-admin-ui/admin-ui/app/new-desc-wizard/new-desc-wizard.component.ts
@@ -15,20 +15,22 @@
* limitations under the License.
*/
import {Component, OnInit, ViewChild} from '@angular/core';
-import {BsModalComponent} from 'ng2-bs3-modal';
+import {FormsModule} from '@angular/forms';
import {ProviderConfigSelectorComponent} from '../provider-config-selector/provider-config-selector.component';
-import {Descriptor} from '../resource-detail/descriptor';
-import {ResourceService} from '../resource/resource.service';
-import {Resource} from '../resource/resource';
-import {ResourceTypesService} from '../resourcetypes/resourcetypes.service';
+import {Descriptor} from '../model/descriptor';
+import {ResourceService} from '../service/resource.service';
+import {Resource} from '../model/resource';
+import {ResourceTypesService} from '../service/resourcetypes.service';
import {ValidationUtils} from '../utils/validation-utils';
-import {HttpErrorResponse} from '@angular/common/http';
+import {ModalComponent} from '../utils/modal.component';
+import { HttpErrorResponse } from '@angular/common/http';
@Component({
selector: 'app-new-desc-wizard',
templateUrl: './new-desc-wizard.component.html',
- styleUrls: ['./new-desc-wizard.component.css']
+ styleUrls: ['./new-desc-wizard.component.css'],
+ imports: [FormsModule, ProviderConfigSelectorComponent, ModalComponent]
})
export class NewDescWizardComponent implements OnInit {
@@ -80,7 +82,7 @@ export class NewDescWizardComponent implements OnInit {
'ZEPPELINWS'];
@ViewChild('newDescriptorModal')
- childModal: BsModalComponent;
+ childModal: ModalComponent;
@ViewChild('choosePC')
chooseProviderConfigModal: ProviderConfigSelectorComponent;
@@ -102,9 +104,9 @@ export class NewDescWizardComponent implements OnInit {
this.descriptor = new Descriptor();
}
- open(size?: string) {
+ open() {
this.reset();
- this.childModal.open(size ? size : 'lg');
+ this.childModal.open('lg');
}
reset() {
@@ -157,7 +159,7 @@ export class NewDescWizardComponent implements OnInit {
}
}
});
- this.childModal.close(); // close the dialog if there was no error
+ this.childModal.dismiss();
}).catch((err: HttpErrorResponse) => {
this.existingReadOnlyTopology = (err.status === 409);
console.error('Error creating ' + this.descriptorName + ' : ' + err.message);
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.html b/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.html
index 71dd9fea3..2179ac861 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.html
+++ b/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.html
@@ -1,28 +1,25 @@
-<bs-modal (onClose)="onClose()" #chooseProviderConfigModal>
- <bs-modal-header [showDismiss]="true">
+<app-modal (onClose)="onClose()" #chooseProviderConfigModal>
+ <div class="modal-header">
<label class="modal-title">Choose a Provider Configuration</label>
- </bs-modal-header>
- <bs-modal-body>
+ <button type="button" class="btn-close" (click)="chooseProviderConfigModal.dismiss()"></button>
+ </div>
+ <div class="modal-body">
<div class="form-group">
<select autofocus required class="md-select form-control" [(ngModel)]="selectedName"
id="select">
- <option *ngFor="let pc of getProviderConfigs()"
- class="md-option"
- [value]="getReferenceName(pc.name)"
- [selected]="getReferenceName(pc.name) === selectedName">{{getReferenceName(pc.name)}}</option>
+ @for (pc of getProviderConfigs(); track pc.name) {
+ <option class="md-option"
+ [value]="getReferenceName(pc.name)"
+ [selected]="getReferenceName(pc.name) === selectedName">{{getReferenceName(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"
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default btn-sm"
+ (click)="chooseProviderConfigModal.dismiss()">Cancel</button>
+ <button type="button" class="btn btn-primary btn-sm"
[disabled]="!selectedName"
- (click)="chooseProviderConfigModal.close()">Ok
- </button>
- </bs-modal-footer>
-</bs-modal>
+ (click)="chooseProviderConfigModal.close()">Ok</button>
+ </div>
+</app-modal>
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.spec.ts b/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.spec.ts
deleted file mode 100644
index 1ea1a4648..000000000
--- a/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.spec.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {async, ComponentFixture, TestBed} from '@angular/core/testing';
-
-import {ProviderConfigSelectorComponent} from './provider-config-selector.component';
-
-describe('ProviderConfigSelectorComponent', () => {
- let component: ProviderConfigSelectorComponent;
- let fixture: ComponentFixture<ProviderConfigSelectorComponent>;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- declarations: [ProviderConfigSelectorComponent]
- })
- .compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(ProviderConfigSelectorComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.ts b/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.ts
index ab5a3f016..67894f382 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-selector/provider-config-selector.component.ts
@@ -14,23 +14,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {Component, OnInit, ViewChild} from '@angular/core';
-import {ResourceService} from '../resource/resource.service';
-import {Resource} from '../resource/resource';
-import {BsModalComponent} from 'ng2-bs3-modal';
-import {Descriptor} from '../resource-detail/descriptor';
-import {HttpErrorResponse} from '@angular/common/http';
+import {Component, ViewChild} from '@angular/core';
+import {FormsModule} from '@angular/forms';
+import {ResourceService} from '../service/resource.service';
+import {Resource} from '../model/resource';
+import {Descriptor} from '../model/descriptor';
+import {ModalComponent} from '../utils/modal.component';
+import { HttpErrorResponse } from '@angular/common/http';
@Component({
selector: 'app-provider-config-selector',
templateUrl: './provider-config-selector.component.html',
- styleUrls: ['./provider-config-selector.component.css']
+ styleUrls: ['./provider-config-selector.component.css'],
+ imports: [FormsModule, ModalComponent]
})
export class ProviderConfigSelectorComponent {
@ViewChild('chooseProviderConfigModal')
- private childModal: BsModalComponent;
+ private childModal: ModalComponent;
private providerConfigs: Resource[];
@@ -42,16 +44,15 @@ export class ProviderConfigSelectorComponent {
constructor(private resourceService: ResourceService) {
}
- open(desc: Descriptor, size?: string) {
+ open(desc: Descriptor) {
this.descriptor = desc;
- this.selectedName = desc.providerConfig; // Set the default selection based on the current ref in the descriptor
+ this.selectedName = desc.providerConfig;
- // Load the available provider configs every time this modal is open
this.resourceService.getResources('Provider Configurations')
.then(result => this.providerConfigs = result)
.catch((err: HttpErrorResponse) => console.debug('Error access provider configurations: ' + err));
- this.childModal.open(size);
+ this.childModal.open('sm');
}
onClose() {
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/AnonymousProviderConfig.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/AnonymousProviderConfig.ts
index b34ec60e5..c0cc1a242 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/AnonymousProviderConfig.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/AnonymousProviderConfig.ts
@@ -30,7 +30,7 @@ export class AnonymousProviderConfig extends AuthenticationProviderConfig {
return this.displayBindingPropertyNames;
}
- getDisplayNamePropertyBinding(name: string): string {
+ getDisplayNamePropertyBinding(_name: string): string {
return null;
}
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/authentication-wizard.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/authentication-wizard.ts
index 3b1ee4da5..1ccf0f8d2 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/authentication-wizard.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/authentication-wizard.ts
@@ -82,8 +82,7 @@ export class AuthenticationWizard extends CategoryWizard {
onChange() {
let configType = AuthenticationWizard.typeConfigMap.get(this.selectedType);
if (configType) {
- this.providerConfig = Object.create(configType.prototype) as AuthenticationProviderConfig;
- this.providerConfig = this.providerConfig.constructor.apply(this.providerConfig);
+ this.providerConfig = new (configType as any)();
(this.providerConfig as AuthenticationProviderConfig).setType(this.selectedType);
} else {
console.debug('AuthenticationWizard --> No provider configuration type mapped for ' + this.selectedType);
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/authorization-wizard.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/authorization-wizard.ts
index 5d64810d3..845d4f888 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/authorization-wizard.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/authorization-wizard.ts
@@ -42,8 +42,7 @@ export class AuthorizationWizard extends CategoryWizard {
onChange() {
let configType = AuthorizationWizard.typeConfigMap.get(this.selectedType);
if (configType) {
- this.providerConfig = Object.create(configType.prototype) as DisplayBindingProviderConfig;
- this.providerConfig = this.providerConfig.constructor.apply(this.providerConfig);
+ this.providerConfig = new (configType as any)();
(this.providerConfig as DisplayBindingProviderConfig).setType(this.selectedType);
} else {
console.debug('AuthorizationWizard --> No provider configuration type mapped for ' + this.selectedType);
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/category-wizard.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/category-wizard.ts
index a28e15fef..17c514289 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/category-wizard.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/category-wizard.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import {ProviderConfig} from '../resource-detail/provider-config';
+import {ProviderConfig} from '../model/provider-config';
export abstract class CategoryWizard {
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/csrf-provider-config.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/csrf-provider-config.ts
index 10044e216..a3e56d29a 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/csrf-provider-config.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/csrf-provider-config.ts
@@ -57,12 +57,13 @@ export class CSRFProviderConfig extends WebAppSecurityContributor {
case CSRFProviderConfig.CUSTOM_HEADER:
isValid = ValidationUtils.isValidString(value);
break;
- case CSRFProviderConfig.METHODS_TO_IGNORE:
+ case CSRFProviderConfig.METHODS_TO_IGNORE: {
let methodList: string[] = value.split(',');
for (let method of methodList) {
isValid = isValid && ValidationUtils.isValidHTTPMethod(method.trim().toUpperCase());
}
break;
+ }
default:
}
}
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/display-binding-provider-config.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/display-binding-provider-config.ts
index 7d864cf27..4d89ae47f 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/display-binding-provider-config.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/display-binding-provider-config.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import {ProviderConfig} from '../resource-detail/provider-config';
+import {ProviderConfig} from '../model/provider-config';
export abstract class DisplayBindingProviderConfig extends ProviderConfig {
@@ -59,11 +59,11 @@ export abstract class DisplayBindingProviderConfig extends ProviderConfig {
return this.params[name];
}
- isPasswordParam(name: string): boolean {
+ isPasswordParam(_name: string): boolean {
return false;
}
- isValidParamValue(paramName: string) {
+ isValidParamValue(_paramName: string) {
return true;
}
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/ha-wizard.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/ha-wizard.ts
index 84f489b2f..7078cea8a 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/ha-wizard.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/ha-wizard.ts
@@ -16,7 +16,7 @@
*/
import {CategoryWizard} from './category-wizard';
-import {ProviderConfig} from '../resource-detail/provider-config';
+import {ProviderConfig} from '../model/provider-config';
import {ProviderContributorWizard} from './provider-contributor-wizard';
import {HaProviderConfig} from './ha-provider-config';
import {DisplayBindingProviderConfig} from './display-binding-provider-config';
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/hostmap-provider-wizard.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/hostmap-provider-wizard.ts
index 8fedb3e98..1ab1cee13 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/hostmap-provider-wizard.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/hostmap-provider-wizard.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
import {CategoryWizard} from './category-wizard';
-import {ProviderConfig} from '../resource-detail/provider-config';
+import {ProviderConfig} from '../model/provider-config';
export class HostMapProviderWizard extends CategoryWizard {
private stepCount = 2;
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/identity-assertion-wizard.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/identity-assertion-wizard.ts
index 126c8a955..8c9e4007f 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/identity-assertion-wizard.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/identity-assertion-wizard.ts
@@ -16,7 +16,7 @@
*/
import {CategoryWizard} from './category-wizard';
-import {ProviderConfig} from '../resource-detail/provider-config';
+import {ProviderConfig} from '../model/provider-config';
import {IdentityAssertionProviderConfig} from './identity-assertion-provider-config';
import {DefaultIdAssertionProviderConfig} from './default-idassertion-provider-config';
import {ConcatAssertionProviderConfig} from './concat-idassertion-provider-config';
@@ -59,8 +59,7 @@ export class IdentityAssertionWizard extends CategoryWizard {
onChange() {
let configType = IdentityAssertionWizard.typeConfigMap.get(this.selectedType);
if (configType) {
- this.providerConfig = Object.create(configType.prototype) as IdentityAssertionProviderConfig;
- this.providerConfig = this.providerConfig.constructor.apply(this.providerConfig);
+ this.providerConfig = new (configType as any)();
(this.providerConfig as IdentityAssertionProviderConfig).setType(this.selectedType);
} else {
console.debug('IdentityAssertionWizard --> No provider configuration type mapped for ' + this.selectedType);
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.html b/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.html
index 46cd5dc21..3c93852e0 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.html
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.html
@@ -1,133 +1,150 @@
-<bs-modal #newProviderConfigModal xmlns="http://www.w3.org/1999/html">
- <bs-modal-header [showDismiss]="true">
+<app-modal #newProviderConfigModal>
+ <div class="modal-header">
<label class="modal-title">Create a New Provider Configuration</label>
- </bs-modal-header>
- <bs-modal-body>
+ <button type="button" class="btn-close" (click)="newProviderConfigModal.dismiss()"></button>
+ </div>
+ <div class="modal-body">
- <div *ngIf="isRootStep()">
- <!-- Provider Configuration Name -->
+ @if (isRootStep()) {
<div>
- <table>
- <tr>
- <td><strong>Name</strong></td>
- <td><input type="textbox"
- name="name"
- #field="ngModel"
- [required]="true"
- size="60"
- [(ngModel)]="name">
- <span *ngIf="field.errors?.required" style="color: red">
- required
- </span>
- <span *ngIf="isExistingReadOnlyProvider()"
- style="color: red">Cannot overwrite existing read-only topology</span>
- <span *ngIf="!field.errors?.required && !isValidProviderConfigName()"
- style="color: red">
- invalid
- </span>
- </td>
- </tr>
- </table>
- </div> <!-- Provider Configuration Name -->
+ <!-- Provider Configuration Name -->
+ <div>
+ <table>
+ <tr>
+ <td><strong>Name <span class="required-marker">*</span></strong></td>
+ <td><input type="textbox"
+ name="name"
+ #field="ngModel"
+ [required]="true"
+ size="60"
+ [(ngModel)]="name">
+ @if (isExistingReadOnlyProvider()) {
+ <span class="validation-error">Cannot overwrite existing read-only topology</span>
+ }
+ @if (!field.errors?.required && !isValidProviderConfigName()) {
+ <span class="validation-error">Invalid name</span>
+ }
+ </td>
+ </tr>
+ </table>
+ </div> <!-- Provider Configuration Name -->
- <br/>
+ <br/>
- <!-- Display New Providers -->
- <div>
- <strong>Providers</strong><br/>
- <div *ngFor="let pDisplay of getConfiguredProviderDisplayNames()">
- {{ pDisplay }}
- </div>
- </div> <!-- Display New Providers -->
+ <!-- Display New Providers -->
+ <div>
+ <strong>Providers</strong><br/>
+ @for (pDisplay of getConfiguredProviderDisplayNames(); track pDisplay) {
+ <div>{{ pDisplay }}</div>
+ }
+ </div> <!-- Display New Providers -->
- <br/>
+ <br/>
- <!-- Root Step -->
- <div>
- <button type="button"
- class="btn btn-default btn-sm"
- data-dismiss="newProviderConfigModal"
- (click)="onNextStep()">Add Provider
- </button>
- </div> <!-- Root Step -->
- </div>
+ <!-- Root Step -->
+ <div>
+ <button type="button"
+ class="btn btn-default btn-sm"
+ (click)="onNextStep()">Add Provider
+ </button>
+ </div> <!-- Root Step -->
+ </div>
+ }
<!-- Provider Category Selection Step -->
- <div *ngIf="isProviderCategoryStep()">
- <strong>Choose a Provider Category</strong><br/><br/>
- <div *ngFor="let pc of getProviderCategories()">
- <label>
- <input type="radio"
- [name]="pc"
- [(ngModel)]="selectedCategory"
- [value]="pc"> {{pc}}
- </label>
- </div>
- </div> <!-- Provider Category Selection Step -->
+ @if (isProviderCategoryStep()) {
+ <div>
+ <strong>Choose a Provider Category</strong><br/><br/>
+ @for (pc of getProviderCategories(); track pc) {
+ <div>
+ <label>
+ <input type="radio"
+ [name]="pc"
+ [(ngModel)]="selectedCategory"
+ [value]="pc"> {{pc}}
+ </label>
+ </div>
+ }
+ </div> <!-- Provider Category Selection Step -->
+ }
<!-- Provider Type Selection Step -->
- <div *ngIf="isProviderTypeStep()">
- <strong>Choose a {{ selectedCategory }} Provider Type</strong><br/><br/>
- <div *ngFor="let pt of getProviderTypes()">
- <label>
- <input type="radio"
- [name]="pt"
- (change)="getCategoryWizard().onChange()"
- [(ngModel)]="getCategoryWizard().selectedType"
- [value]="pt"> {{pt}}
- </label>
- </div>
- </div> <!-- Provider Type Selection Step -->
+ @if (isProviderTypeStep()) {
+ <div>
+ <strong>Choose a {{ selectedCategory }} Provider Type</strong><br/><br/>
+ @for (pt of getProviderTypes(); track pt) {
+ <div>
+ <label>
+ <input type="radio"
+ [name]="pt"
+ (change)="getCategoryWizard().onChange()"
+ [(ngModel)]="getCategoryWizard().selectedType"
+ [value]="pt"> {{pt}}
+ </label>
+ </div>
+ }
+ </div> <!-- Provider Type Selection Step -->
+ }
<!-- Provider Type Params Step -->
- <div *ngIf="isProviderParamsStep()">
- <strong>Specify {{ getCategoryWizard().getSelectedType() }} Provider Parameters</strong><br/><br/>
- <table>
- <tr *ngFor="let pt of getProviderParams()">
- <td><strong>{{pt}}</strong></td>
- <td>
- <span>
- <input [type]="!isPasswordParam(pt) || this['show'+pt] ? 'textbox' : 'password'"
- size="60"
- #paramInput
- (change)="setProviderParamBinding(pt, paramInput.value)"
- [value]="getProviderParamBinding(pt)">
- </span>
- <span *ngIf="isPasswordParam(pt)">
- <input type="checkbox"
- class="clickable"
- [checked]="getPasswordDisplay(pt)"
- (click)="togglePasswordDisplay(pt)">show
- </span>
- <span *ngIf="!isValidParamValue(pt)" style="color: red">invalid</span>
- </td>
- </tr>
- </table>
- </div> <!-- Provider Type Params Step -->
-
+ @if (isProviderParamsStep()) {
+ <div>
+ <strong>Specify {{ getCategoryWizard().getSelectedType() }} Provider Parameters</strong><br/><br/>
+ <table>
+ @for (pt of getProviderParams(); track pt) {
+ <tr>
+ <td><strong>{{pt}}</strong></td>
+ <td>
+ <span>
+ <input [type]="!isPasswordParam(pt) || this['show'+pt] ? 'textbox' : 'password'"
+ size="60"
+ #paramInput
+ (change)="setProviderParamBinding(pt, paramInput.value)"
+ [value]="getProviderParamBinding(pt)">
+ </span>
+ @if (isPasswordParam(pt)) {
+ <span>
+ <input type="checkbox"
+ class="clickable"
+ [checked]="getPasswordDisplay(pt)"
+ (click)="togglePasswordDisplay(pt)">show
+ </span>
+ }
+ @if (!isValidParamValue(pt)) {
+ <span class="validation-error">Invalid value</span>
+ }
+ </td>
+ </tr>
+ }
+ </table>
+ </div> <!-- Provider Type Params Step -->
+ }
- </bs-modal-body>
- <bs-modal-footer>
+ </div>
+ <div class="modal-footer">
+ <span class="pull-left required-footnote">Required field</span>
<button type="button"
- class="btn btn-default btn-sm pull-left"
- data-dismiss="newProviderConfigModal"
+ class="btn btn-default btn-sm"
(click)="newProviderConfigModal.dismiss()">Cancel
</button>
- <button type="button"
- *ngIf="!isRootStep()"
- class="btn btn-primary btn-sm"
- (click)="onPreviousStep()">Back
- </button>
- <button type="button"
- *ngIf="isRootStep() || !hasMoreSteps()"
- class="btn btn-primary btn-sm"
- [disabled]="(isRootStep() && !name)"
- (click)="isRootStep() ? save() : onFinishAdd()">Ok
- </button>
- <button type="button"
- *ngIf="!isRootStep() && hasMoreSteps()"
- class="btn btn-primary btn-sm"
- (click)="onNextStep()">Next
- </button>
- </bs-modal-footer>
-</bs-modal>
+ @if (!isRootStep()) {
+ <button type="button"
+ class="btn btn-primary btn-sm"
+ (click)="onPreviousStep()">Back
+ </button>
+ }
+ @if (isRootStep() || !hasMoreSteps()) {
+ <button type="button"
+ class="btn btn-primary btn-sm"
+ [disabled]="(isRootStep() && !name)"
+ (click)="isRootStep() ? save() : onFinishAdd()">Ok
+ </button>
+ }
+ @if (!isRootStep() && hasMoreSteps()) {
+ <button type="button"
+ class="btn btn-primary btn-sm"
+ (click)="onNextStep()">Next
+ </button>
+ }
+ </div>
+</app-modal>
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.spec.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.spec.ts
deleted file mode 100644
index 2897ef0f6..000000000
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.spec.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {async, ComponentFixture, TestBed} from '@angular/core/testing';
-
-import {ProviderConfigWizardComponent} from './provider-config-wizard.component';
-
-describe('ProviderConfigWizardComponent', () => {
- let component: ProviderConfigWizardComponent;
- let fixture: ComponentFixture<ProviderConfigWizardComponent>;
-
- beforeEach(async(() => {
- TestBed.configureTestingModule({
- declarations: [ProviderConfigWizardComponent]
- })
- .compileComponents();
- }));
-
- beforeEach(() => {
- fixture = TestBed.createComponent(ProviderConfigWizardComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
-
- it('should create', () => {
- expect(component).toBeTruthy();
- });
-});
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.ts
index a4b03a7e8..4ed21c631 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-config-wizard.component.ts
@@ -16,28 +16,30 @@
*/
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 {FormsModule} from '@angular/forms';
+import {ResourceTypesService} from '../service/resourcetypes.service';
+import {ResourceService} from '../service/resource.service';
+import {ProviderConfig} from '../model/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 {Resource} from '../model/resource';
import {DisplayBindingProviderConfig} from './display-binding-provider-config';
import {OrderedParamContainer} from './ordered-param-container';
import {HostMapProviderWizard} from './hostmap-provider-wizard';
import {ProviderContributorWizard} from './provider-contributor-wizard';
import {WebAppSecurityWizard} from './webappsec-wizard';
import {ValidationUtils} from '../utils/validation-utils';
-import {HttpErrorResponse} from '@angular/common/http';
+import {ModalComponent} from '../utils/modal.component';
+import { HttpErrorResponse } from '@angular/common/http';
@Component({
selector: 'app-provider-config-wizard',
templateUrl: './provider-config-wizard.component.html',
- styleUrls: ['./provider-config-wizard.component.css']
+ styleUrls: ['./provider-config-wizard.component.css'],
+ imports: [FormsModule, ModalComponent]
})
export class ProviderConfigWizardComponent implements OnInit {
private static CATEGORY_STEP = 1;
@@ -70,7 +72,7 @@ export class ProviderConfigWizardComponent implements OnInit {
]);
@ViewChild('newProviderConfigModal')
- childModal: BsModalComponent;
+ childModal: ModalComponent;
private step = 0;
@@ -105,9 +107,9 @@ export class ProviderConfigWizardComponent implements OnInit {
this.selectedCategory = ProviderConfigWizardComponent.CATEGORY_AUTHENTICATION; // Default to authentication
}
- open(size?: string) {
+ open() {
this.reset();
- this.childModal.open(size ? size : 'lg');
+ this.childModal.open('lg');
}
reset() {
@@ -226,7 +228,7 @@ export class ProviderConfigWizardComponent implements OnInit {
}
}
});
- this.childModal.close(); // close the dialog if there was no error
+ this.childModal.dismiss();
}).catch((err: HttpErrorResponse) => {
this.existingReadOnlyProvider = (err.status === 409);
console.error('Error creating ' + newResource + ' : ' + err.message);
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-contributor-wizard.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-contributor-wizard.ts
index 59062bd8b..ae32cbda7 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-contributor-wizard.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/provider-contributor-wizard.ts
@@ -16,7 +16,7 @@
*/
-import {ProviderConfig} from '../resource-detail/provider-config';
+import {ProviderConfig} from '../model/provider-config';
export interface ProviderContributorWizard {
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/webappsec-provider-config.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/webappsec-provider-config.ts
index 1825034d4..cb78133d4 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/webappsec-provider-config.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/webappsec-provider-config.ts
@@ -33,7 +33,7 @@ export class WebAppSecurityProviderConfig extends DisplayBindingProviderConfig {
return [];
}
- getDisplayNamePropertyBinding(name: string): string {
+ getDisplayNamePropertyBinding(_name: string): string {
return null;
}
}
diff --git a/gateway-admin-ui/admin-ui/app/provider-config-wizard/webappsec-wizard.ts b/gateway-admin-ui/admin-ui/app/provider-config-wizard/webappsec-wizard.ts
index 1f097ce57..f712ec665 100644
--- a/gateway-admin-ui/admin-ui/app/provider-config-wizard/webappsec-wizard.ts
+++ b/gateway-admin-ui/admin-ui/app/provider-config-wizard/webappsec-wizard.ts
@@ -16,7 +16,7 @@
*/
import {CategoryWizard} from './category-wizard';
-import {ProviderConfig} from '../resource-detail/provider-config';
+import {ProviderConfig} from '../model/provider-config';
import {ProviderContributorWizard} from './provider-contributor-wizard';
import {DisplayBindingProviderConfig} from './display-binding-provider-config';
import {WebAppSecurityProviderConfig} from './webappsec-provider-config';
@@ -68,8 +68,7 @@ export class WebAppSecurityWizard extends CategoryWizard implements ProviderCont
onChange() {
let configType = WebAppSecurityWizard.typeConfigMap.get(this.selectedType);
if (configType) {
- this.providerConfig = Object.create(configType.prototype) as WebAppSecurityContributor;
- this.providerConfig = this.providerConfig.constructor.apply(this.providerConfig);
+ this.providerConfig = new (configType as any)();
(this.providerConfig as WebAppSecurityContributor).setType(this.selectedType);
} else {
console.debug('WebAppSecurityWizard --> No provider configuration type mapped for ' + this.selectedType);
diff --git a/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.css b/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.css
index c1343e95c..c9380855f 100644
--- a/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.css
+++ b/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.css
@@ -16,10 +16,12 @@
}
.inline-editable:hover:after {
- font-family: 'Glyphicons Halflings';
- content: "\270f";
+ font-family: 'Material Icons';
+ content: "\e254";
+ font-size: 14px;
position: relative;
- left: 10px;
+ left: 6px;
+ color: #4caf50;
}
.inline-editable.editable-empty,
@@ -42,7 +44,6 @@
.inline-editor.select {
width: auto;
display: inline;
- border-radius: 5px;
}
.inline-editor.inline-editor-button-group {
@@ -63,5 +64,8 @@
}
.inline-glyph {
- vertical-align: 2%;
+ display: inline-block;
+ vertical-align: middle;
+ line-height: 1;
}
+
diff --git a/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.html b/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.html
index 9b1455e3c..35cf22c0d 100644
--- a/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.html
+++ b/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.html
@@ -1,363 +1,418 @@
-<div *ngIf="resourceType && resourceType !== 'Topologies' && resourceType !== 'Service Definitions'" class="panel panel-default">
+@if (resourceType && resourceType !== 'Topologies' && resourceType !== 'Service Definitions') {
+<div class="panel panel-default" style="margin-top: 10px;">
<div class="panel-heading">
<h4 class="panel-title">
{{ getTitleSubject() }} Detail
- <span *ngIf="showEditOptions() === false" style="padding-left: 15%;" class="text-danger text-center"> Read Only (generated file) </span>
- <span *ngIf="hasSelectedResource()" class="pull-right">{{resourceService.getResourceDisplayName(resource)}}</span>
+ @if (showEditOptions() === false) {
+ <span style="padding-left: 15%;" class="text-danger text-center"> Read Only (generated file) </span>
+ }
+ @if (hasSelectedResource()) {
+ <span class="pull-right">{{resourceService.getResourceDisplayName(resource)}}</span>
+ }
</h4>
</div>
<!-- Provider Configuration Details -->
- <div class="panel-body"
- *ngIf="hasSelectedResource() && resourceType === 'Provider Configurations'">
- <div *ngIf="referencedProviderConfigError" class="alert alert-warning alert-dismissible"
- role="alert">
- <button type="button" class="close" data-dismiss="alert" aria-label="Close"
- (click)="referencedProviderConfigError=false">
- <span aria-hidden="true">×</span>
- </button>
- Cannot remove <strong>{{resourceService.getResourceDisplayName(resource)}}</strong>
- because it is referenced by one or more descriptors
- </div>
+ @if (hasSelectedResource() && resourceType === 'Provider Configurations') {
+ <div class="panel-body">
+ @if (referencedProviderConfigError) {
+ <div class="alert alert-warning alert-dismissible" role="alert">
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close"
+ (click)="referencedProviderConfigError=false">
+ <span aria-hidden="true">×</span>
+ </button>
+ Cannot remove <strong>{{resourceService.getResourceDisplayName(resource)}}</strong>
+ because it is referenced by one or more descriptors
+ </div>
+ }
<div style="padding-bottom: 10px">
<span><strong>Providers</strong></span>
- <span *ngIf="!isAddingProvider"
- class="clickable inline-glyph glyphicon glyphicon-plus-sign btn btn-xs pull-right"
- (click)="isAddingProvider=true"
- data-toggle="tooltip" title="Add Provider"></span>
- <span *ngIf="isAddingProvider" class="inline-editor inlineEditForm pull-right">
- <input type="text" value="name" onClick="this.setSelectionRange(0, this.value.length)"
- #newProviderName>
- <input type="text" value="role" onClick="this.setSelectionRange(0, this.value.length)"
- #newProviderRole>
- <button class="btn btn-xs"
- (click)="isAddingProvider=false;
- addProvider(newProviderName.value, newProviderRole.value)">
- <span class="glyphicon glyphicon-ok "></span>
- </button>
- <button class="btn btn-xs" (click)="isAddingProvider=false">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
- </div>
- <div class="panel panel-default" *ngFor="let provider of providers">
- <div class="panel-heading">
- <span> </span>
- <span [class]="'clickable inline-glyph glyhpicon glyphicon-' + (isShowProvider(provider) ? 'minus' : 'plus')"
- (click)="toggleShowProvider(provider)"></span>
- <span><strong>{{ provider.role }}</strong></span>
- <span class="clickable inline-glyph glyphicon glyphicon-remove pull-right btn btn-xs"
- [title]="'Remove ' + provider.role"
- (click)="onRemoveProvider(provider.name)"
- data-toggle="tooltip"></span>
- </div>
- <div class="panel-body" *ngIf="isShowProvider(provider)">
- <strong>Name</strong> {{ provider.name }}<br>
- <strong>Enabled</strong> <input type="checkbox"
- [checked]="isProviderEnabled(provider)"
- (click)="onProviderEnabled(provider)"><br>
- <div>
- <span [class]="'clickable inline-glyph glyhpicon glyphicon-' + (isShowProviderParams(provider) ? 'minus' : 'plus')"
- (click)="toggleShowProviderParams(provider)"></span>
- <span><strong>Params</strong></span>
- <span *ngIf="!isAddingProviderParam(provider)"
- class="clickable inline-glyph glyphicon glyphicon-plus-sign btn btn-xs"
- (click)="setAddingProviderParam(provider,true)"
- data-toggle="tooltip" title="Add Param"></span>
- <span *ngIf="isAddingProviderParam(provider)"
- class="inline-editor inlineEditForm">
- <input type="text" value="name" onClick="this.setSelectionRange(0, this.value.length)"
- #newParamName>
- <input type="text" value="value" onClick="this.setSelectionRange(0, this.value.length)"
- #newParamValue>
- <button class="btn btn-xs"
- (click)="setAddingProviderParam(provider,false);
- addProviderParam(provider, newParamName.value, newParamValue.value);
- showProviderParams(provider)">
- <span class="glyphicon glyphicon-ok "></span>
- </button>
- <button class="btn btn-xs" (click)="setAddingProviderParam(provider,false)">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
- <div class="panel panel-default table-responsive"
- *ngIf="isShowProviderParams(provider)">
- <table class="table table-sm">
- <tr *ngFor="let paramName of getProviderParamNames(provider)">
- <td>
- <span class="clickable inline-glyph glyphicon glyphicon-remove btn btn-xs"
- title="Remove Param"
- (click)="onRemoveProviderParam(provider, paramName)"
- data-toggle="tooltip"></span>
- </td>
- <td><strong>{{ paramName }}</strong></td>
- <td>
- <span class="inline-editable"
- (click)="setProviderParamEditFlag(provider, paramName, true)"
- *ngIf="!getProviderParamEditFlag(provider, paramName)">{{provider.params[paramName]}}</span>
- <span *ngIf="getProviderParamEditFlag(provider, paramName)"
- class="inline-editor inlineEditForm">
- <input type="text" size="30" [(ngModel)]="provider.params[paramName]">
+ @if (!isAddingProvider) {
+ <span class="clickable inline-glyph btn btn-xs pull-right"
+ (click)="isAddingProvider=true"
+ data-toggle="tooltip" title="Add Provider"><span class="material-icons">add_circle</span></span>
+ }
+ @if (isAddingProvider) {
+ <span class="inline-editor inlineEditForm pull-right">
+ <input type="text" value="name" onClick="this.setSelectionRange(0, this.value.length)"
+ #newProviderName>
+ <input type="text" value="role" onClick="this.setSelectionRange(0, this.value.length)"
+ #newProviderRole>
<button class="btn btn-xs"
- (click)="setProviderParamEditFlag(provider, paramName, false);changedProviders=providers">
- <span class="glyphicon glyphicon-ok"></span>
+ (click)="isAddingProvider=false;
+ addProvider(newProviderName.value, newProviderRole.value)">
+ <span class="material-icons">check</span>
</button>
- <button class="btn btn-xs"
- (click)="setProviderParamEditFlag(provider, paramName, false)">
- <span class="glyphicon glyphicon-remove"></span>
+ <button class="btn btn-xs" (click)="isAddingProvider=false">
+ <span class="material-icons">close</span>
</button>
- </span>
- </td>
- </tr>
- </table>
- </div> <!-- Provider params -->
+ </span>
+ }
+ </div>
+ @for (provider of providers; track provider.name) {
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <span> </span>
+ <span class="clickable inline-glyph material-icons"
+ (click)="toggleShowProvider(provider)">{{isShowProvider(provider) ? 'expand_more' : 'chevron_right'}}</span>
+ <span><strong>{{ provider.role }}</strong></span>
+ <span class="clickable inline-glyph pull-right btn btn-xs"
+ [title]="'Remove ' + provider.role"
+ (click)="onRemoveProvider(provider.name)"
+ data-toggle="tooltip"><span class="material-icons">cancel</span></span>
</div>
- </div> <!-- Provider Details -->
- </div> <!-- Provider panel -->
+ @if (isShowProvider(provider)) {
+ <div class="panel-body">
+ <strong>Name</strong> {{ provider.name }}<br>
+ <strong>Enabled</strong> <input type="checkbox"
+ [checked]="isProviderEnabled(provider)"
+ (click)="onProviderEnabled(provider)"><br>
+ <div>
+ <span class="clickable inline-glyph material-icons"
+ (click)="toggleShowProviderParams(provider)">{{isShowProviderParams(provider) ? 'expand_more' : 'chevron_right'}}</span>
+ <span><strong>Params</strong></span>
+ @if (!isAddingProviderParam(provider)) {
+ <span class="clickable inline-glyph btn btn-xs"
+ (click)="setAddingProviderParam(provider,true)"
+ data-toggle="tooltip" title="Add Param"><span class="material-icons">add_circle</span></span>
+ }
+ @if (isAddingProviderParam(provider)) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" value="name" onClick="this.setSelectionRange(0, this.value.length)"
+ #newParamName>
+ <input type="text" value="value" onClick="this.setSelectionRange(0, this.value.length)"
+ #newParamValue>
+ <button class="btn btn-xs"
+ (click)="setAddingProviderParam(provider,false);
+ addProviderParam(provider, newParamName.value, newParamValue.value);
+ showProviderParams(provider)">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs" (click)="setAddingProviderParam(provider,false)">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
+ @if (isShowProviderParams(provider)) {
+ <div class="panel panel-default table-responsive">
+ <table class="table table-sm">
+ @for (paramName of getProviderParamNames(provider); track paramName) {
+ <tr>
+ <td>
+ <span class="clickable inline-glyph btn btn-xs"
+ title="Remove Param"
+ (click)="onRemoveProviderParam(provider, paramName)"
+ data-toggle="tooltip"><span class="material-icons">cancel</span></span>
+ </td>
+ <td><strong>{{ paramName }}</strong></td>
+ <td>
+ @if (!getProviderParamEditFlag(provider, paramName)) {
+ <span class="inline-editable"
+ (click)="setProviderParamEditFlag(provider, paramName, true)">{{provider.params[paramName]}}</span>
+ }
+ @if (getProviderParamEditFlag(provider, paramName)) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" size="30" [(ngModel)]="provider.params[paramName]">
+ <button class="btn btn-xs"
+ (click)="setProviderParamEditFlag(provider, paramName, false);changedProviders=providers">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs"
+ (click)="setProviderParamEditFlag(provider, paramName, false)">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
+ </td>
+ </tr>
+ }
+ </table>
+ </div> <!-- Provider params -->
+ }
+ </div>
+ </div> <!-- Provider Details -->
+ }
+ </div> <!-- Provider panel -->
+ }
- <div> <!-- Provider Configuration Modification Buttons -->
- <button type="button"
- title="Remove Provider Configuration"
- class="btn btn-default btn-sm pull-left"
- (click)="deleteConfirmModal.open('md')"
- *ngIf="showEditOptions()"
- data-toggle="tooltip">
- <span class="glyphicon glyphicon-trash"></span>
- </button>
- <span class="pull-right">
- <button type="button"
- title="Discard Changes"
- class="btn btn-default btn-sm"
- [disabled]="!changedProviders"
- (click)="discardConfirmModal.open('md')"
- *ngIf="showEditOptions()"
- data-toggle="tooltip">
- <span class="glyphicon glyphicon-refresh"></span>
- </button>
- <span> </span>
- <button type="button"
- title="Update Provider Configuration"
- class="btn btn-default btn-sm"
- [disabled]="!changedProviders"
- (click)="persistChanges()"
- *ngIf="showEditOptions()"
- data-toggle="tooltip">
- <span class="glyphicon glyphicon-floppy-disk"></span>
- </button>
- </span>
+ <div style="overflow: hidden; padding-top: 10px;"> <!-- Provider Configuration Modification Buttons -->
+ @if (showEditOptions()) {
+ <button type="button"
+ title="Remove Provider Configuration"
+ class="btn btn-default btn-sm pull-left"
+ (click)="deleteConfirmModal.open('md')"
+ data-toggle="tooltip">
+ <span class="material-icons">delete</span>
+ </button>
+ <span class="pull-right">
+ <button type="button"
+ title="Discard Changes"
+ class="btn btn-default btn-sm"
+ [disabled]="!changedProviders"
+ (click)="discardConfirmModal.open('md')"
+ data-toggle="tooltip">
+ <span class="material-icons">refresh</span>
+ </button>
+ <span> </span>
+ <button type="button"
+ title="Update Provider Configuration"
+ class="btn btn-default btn-sm"
+ [disabled]="!changedProviders"
+ (click)="persistChanges()"
+ data-toggle="tooltip">
+ <span class="material-icons">save</span>
+ </button>
+ </span>
+ }
</div>
</div> <!-- Provider Configuration Details -->
+ }
<!-- Descriptor Details -->
- <div class="panel-body" *ngIf="hasSelectedResource() && resourceType === 'Descriptors'">
+ @if (hasSelectedResource() && resourceType === 'Descriptors') {
+ <div class="panel-body">
<div> <!-- Provider Config reference -->
<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-editor inlineEditForm" *ngIf="editModePC">
- <input type="text" size="40" [(ngModel)]="descriptor.providerConfig">
- <button class="btn btn-xs" (click)="editModePC=false;descriptor.setDirty()">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs" (click)="editModePC=false">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
+ @if (!editModePC) {
+ <span class="col-md-sm inline-editable" (click)="editModePC=true">{{descriptor.providerConfig}}</span>
+ }
+ @if (editModePC) {
+ <span class="col-md-sm inline-editor inlineEditForm">
+ <input type="text" size="40" [(ngModel)]="descriptor.providerConfig">
+ <button class="btn btn-xs" (click)="editModePC=false;descriptor.setDirty()">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs" (click)="editModePC=false">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
- <button id="chooseProviderConfig"
- class="btn btn-xs"
- (click)="chooseProviderConfigModal.open(descriptor, 'sm')"
- [disabled]="editModePC"
- type="submit"
- data-toggle="tooltip"
- title="Choose Provider Configuration">
- <span class="glyphicon glyphicon-edit"></span>
- </button>
+ <span class="clickable inline-glyph btn btn-xs"
+ (click)="chooseProviderConfigModal.open(descriptor, 'sm')"
+ [class.disabled]="editModePC"
+ data-toggle="tooltip"
+ title="Choose Provider Configuration">
+ <span class="material-icons">edit</span>
+ </span>
</span>
</div>
<app-provider-config-selector #choosePC></app-provider-config-selector>
</div> <!-- Provider Config reference -->
- <br><br>
+ <br>
<div class="panel panel-default">
<div class="panel-heading">
- <span [class]="'clickable inline-glyph glyhpicon glyphicon-' + (isShowServices() ? 'minus' : 'plus')"
- (click)="toggleShowServices()"></span>
+ <span class="clickable inline-glyph material-icons"
+ (click)="toggleShowServices()">{{isShowServices() ? 'expand_more' : 'chevron_right'}}</span>
<span><strong>Services</strong></span>
- <span *ngIf="!isAddingService"
- class="clickable inline-glyph glyphicon glyphicon-plus-sign btn btn-xs"
- (click)="isAddingService=true"
- data-toggle="tooltip" title="Add Service"></span>
- <span *ngIf="isAddingService" class="inline-editor inlineEditForm">
- <input type="text" value="name" onClick="this.setSelectionRange(0, this.value.length)"
- #newServiceName>
- <button class="btn btn-xs"
- (click)="isAddingService=false;
- descriptor.addService(newServiceName.value);
- showServices()">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs" (click)="isAddingService=false">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
- </div>
- <div class="panel-body table-responsive" *ngIf="isShowServices()">
- <table class="table table-striped table-sm">
- <tr *ngFor="let service of descriptor.services">
- <td>
- <div>
- <span [class]="!getServiceVersionEditFlag(service) && !service.version ? 'inline-editable' : ''"
- (click)="setServiceVersionEditFlag(service, true)"
- title="Set version"
- data-toggle="tooltip"><strong>{{ service.name }}</strong></span>
- <span *ngIf="!getServiceVersionEditFlag(service) && service.version"
- (click)="setServiceVersionEditFlag(service, true)"
- [class]="service.version ? 'inline-editable' : ''">({{service.version}}
- )</span>
- <span *ngIf="getServiceVersionEditFlag(service)"
- class="inline-editor inlineEditForm">
- <input type="text" size="40" [(ngModel)]="service.version">
- <button class="btn btn-xs"
- (click)="setServiceVersionEditFlag(service, false);descriptor.onVersionChanged(service)">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs" (click)="setServiceVersionEditFlag(service, false)">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
-
- <span class="clickable inline-glyph glyphicon glyphicon-remove btn btn-xs pull-right"
- [title]="'Remove ' + service.name"
- (click)="onRemoveDescriptorService(service.name)"
- data-toggle="tooltip"></span>
- </div>
- <div>
- <span [class]="'clickable inline-glyph glyhpicon glyphicon-' + (isShowServiceParams(service) ? 'minus' : 'plus')"
- (click)="toggleShowServiceParams(service)"></span>
- <span>Params</span><span> </span>
- <span *ngIf="!isAddingServiceParam(service)"
- class="clickable inline-glyph glyphicon glyphicon-plus-sign btn btn-xs"
- (click)="setAddingServiceParam(service,true)"
- data-toggle="tooltip"
- title="Add Param"></span>
- <span *ngIf="isAddingServiceParam(service)"
- class="inline-editor inlineEditForm">
- <input type="text" value="name"
- onClick="this.setSelectionRange(0, this.value.length)" #newParamName>
- <input type="text" value="value"
- onClick="this.setSelectionRange(0, this.value.length)" #newParamValue>
- <button class="btn btn-xs"
- (click)="setAddingServiceParam(service,false);
- descriptor.addServiceParam(service, newParamName.value, newParamValue.value);
- showServiceParams(service)">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs" (click)="setAddingServiceParam(service,false)">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
- </div>
- <div class="table-responsive" *ngIf="isShowServiceParams(service)">
- <table class="table table-sm"
- *ngIf="descriptor.getServiceParamNames(service).length > 0">
- <tr *ngFor="let paramKey of descriptor.getServiceParamNames(service)">
- <td width="5%">
- <span class="clickable inline-glyph glyphicon glyphicon-remove btn btn-xs"
- title="Remove Param"
- (click)="onRemoveDescriptorServiceParam(service.name, paramKey)"
- data-toggle="tooltip"></span>
- </td>
- <td width="30%"><strong>{{ paramKey }}</strong></td>
- <td width="65%" align="left">
- <span class="inline-editable"
- (click)="setServiceParamEditFlag(service, paramKey, true)"
- *ngIf="!getServiceParamEditFlag(service, paramKey)">{{descriptor.getServiceParamValue(service, paramKey)}}</span>
- <span *ngIf="getServiceParamEditFlag(service, paramKey)"
- class="inline-editor inlineEditForm">
- <input type="text" size="40" [(ngModel)]="service.params[paramKey]">
- <button class="btn btn-xs"
- (click)="setServiceParamEditFlag(service, paramKey, false);descriptor.setDirty()">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs"
- (click)="setServiceParamEditFlag(service, paramKey, false)">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
- </td>
- </tr>
- </table>
- </div>
- <div>
- <span [class]="'clickable inline-glyph glyhpicon glyphicon-' + (isShowServiceURLs(service) ? 'minus' : 'plus')"
- (click)="toggleShowServiceURLs(service)"></span>
- <span>URLs</span><span> </span>
- <span *ngIf="!isAddingServiceURL(service)"
- (click)="setAddingServiceURL(service,true)"
- class="inline-glyph glyphicon glyphicon-plus-sign btn btn-xs"
- data-toggle="tooltip" title="Add URL"></span>
- <span *ngIf="isAddingServiceURL(service)"
- class="inline-editor inlineEditForm">
- <input type="text" value="url"
- onClick="this.setSelectionRange(0, this.value.length)" #newURL>
- <button class="btn btn-xs"
- (click)="setAddingServiceURL(service,false);
- descriptor.addServiceURL(service, newURL.value);
- showServiceURLs(service)">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs" (click)="setAddingServiceURL(service,false)">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
- </div>
- <div class="table-responsive" *ngIf="isShowServiceURLs(service)">
- <table class="table table-sm"
- *ngIf="service.urls && service.urls.length > 0">
- <tr *ngFor="let url of service.urls; let i = index; trackBy:trackByServiceURLIndex">
- <td width="5%">
- <span class="clickable inline-glyph glyphicon glyphicon-remove btn btn-xs"
- title="Remove URL"
- (click)="onRemoveDescriptorServiceURL(service.name, url)"
- data-toggle="tooltip"></span>
- </td>
- <td width="95%">
- <span class="inline-editable"
- (click)="setServiceURLEditFlag(service, i, true)"
- *ngIf="!getServiceURLEditFlag(service, i)">{{url}}</span>
- <span *ngIf="getServiceURLEditFlag(service, i)"
- class="inline-editor inlineEditForm">
- <input type="text" size="50" [(ngModel)]="service.urls[i]">
+ @if (!isAddingService) {
+ <span class="clickable inline-glyph btn btn-xs"
+ (click)="isAddingService=true"
+ data-toggle="tooltip" title="Add Service"><span class="material-icons">add_circle</span></span>
+ }
+ @if (isAddingService) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" value="name" onClick="this.setSelectionRange(0, this.value.length)"
+ #newServiceName>
<button class="btn btn-xs"
- (click)="setServiceURLEditFlag(service, i, false);descriptor.setDirty()">
- <span class="glyphicon glyphicon-ok"></span>
+ (click)="isAddingService=false;
+ descriptor.addService(newServiceName.value);
+ showServices()">
+ <span class="material-icons">check</span>
</button>
- <button class="btn btn-xs"
- (click)="setServiceURLEditFlag(service, i, false)">
- <span class="glyphicon glyphicon-remove"></span>
+ <button class="btn btn-xs" (click)="isAddingService=false">
+ <span class="material-icons">close</span>
</button>
- </span>
- </td>
- </tr>
- </table>
- </div>
- </td>
- </tr>
+ </span>
+ }
+ </div>
+ @if (isShowServices()) {
+ <div class="panel-body table-responsive">
+ <table class="table table-striped table-sm">
+ @for (service of descriptor.services; track service.name) {
+ <tr>
+ <td>
+ <div>
+ @if (!getServiceVersionEditFlag(service) && !service.version) {
+ <span class="inline-editable"
+ (click)="setServiceVersionEditFlag(service, true)"
+ title="Set version"
+ data-toggle="tooltip"><strong>{{ service.name }}</strong></span>
+ } @else {
+ <span (click)="setServiceVersionEditFlag(service, true)"
+ title="Set version"
+ data-toggle="tooltip"><strong>{{ service.name }}</strong></span>
+ }
+ @if (!getServiceVersionEditFlag(service) && service.version) {
+ <span (click)="setServiceVersionEditFlag(service, true)"
+ [class]="service.version ? 'inline-editable' : ''">({{service.version}})</span>
+ }
+ @if (getServiceVersionEditFlag(service)) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" size="40" [(ngModel)]="service.version">
+ <button class="btn btn-xs"
+ (click)="setServiceVersionEditFlag(service, false);descriptor.onVersionChanged(service)">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs" (click)="setServiceVersionEditFlag(service, false)">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
+
+ <span class="clickable inline-glyph btn btn-xs pull-right"
+ [title]="'Remove ' + service.name"
+ (click)="onRemoveDescriptorService(service.name)"
+ data-toggle="tooltip"><span class="material-icons">cancel</span></span>
+ </div>
+ <div>
+ <span class="clickable inline-glyph material-icons"
+ (click)="toggleShowServiceParams(service)">{{isShowServiceParams(service) ? 'expand_more' : 'chevron_right'}}</span>
+ <span>Params</span><span> </span>
+ @if (!isAddingServiceParam(service)) {
+ <span class="clickable inline-glyph btn btn-xs"
+ (click)="setAddingServiceParam(service,true)"
+ data-toggle="tooltip"
+ title="Add Param"><span class="material-icons">add_circle</span></span>
+ }
+ @if (isAddingServiceParam(service)) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" value="name"
+ onClick="this.setSelectionRange(0, this.value.length)" #newParamName>
+ <input type="text" value="value"
+ onClick="this.setSelectionRange(0, this.value.length)" #newParamValue>
+ <button class="btn btn-xs"
+ (click)="setAddingServiceParam(service,false);
+ descriptor.addServiceParam(service, newParamName.value, newParamValue.value);
+ showServiceParams(service)">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs" (click)="setAddingServiceParam(service,false)">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
+ </div>
+ @if (isShowServiceParams(service)) {
+ <div class="table-responsive">
+ @if (descriptor.getServiceParamNames(service).length > 0) {
+ <table class="table table-sm">
+ @for (paramKey of descriptor.getServiceParamNames(service); track paramKey) {
+ <tr>
+ <td width="5%">
+ <span class="clickable inline-glyph btn btn-xs"
+ title="Remove Param"
+ (click)="onRemoveDescriptorServiceParam(service.name, paramKey)"
+ data-toggle="tooltip"><span class="material-icons">cancel</span></span>
+ </td>
+ <td width="30%"><strong>{{ paramKey }}</strong></td>
+ <td width="65%" align="left">
+ @if (!getServiceParamEditFlag(service, paramKey)) {
+ <span class="inline-editable"
+ (click)="setServiceParamEditFlag(service, paramKey, true)">{{descriptor.getServiceParamValue(service, paramKey)}}</span>
+ }
+ @if (getServiceParamEditFlag(service, paramKey)) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" size="40" [(ngModel)]="service.params[paramKey]">
+ <button class="btn btn-xs"
+ (click)="setServiceParamEditFlag(service, paramKey, false);descriptor.setDirty()">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs"
+ (click)="setServiceParamEditFlag(service, paramKey, false)">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
+ </td>
+ </tr>
+ }
+ </table>
+ }
+ </div>
+ }
+ <div>
+ <span class="clickable inline-glyph material-icons"
+ (click)="toggleShowServiceURLs(service)">{{isShowServiceURLs(service) ? 'expand_more' : 'chevron_right'}}</span>
+ <span>URLs</span><span> </span>
+ @if (!isAddingServiceURL(service)) {
+ <span (click)="setAddingServiceURL(service,true)"
+ class="clickable inline-glyph btn btn-xs"
+ data-toggle="tooltip" title="Add URL"><span class="material-icons">add_circle</span></span>
+ }
+ @if (isAddingServiceURL(service)) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" value="url"
+ onClick="this.setSelectionRange(0, this.value.length)" #newURL>
+ <button class="btn btn-xs"
+ (click)="setAddingServiceURL(service,false);
+ descriptor.addServiceURL(service, newURL.value);
+ showServiceURLs(service)">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs" (click)="setAddingServiceURL(service,false)">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
+ </div>
+ @if (isShowServiceURLs(service)) {
+ <div class="table-responsive">
+ @if (service.urls && service.urls.length > 0) {
+ <table class="table table-sm">
+ @for (url of service.urls; track trackByServiceURLIndex($index, url); let i = $index) {
+ <tr>
+ <td width="5%">
+ <span class="clickable inline-glyph btn btn-xs"
+ title="Remove URL"
+ (click)="onRemoveDescriptorServiceURL(service.name, url)"
+ data-toggle="tooltip"><span class="material-icons">cancel</span></span>
+ </td>
+ <td width="95%">
+ @if (!getServiceURLEditFlag(service, i)) {
+ <span class="inline-editable"
+ (click)="setServiceURLEditFlag(service, i, true)">{{url}}</span>
+ }
+ @if (getServiceURLEditFlag(service, i)) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" size="50" [(ngModel)]="service.urls[i]">
+ <button class="btn btn-xs"
+ (click)="setServiceURLEditFlag(service, i, false);descriptor.setDirty()">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs"
+ (click)="setServiceURLEditFlag(service, i, false)">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
+ </td>
+ </tr>
+ }
+ </table>
+ }
+ </div>
+ }
+ </td>
+ </tr>
+ }
</table>
</div> <!-- Services table -->
+ }
</div> <!-- Services panel -->
<div class="panel panel-default"> <!-- Discovery panel -->
<div class="panel-heading">
- <span [class]="'clickable inline-glyph glyhpicon glyphicon-' + (isShowServiceDiscovery() ? 'minus' : 'plus')"
- (click)="toggleShowServiceDiscovery()"></span>
+ <span class="clickable inline-glyph material-icons"
+ (click)="toggleShowServiceDiscovery()">{{isShowServiceDiscovery() ? 'expand_more' : 'chevron_right'}}</span>
<span><strong>Discovery Details</strong></span>
</div>
- <div class="panel-body" *ngIf="isShowServiceDiscovery()">
+ @if (isShowServiceDiscovery()) {
+ <div class="panel-body">
<table class="table table-sm">
<!-- Discovery type field -->
<tr>
@@ -370,10 +425,11 @@
<span>
<select id="select" autofocus required class="md-select form-control"
[(ngModel)]="descriptor.discoveryType" (change)="descriptor.setDirty()">
- <option *ngFor="let typeOption of resourceService.discoveryTypes"
- class="md-option"
- [value]="typeOption"
- [selected]="descriptor.discoveryType === typeOption">{{typeOption}}</option>
+ @for (typeOption of resourceService.discoveryTypes; track typeOption) {
+ <option class="md-option"
+ [value]="typeOption"
+ [selected]="descriptor.discoveryType === typeOption">{{typeOption}}</option>
+ }
</select>
</span>
</td>
@@ -385,21 +441,26 @@
(click)="editModeAddress=true">
<strong>Address</strong>
</span>
- <span *ngIf="!editModeAddress && !descriptor.discoveryAddress"> </span>
+ @if (!editModeAddress && !descriptor.discoveryAddress) {
+ <span> </span>
+ }
</td>
<td>
- <span class="inline-editable"
- (click)="editModeAddress=true"
- *ngIf="!editModeAddress">{{ descriptor.discoveryAddress }}</span>
- <span *ngIf="editModeAddress" class="inline-editor inlineEditForm">
- <input type="text" size="40" [(ngModel)]="descriptor.discoveryAddress">
- <button class="btn btn-xs" (click)="editModeAddress=false;descriptor.setDirty()">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs" (click)="editModeAddress=false">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
+ @if (!editModeAddress) {
+ <span class="inline-editable"
+ (click)="editModeAddress=true">{{ descriptor.discoveryAddress }}</span>
+ }
+ @if (editModeAddress) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" size="40" [(ngModel)]="descriptor.discoveryAddress">
+ <button class="btn btn-xs" (click)="editModeAddress=false;descriptor.setDirty()">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs" (click)="editModeAddress=false">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
</td>
</tr>
<!-- Discovery cluster field -->
@@ -409,21 +470,26 @@
(click)="editModeCluster=true">
<strong>Cluster</strong>
</span>
- <span *ngIf="!editModeCluster && !descriptor.discoveryCluster"> </span>
+ @if (!editModeCluster && !descriptor.discoveryCluster) {
+ <span> </span>
+ }
</td>
<td>
- <span class="inline-editable"
- (click)="editModeCluster=true"
- *ngIf="!editModeCluster">{{ descriptor.discoveryCluster}}</span>
- <span *ngIf="editModeCluster" class="inline-editor inlineEditForm">
- <input type="text" size="40" [(ngModel)]="descriptor.discoveryCluster">
- <button class="btn btn-xs" (click)="editModeCluster=false;descriptor.setDirty()">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs" (click)="editModeCluster=false">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
+ @if (!editModeCluster) {
+ <span class="inline-editable"
+ (click)="editModeCluster=true">{{ descriptor.discoveryCluster}}</span>
+ }
+ @if (editModeCluster) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" size="40" [(ngModel)]="descriptor.discoveryCluster">
+ <button class="btn btn-xs" (click)="editModeCluster=false;descriptor.setDirty()">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs" (click)="editModeCluster=false">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
</td>
</tr>
<!-- Discovery user field -->
@@ -433,21 +499,26 @@
(click)="editModeUser=true">
<strong>Username</strong>
</span>
- <span *ngIf="!editModeUser && !descriptor.discoveryUser"> </span>
+ @if (!editModeUser && !descriptor.discoveryUser) {
+ <span> </span>
+ }
</td>
<td>
- <span class="inline-editable"
- (click)="editModeUser=true"
- *ngIf="!editModeUser">{{ descriptor.discoveryUser }}</span>
- <span *ngIf="editModeUser" class="inline-editor inlineEditForm">
- <input type="text" size="40" [(ngModel)]="descriptor.discoveryUser">
- <button class="btn btn-xs" (click)="editModeUser=false;descriptor.setDirty()">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs" (click)="editModeUser=false">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
+ @if (!editModeUser) {
+ <span class="inline-editable"
+ (click)="editModeUser=true">{{ descriptor.discoveryUser }}</span>
+ }
+ @if (editModeUser) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" size="40" [(ngModel)]="descriptor.discoveryUser">
+ <button class="btn btn-xs" (click)="editModeUser=false;descriptor.setDirty()">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs" (click)="editModeUser=false">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
</td>
</tr>
<!-- Discovery password alias field -->
@@ -457,109 +528,112 @@
(click)="editModeAlias=true">
<strong>Password Alias</strong>
</span>
- <span *ngIf="!editModeAlias && !descriptor.discoveryPassAlias"> </span>
+ @if (!editModeAlias && !descriptor.discoveryPassAlias) {
+ <span> </span>
+ }
</td>
<td>
- <span class="inline-editable"
- (click)="editModeAlias=true"
- *ngIf="!editModeAlias">{{ descriptor.discoveryPassAlias }}</span>
- <span *ngIf="editModeAlias" class="inline-editor inlineEditForm">
- <input type="text" size="40" [(ngModel)]="descriptor.discoveryPassAlias">
- <button class="btn btn-xs" (click)="editModeAlias=false;descriptor.setDirty()">
- <span class="glyphicon glyphicon-ok"></span>
- </button>
- <button class="btn btn-xs" (click)="editModeAlias=false">
- <span class="glyphicon glyphicon-remove"></span>
- </button>
- </span>
+ @if (!editModeAlias) {
+ <span class="inline-editable"
+ (click)="editModeAlias=true">{{ descriptor.discoveryPassAlias }}</span>
+ }
+ @if (editModeAlias) {
+ <span class="inline-editor inlineEditForm">
+ <input type="text" size="40" [(ngModel)]="descriptor.discoveryPassAlias">
+ <button class="btn btn-xs" (click)="editModeAlias=false;descriptor.setDirty()">
+ <span class="material-icons">check</span>
+ </button>
+ <button class="btn btn-xs" (click)="editModeAlias=false">
+ <span class="material-icons">close</span>
+ </button>
+ </span>
+ }
</td>
</tr>
</table>
</div><!-- Discovery details -->
+ }
</div><!-- Discovery panel -->
- <div> <!-- Descriptor Modification Buttons -->
- <button type="button"
- title="Remove Descriptor"
- class="btn btn-default btn-sm pull-left"
- (click)="deleteConfirmModal.open('md')"
- data-toggle="tooltip"
- *ngIf="showEditOptions()">
- <span class="glyphicon glyphicon-trash"></span>
- </button>
- <span class="pull-right">
- <button type="button"
- title="Discard Changes"
- class="btn btn-default btn-sm"
- [disabled]="!descriptor.isDirty()"
- (click)="discardConfirmModal.open('md')"
- data-toggle="tooltip"
- *ngIf="showEditOptions()">
- <span class="glyphicon glyphicon-refresh"></span>
- </button>
- <span> </span>
- <button type="button"
- title="Update Descriptor"
- class="btn btn-default btn-sm"
- [disabled]="!descriptor.isDirty()"
- (click)="persistChanges()"
- data-toggle="tooltip"
- *ngIf="showEditOptions()">
- <span class="glyphicon glyphicon-floppy-disk"></span>
- </button>
- </span>
+ <div style="overflow: hidden; padding-top: 10px;"> <!-- Descriptor Modification Buttons -->
+ @if (showEditOptions()) {
+ <button type="button"
+ title="Remove Descriptor"
+ class="btn btn-default btn-sm pull-left"
+ (click)="deleteConfirmModal.open('md')"
+ data-toggle="tooltip">
+ <span class="material-icons">delete</span>
+ </button>
+ <span class="pull-right">
+ <button type="button"
+ title="Discard Changes"
+ class="btn btn-default btn-sm"
+ [disabled]="!descriptor.isDirty()"
+ (click)="discardConfirmModal.open('md')"
+ data-toggle="tooltip">
+ <span class="material-icons">refresh</span>
+ </button>
+ <span> </span>
+ <button type="button"
+ title="Update Descriptor"
+ class="btn btn-default btn-sm"
+ [disabled]="!descriptor.isDirty()"
+ (click)="persistChanges()"
+ data-toggle="tooltip">
+ <span class="material-icons">save</span>
+ </button>
+ </span>
+ }
</div>
</div> <!-- Descriptor Details -->
+ }
- <div> <!-- Confirmation Modal Dialogs -->
- <bs-modal (onClose)="deleteResource()" #deleteConfirmModal>
- <bs-modal-header [showDismiss]="true">
+ <div>
+ <app-modal (onClose)="deleteResource()" #deleteConfirmModal>
+ <div class="modal-header">
<h4 class="modal-title">Deleting {{getTitleSubject()}}</h4>
- </bs-modal-header>
- <bs-modal-body>Are you sure you want to delete
+ <button type="button" class="btn-close" (click)="deleteConfirmModal.dismiss()"></button>
+ </div>
+ <div class="modal-body">Are you sure you want to delete
<strong>{{resourceService.getResourceDisplayName(resource)}}</strong>?
- </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>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default btn-sm"
+ (click)="deleteConfirmModal.dismiss()">Cancel</button>
+ <button type="button" class="btn btn-primary btn-sm"
+ (click)="deleteConfirmModal.close()">Ok</button>
+ </div>
+ </app-modal>
- <bs-modal (onClose)="discardChanges()" #discardConfirmModal>
- <bs-modal-header [showDismiss]="true">
+ <app-modal (onClose)="discardChanges()" #discardConfirmModal>
+ <div class="modal-header">
<h4 class="modal-title">Discard {{getTitleSubject()}} Changes</h4>
- </bs-modal-header>
- <bs-modal-body>Are you sure you want to discard
+ <button type="button" class="btn-close" (click)="discardConfirmModal.dismiss()"></button>
+ </div>
+ <div class="modal-body">Are you sure you want to discard
<strong>{{resourceService.getResourceDisplayName(resource)}}</strong> changes?
- </bs-modal-body>
- <bs-modal-footer>
- <button type="button"
- class="btn btn-default btn-sm"
- data-dismiss="revertConfirmModal"
- (click)="discardConfirmModal.dismiss()">Cancel
- </button>
- <button type="button"
- class="btn btn-primary btn-sm"
- (click)="discardConfirmModal.close()">Ok
- </button>
- </bs-modal-footer>
- </bs-modal>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default btn-sm"
+ (click)="discardConfirmModal.dismiss()">Cancel</button>
+ <button type="button" class="btn btn-primary btn-sm"
+ (click)="discardConfirmModal.close()">Ok</button>
+ </div>
+ </app-modal>
</div>
</div>
+}
<!-- Topology Details -->
-<div *ngIf="resourceType === 'Topologies'">
+@if (resourceType === 'Topologies') {
+<div>
<app-topology-detail></app-topology-detail>
</div>
+}
<!-- Service Definition Details -->
-<div *ngIf="resourceType === 'Service Definitions'">
+@if (resourceType === 'Service Definitions') {
+<div>
<app-servicedefinition-detail></app-servicedefinition-detail>
-</div>
\ No newline at end of file
+</div>
+}
diff --git a/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.spec.ts b/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.spec.ts
deleted file mode 100644
index a081aee9a..000000000
--- a/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.spec.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {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();
- });
-});
diff --git a/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.ts b/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.ts
index bc110064e..93b09fbdd 100644
--- a/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.ts
+++ b/gateway-admin-ui/admin-ui/app/resource-detail/resource-detail.component.ts
@@ -15,25 +15,27 @@
* limitations under the License.
*/
import {Component, OnInit, ViewChild} 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';
-// Commented out in scope of KNOX-2834 (see below)
-// import {parseString} from 'xml2js';
-
-import 'brace/theme/monokai';
-import 'brace/mode/xml';
+import {FormsModule} from '@angular/forms';
+import {ResourceService} from '../service/resource.service';
+import {Resource} from '../model/resource';
+import {ProviderConfig} from '../model/provider-config';
+import {Descriptor} from '../model/descriptor';
+import {Service} from '../model/service';
import {ProviderConfigSelectorComponent} from '../provider-config-selector/provider-config-selector.component';
-import {ResourceTypesService} from '../resourcetypes/resourcetypes.service';
-import {HttpErrorResponse} from '@angular/common/http';
+import {ResourceTypesService} from '../service/resourcetypes.service';
+import {TopologyDetailComponent} from '../topology-detail/topology-detail.component';
+import {ServiceDefinitionDetailComponent} from '../service-definition/servicedefinition-detail.component';
+import {ModalComponent} from '../utils/modal.component';
+import { HttpErrorResponse } from '@angular/common/http';
+import * as yaml from 'js-yaml';
@Component({
selector: 'app-resource-detail',
templateUrl: './resource-detail.component.html',
- styleUrls: ['./resource-detail.component.css']
+ styleUrls: ['./resource-detail.component.css'],
+ imports: [FormsModule, ProviderConfigSelectorComponent,
+ TopologyDetailComponent, ServiceDefinitionDetailComponent, ModalComponent]
})
export class ResourceDetailComponent implements OnInit {
@@ -43,8 +45,6 @@ export class ResourceDetailComponent implements OnInit {
private static emptyDescriptor: Descriptor = new Descriptor();
- title: string;
-
resourceType: string;
resource: Resource;
resourceContent: string;
@@ -119,48 +119,10 @@ export class ResourceDetailComponent implements OnInit {
this.providers = contentObj['providers'];
this.readOnlyProviderConfig = contentObj['readOnly'];
} else if (res.name.endsWith('yaml') || res.name.endsWith('yml')) {
- // Parse the YAML representation
- let yaml = require('js-yaml');
- contentObj = yaml.safeLoad(this.resourceContent);
+ contentObj = yaml.load(this.resourceContent);
this.providers = contentObj['providers'];
this.readOnlyProviderConfig = contentObj['readOnly'];
}
- /* Commented out in scope of KNOX-2834, because documentation does not mention supporting
- XML shared provider files and xml2js library is not compatible with angular 14.
-
- else if (res.name.endsWith('xml')) {
- // Parse the XML representation
-
- parseString(this.resourceContent,
- (error, result) => {
- if (error) {
- console.log('Error parsing ' + res.name + ' error: ' + error);
- } else {
- // Parsing the XML is a bit less straight-forward
- let tempProviders = new Array<ProviderConfig>();
- result['gateway'].provider.forEach(entry => {
- let providerConfig: ProviderConfig = new ProviderConfig();
- providerConfig.role = entry.role[0];
- providerConfig.name = entry.name[0];
- providerConfig.enabled = entry.enabled[0];
-
- // There may not be params
- if (entry.param) {
- let params = new Map<string, string>();
- for (let i = 0; i < entry.param.length; i++) {
- let param = entry.param[i];
- params[param.name[0]] = param.value[0];
- }
- providerConfig.params = params;
- }
- tempProviders.push(providerConfig);
- });
- this.providers = tempProviders;
- this.readOnlyProviderConfig = result['gateway'].readOnly;
- }
- }
- );
- } */
} catch (e) {
console.error('ResourceDetailComponent --> setProviderConfigContent() --> Error parsing ' + res.name + ' content: ' + e);
this.providers = null; // Clear detail display
@@ -176,7 +138,6 @@ export class ResourceDetailComponent implements OnInit {
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();
@@ -331,7 +292,7 @@ export class ResourceDetailComponent implements OnInit {
}
onRemoveProviderParam(pc: ProviderConfig, paramName: string) {
- if (pc.params.hasOwnProperty(paramName)) {
+ if (Object.prototype.hasOwnProperty.call(pc.params, paramName)) {
delete pc.params[paramName];
}
this.changedProviders = this.providers;
@@ -352,7 +313,7 @@ export class ResourceDetailComponent implements OnInit {
for (let i = 0; i < this.descriptor.services.length; i++) {
if (this.descriptor.services[i].name === serviceName) {
let service = this.descriptor.services[i];
- if (service.params.hasOwnProperty(paramName)) {
+ if (Object.prototype.hasOwnProperty.call(service.params, paramName)) {
delete service.params[paramName];
this.descriptor.setDirty();
done = true;
@@ -548,7 +509,7 @@ export class ResourceDetailComponent implements OnInit {
}
// This method is required to maintain focus on descriptor service URLs when they're being edited.
- trackByServiceURLIndex(index: any, item: any) {
+ trackByServiceURLIndex(index: any, _item: any) {
return index;
}
@@ -573,7 +534,7 @@ export class ResourceDetailComponent implements OnInit {
showEditOptions(): boolean {
if (this.resourceType === 'Descriptors' && this.descriptor.readOnly) {
- return !Boolean(this.descriptor.readOnly);
+ return !this.descriptor.readOnly;
}
if (this.resourceType === 'Provider Configurations' && this.readOnlyProviderConfig) {
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.component.css b/gateway-admin-ui/admin-ui/app/resource/resource.component.css
index e69de29bb..135714db5 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.component.css
+++ b/gateway-admin-ui/admin-ui/app/resource/resource.component.css
@@ -0,0 +1,58 @@
+.table-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 6px 12px;
+ background-color: #fff;
+ border-bottom: 2px solid #4caf50;
+}
+
+.table-title {
+ font-weight: 600;
+ font-size: 13px;
+ color: #333;
+}
+
+:host ::ng-deep .mat-mdc-table {
+ background-color: #fff;
+}
+
+:host ::ng-deep .mat-mdc-header-row {
+ height: 32px;
+ background-color: #fafafa;
+}
+
+:host ::ng-deep .mat-mdc-header-cell {
+ font-size: 12px;
+ font-weight: 600;
+ color: #555;
+ padding: 0 12px;
+}
+
+:host ::ng-deep .mat-mdc-row {
+ height: 30px;
+}
+
+:host ::ng-deep .mat-mdc-cell {
+ font-size: 13px;
+ padding: 0 12px;
+ border-bottom-color: #eee;
+}
+
+:host ::ng-deep tr.mat-mdc-row:nth-child(even) {
+ background-color: #f9fdf9;
+}
+
+:host ::ng-deep tr.mat-mdc-row:hover {
+ background-color: #e8f5e9;
+}
+
+:host ::ng-deep tr.mat-mdc-row.selected,
+:host ::ng-deep tr.mat-mdc-row.active {
+ background-color: #c8e6c9;
+}
+
+:host ::ng-deep .mat-mdc-paginator {
+ font-size: 12px;
+ border-top: 1px solid #eee;
+}
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.component.html b/gateway-admin-ui/admin-ui/app/resource/resource.component.html
index 4845e6039..e7ddab505 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.component.html
+++ b/gateway-admin-ui/admin-ui/app/resource/resource.component.html
@@ -1,51 +1,47 @@
<div>
- <div class="table-responsive" style="width:100%; overflow: auto; overflow-y: scroll">
- <table class="table table-hover" [mfData]="resources" #mf="mfDataTable" [mfRowsOnPage]="10">
- <thead>
- <tr>
- <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>
- <span class="clickable inline-glyph glyphicon glyphicon-plus-sign btn btn-xs pull-right"
- *ngIf="resourceType === 'Service Definitions'"
- (click)="newServiceDefinitionModal.open()"
- title="Create New Service Definition"
- data-toggle="tooltip"></span>
- </th>
- <th *ngIf="resourceType === 'Topologies'">Timestamp</th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let resource of mf.data"
- [class.selected]="resource === selectedResource"
- [class.active]="isSelectedResource(resource)"
- (click)="onSelect(resource)"
- class="clickable">
- <td>{{resourceService.getResourceDisplayName(resource)}}</td>
- <td *ngIf="resourceType === 'Topologies'">{{resource.timestamp | date:'medium'}}</td>
- </tr>
- </tbody>
- <tfoot>
- <tr>
- <td colspan="4">
- <mfBootstrapPaginator [rowsOnPageSet]="[5,10,15]"></mfBootstrapPaginator>
- </td>
- </tr>
- </tfoot>
- </table>
+ <div class="table-header">
+ <span class="table-title">{{ getResourceTypeSingularDisplayName(resourceType) }}</span>
+ @if (resourceType === 'Provider Configurations') {
+ <span class="clickable inline-glyph btn btn-xs"
+ (click)="newProviderConfigModal.open()"
+ title="Create New Provider Configuration"
+ data-toggle="tooltip"><span class="material-icons">add_circle</span></span>
+ }
+ @if (resourceType === 'Descriptors') {
+ <span class="clickable inline-glyph btn btn-xs"
+ (click)="newDescriptorModal.open()"
+ title="Create New Descriptor"
+ data-toggle="tooltip"><span class="material-icons">add_circle</span></span>
+ }
+ @if (resourceType === 'Service Definitions') {
+ <span class="clickable inline-glyph btn btn-xs"
+ (click)="newServiceDefinitionModal.open()"
+ title="Create New Service Definition"
+ data-toggle="tooltip"><span class="material-icons">add_circle</span></span>
+ }
</div>
+
+ <table mat-table [dataSource]="dataSource" style="width: 100%;">
+ <ng-container matColumnDef="name">
+ <th mat-header-cell *matHeaderCellDef>Name</th>
+ <td mat-cell *matCellDef="let resource">{{resourceService.getResourceDisplayName(resource)}}</td>
+ </ng-container>
+
+ <ng-container matColumnDef="timestamp">
+ <th mat-header-cell *matHeaderCellDef>Timestamp</th>
+ <td mat-cell *matCellDef="let resource">{{resource.timestamp | date:'medium'}}</td>
+ </ng-container>
+
+ <tr mat-header-row *matHeaderRowDef="getDisplayedColumns()"></tr>
+ <tr mat-row *matRowDef="let row; columns: getDisplayedColumns();"
+ [class.selected]="row === selectedResource"
+ [class.active]="isSelectedResource(row)"
+ (click)="onSelect(row)"
+ class="clickable"></tr>
+ </table>
+
+ <mat-paginator [pageSizeOptions]="[5, 10, 15]" [pageSize]="10" showFirstLastButtons></mat-paginator>
+
<div>
<app-new-desc-wizard #newDescriptorModal></app-new-desc-wizard>
<app-provider-config-wizard #newProviderConfigModal></app-provider-config-wizard>
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.component.spec.ts b/gateway-admin-ui/admin-ui/app/resource/resource.component.spec.ts
deleted file mode 100644
index f5f4bc59b..000000000
--- a/gateway-admin-ui/admin-ui/app/resource/resource.component.spec.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {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();
- });
-});
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.component.ts b/gateway-admin-ui/admin-ui/app/resource/resource.component.ts
index 6ba0b1cff..0a2383010 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.component.ts
+++ b/gateway-admin-ui/admin-ui/app/resource/resource.component.ts
@@ -14,26 +14,35 @@
* 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';
-import {ServiceDefinitionService} from '../service-definition/servicedefinition.service';
-import {ServiceDefinition} from '../service-definition/servicedefinition';
-import {HttpErrorResponse} from '@angular/common/http';
+import {Component, OnInit, ViewChild, AfterViewInit} from '@angular/core';
+import {DatePipe} from '@angular/common';
+import {MatTableModule, MatTableDataSource} from '@angular/material/table';
+import {MatPaginatorModule, MatPaginator} from '@angular/material/paginator';
+import {ResourceTypesService} from '../service/resourcetypes.service';
+import {ResourceService} from '../service/resource.service';
+import {Resource} from '../model/resource';
+import {TopologyService} from '../service/topology.service';
+import {Topology} from '../model/topology';
+import {ServiceDefinitionService} from '../service/servicedefinition.service';
+import {ServiceDefinition} from '../model/servicedefinition';
+import {NewDescWizardComponent} from '../new-desc-wizard/new-desc-wizard.component';
+import {ProviderConfigWizardComponent} from '../provider-config-wizard/provider-config-wizard.component';
+import {NewServiceDefinitionComponent} from '../service-definition/new-service-definition.component';
+import { HttpErrorResponse } from '@angular/common/http';
@Component({
selector: 'app-resource',
templateUrl: './resource.component.html',
- styleUrls: ['./resource.component.css']
+ styleUrls: ['./resource.component.css'],
+ imports: [DatePipe, MatTableModule, MatPaginatorModule,
+ NewDescWizardComponent, ProviderConfigWizardComponent, NewServiceDefinitionComponent]
})
-export class ResourceComponent implements OnInit {
+export class ResourceComponent implements OnInit, AfterViewInit {
resourceType: string;
- value: any;
- resources: Resource[];
selectedResource: Resource;
+ dataSource = new MatTableDataSource<Resource>([]);
+
+ @ViewChild(MatPaginator) paginator: MatPaginator;
constructor(private resourceTypesService: ResourceTypesService,
private resourceService: ResourceService,
@@ -45,15 +54,25 @@ export class ResourceComponent implements OnInit {
this.resourceTypesService.selectedResourceType$.subscribe(resourceType => this.setResourceType(resourceType));
}
+ ngAfterViewInit() {
+ this.dataSource.paginator = this.paginator;
+ }
+
+ getDisplayedColumns(): string[] {
+ if (this.resourceType === 'Topologies') {
+ return ['name', 'timestamp'];
+ }
+ return ['name'];
+ }
+
setResourceType(resType: string) {
- // Clear the selected resource, so it can be removed from the list on refresh if necessary
this.selectedResource = null;
this.resourceType = resType;
this.resourceService.selectedResourceType(this.resourceType);
this.resourceService.getResources(resType)
.then(resources => {
- this.resources = resources;
+ this.dataSource.data = resources;
let debugMsg = 'ResourceComponent --> Found ' + resources.length + ' ' + resType + ' resources\n';
for (let res of resources) {
@@ -73,7 +92,6 @@ export class ResourceComponent implements OnInit {
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;
@@ -81,13 +99,11 @@ export class ResourceComponent implements OnInit {
this.topologyService.selectedTopology(topology);
} else if (this.resourceType === 'Service Definitions') {
let serviceDefinition = new ServiceDefinition();
- serviceDefinition.name = resource.name;
serviceDefinition.service = resource.service['name'];
serviceDefinition.role = resource.service['role'];
serviceDefinition.version = resource.service['version'];
this.serviceDefinitionService.selectedServiceDefinition(serviceDefinition);
} else {
- // Otherwise, notify the resource service
this.resourceService.selectedResource(resource);
}
}
diff --git a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.css b/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.css
index e69de29bb..ba98cb320 100644
--- a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.css
+++ b/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.css
@@ -0,0 +1,45 @@
+.resource-types-panel {
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ overflow: hidden;
+}
+
+.resource-types-header {
+ padding: 8px 12px;
+ font-weight: 600;
+ font-size: 13px;
+ color: #333;
+ background-color: #fff;
+ border-bottom: 2px solid #4caf50;
+}
+
+.resource-types-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+.resource-type-item {
+ padding: 8px 12px;
+ font-size: 13px;
+ border-bottom: 1px solid #eee;
+ transition: background-color 0.1s;
+}
+
+.resource-type-item:last-child {
+ border-bottom: none;
+}
+
+.resource-type-item:hover {
+ background-color: #e8f5e9;
+}
+
+.resource-type-item.selected {
+ background-color: #4caf50;
+ color: #fff;
+ font-weight: 500;
+}
+
+.resource-type-item.selected:hover {
+ background-color: #388e3c;
+}
diff --git a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.html b/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.html
index e84539262..c22963ad9 100644
--- a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.html
+++ b/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.html
@@ -1,18 +1,12 @@
-<div class="table-responsive" style="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 class="resource-types-panel">
+ <div class="resource-types-header">Resource Types</div>
+ <ul class="resource-types-list">
+ @for (type of resourceTypes; track type) {
+ <li [class.selected]="type === selectedResourceType"
+ (click)="onSelect(type)"
+ class="clickable resource-type-item">
+ {{type}}
+ </li>
+ }
+ </ul>
</div>
diff --git a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.spec.ts b/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.spec.ts
deleted file mode 100644
index 2790701ba..000000000
--- a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.spec.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {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();
- });
-});
diff --git a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.ts b/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.ts
index f278e838e..5a62a935c 100644
--- a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.ts
+++ b/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.component.ts
@@ -14,8 +14,8 @@
* 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.service';
+import {Component, OnInit} from '@angular/core';
+import {ResourceTypesService} from '../service/resourcetypes.service';
@Component({
selector: 'app-resourcetypes',
diff --git a/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.css b/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.css
index 0cc494ab8..52e0fee93 100644
--- a/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.css
+++ b/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.css
@@ -2,4 +2,26 @@ td {
border-collapse: collapse;
padding: 8px;
vertical-align: top;
-}
\ No newline at end of file
+}
+
+.code-editor-modal {
+ min-height: 430px;
+ width: 100%;
+ padding: 12px;
+ background-color: #272822;
+ color: #f8f8f2;
+ border: 1px solid #3e3d32;
+ border-radius: 4px;
+ outline: none;
+ resize: vertical;
+ font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
+ font-size: 12px;
+ line-height: 18px;
+ tab-size: 4;
+ white-space: pre;
+ overflow: auto;
+}
+
+.code-editor-modal::selection {
+ background-color: #49483e;
+}
diff --git a/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.html b/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.html
index 89a2716f3..a18816a76 100644
--- a/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.html
+++ b/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.html
@@ -1,27 +1,21 @@
-<bs-modal (onClose)="onClose()" #newServiceDefinitionModal xmlns="http://www.w3.org/1999/html">
- <bs-modal-header [showDismiss]="true">
+<app-modal #newServiceDefinitionModal>
+ <div class="modal-header">
<label class="modal-title">Create a New Service Definition</label>
- </bs-modal-header>
- <bs-modal-body>
- <div class="panel-body">
- <div>
- <span style="text-shadow: infotext; text-align: center;">At a minimum you must modify the service's name and role attributes!</span>
- </div>
- <br />
- <div>
- <ace-editor
- #editor
- [(text)]="serviceDefinitionContent"
- [options]="options"
- [theme]="theme"
- style="min-height: 430px; width:100%; overflow: auto;">
- </ace-editor>
- </div>
+ <button type="button" class="btn-close" (click)="newServiceDefinitionModal.dismiss()"></button>
+ </div>
+ <div class="modal-body" style="padding: 12px;">
+ <div class="alert alert-info" style="margin-bottom: 10px; font-size: 12px;">
+ At a minimum you must modify the service's <strong>name</strong> and <strong>role</strong> attributes.
</div>
- </bs-modal-body>
- <bs-modal-footer>
+ <textarea
+ [(ngModel)]="serviceDefinitionContent"
+ spellcheck="false"
+ class="code-editor-modal">
+ </textarea>
+ </div>
+ <div class="modal-footer">
<button type="button" class="btn btn-default btn-sm" (click)="newServiceDefinitionModal.dismiss()">Cancel</button>
- <button type="button" class="btn btn-primary btn-sm" (click)="newServiceDefinitionModal.close()"
+ <button type="button" class="btn btn-primary btn-sm" (click)="onClose()"
[disabled]="!validate()">Ok</button>
- </bs-modal-footer>
-</bs-modal>
+ </div>
+</app-modal>
diff --git a/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.ts b/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.ts
index cb99ccde8..912bb1f07 100644
--- a/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.ts
+++ b/gateway-admin-ui/admin-ui/app/service-definition/new-service-definition.component.ts
@@ -14,34 +14,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
-import {HttpClient} from '@angular/common/http';
-import {BsModalComponent} from 'ng2-bs3-modal';
-import Swal from 'sweetalert2';
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {FormsModule} from '@angular/forms';
+import { HttpClient } from '@angular/common/http';
+import Swal from 'sweetalert2/dist/sweetalert2.esm.all.js';
-import {ServiceDefinitionService} from './servicedefinition.service';
-import {ResourceTypesService} from '../resourcetypes/resourcetypes.service';
-import * as ace from 'ace-builds';
+import {ServiceDefinitionService} from '../service/servicedefinition.service';
+import {ResourceTypesService} from '../service/resourcetypes.service';
+import {ModalComponent} from '../utils/modal.component';
@Component({
selector: 'app-service-definition-wizard',
templateUrl: './new-service-definition.component.html',
- styleUrls: ['./new-service-definition.component.css']
+ styleUrls: ['./new-service-definition.component.css'],
+ imports: [FormsModule, ModalComponent]
})
export class NewServiceDefinitionComponent implements OnInit {
+ @ViewChild('newServiceDefinitionModal')
+ childModal: ModalComponent;
+
serviceDefinitionXmlTemplate = 'assets/new-service-definition-template.xml';
defaultServiceDefinitionContent: string;
serviceDefinitionContent: string;
- theme: String = 'monokai';
- options: any = {useWorker: false, printMargin: false};
-
- @ViewChild('newServiceDefinitionModal')
- childModal: BsModalComponent;
-
- @ViewChild('editor')
- editor: ElementRef<HTMLElement>;
constructor(private http: HttpClient,
private serviceDefinitionService: ServiceDefinitionService,
@@ -53,18 +49,9 @@ export class NewServiceDefinitionComponent implements OnInit {
.subscribe(data => this.defaultServiceDefinitionContent = data);
}
- ngAfterViewInit(): void {
- ace.config.set(
- 'basePath',
- 'https://unpkg.com/ace-builds@1.4.12/src-noconflict'
- );
- const aceEditor = ace.edit(this.editor.nativeElement);
- aceEditor.session.setMode('xml');
- }
-
- open(size?: string) {
+ open() {
this.reset();
- this.childModal.open(size ? size : 'lg');
+ this.childModal.open('lg');
}
reset() {
@@ -73,7 +60,8 @@ export class NewServiceDefinitionComponent implements OnInit {
onClose() {
this.serviceDefinitionService.saveNewServiceDefinition(this.serviceDefinitionContent)
- .then(response => {
+ .then(() => {
+ this.childModal.dismiss();
Swal.fire({
text: 'Saved successfully!',
confirmButtonColor: '#7cd1f9'
diff --git a/gateway-admin-ui/admin-ui/app/service-definition/rewrite.rules.ts b/gateway-admin-ui/admin-ui/app/service-definition/rewrite.rules.ts
deleted file mode 100644
index d6629811c..000000000
--- a/gateway-admin-ui/admin-ui/app/service-definition/rewrite.rules.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {RewriteRule} from './rewrite.rule';
-
-export class RewriteRules {
- rules: RewriteRule[];
-}
diff --git a/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.css b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.css
new file mode 100644
index 000000000..f8e5a066b
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.css
@@ -0,0 +1,76 @@
+.code-editor-scroll {
+ height: 65vh;
+ overflow: auto;
+ background-color: #272822;
+ border-radius: 4px 4px 0 0;
+}
+
+.code-editor-wrapper {
+ display: flex;
+ align-items: stretch;
+ min-height: 100%;
+}
+
+.code-editor-gutter {
+ min-width: 40px;
+ padding: 10px 8px 10px 0;
+ background-color: #1e1f1c;
+ text-align: right;
+ user-select: none;
+ border-right: 1px solid #3e3d32;
+ flex-shrink: 0;
+}
+
+.line-number {
+ font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
+ font-size: 12px;
+ line-height: 18px;
+ color: #75715e;
+}
+
+.code-editor {
+ flex: 1;
+ padding: 10px 12px;
+ background-color: #272822;
+ color: #f8f8f2;
+ border: none;
+ outline: none;
+ resize: none;
+ font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
+ font-size: 12px;
+ line-height: 18px;
+ tab-size: 4;
+ white-space: pre;
+ overflow: hidden;
+}
+
+.code-editor::selection {
+ background-color: #49483e;
+}
+
+.editor-toolbar {
+ padding: 8px 12px;
+ background-color: #1e1f1c;
+ border-top: 1px solid #3e3d32;
+ border-radius: 0 0 4px 4px;
+}
+
+.editor-toolbar .btn {
+ background-color: #3e3d32;
+ border-color: #555;
+ color: #f8f8f2;
+}
+
+.editor-toolbar .btn:hover:not(:disabled) {
+ background-color: #555;
+ border-color: #75715e;
+}
+
+.editor-toolbar .btn:disabled {
+ opacity: 0.4;
+}
+
+.editor-toolbar .material-icons {
+ color: #f8f8f2;
+ font-size: 16px;
+}
diff --git a/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.html b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.html
new file mode 100644
index 000000000..969df3dc5
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.html
@@ -0,0 +1,65 @@
+<div class="panel panel-default" style="margin-top: 10px;">
+ <div class="panel-heading">
+ <h4 class="panel-title">{{title}} <span class="pull-right">{{titleSuffix}}</span></h4>
+ </div>
+ @if (serviceDefinitionContent) {
+ <div class="panel-body" style="padding: 0;">
+ <div class="code-editor-scroll">
+ <div class="code-editor-wrapper">
+ <div class="code-editor-gutter">
+ @for (line of getLineNumbers(); track line) {
+ <div class="line-number">{{line}}</div>
+ }
+ </div>
+ <textarea
+ class="code-editor"
+ [(ngModel)]="serviceDefinitionContent"
+ [attr.rows]="getLineNumbers().length || 1"
+ spellcheck="false"
+ (input)="onChange($event.target.value)">
+ </textarea>
+ </div>
+ </div>
+ <div class="editor-toolbar">
+ <button id="deleteServiceDefinition" (click)="deleteServiceDefConfirmModal.open('sm')"
+ class="btn btn-default btn-sm" title="Delete Service Definition" type="submit">
+ <span class="material-icons">delete</span>
+ </button>
+ <button id="updateServiceDefinition" (click)="updateServiceDefConfirmModal.open('sm')"
+ class="btn btn-default btn-sm pull-right" title="Save Service Definition" type="submit">
+ <span class="material-icons">save</span>
+ </button>
+ </div>
+ </div>
+ }
+</div>
+<app-modal (onClose)="updateServiceDefinition()" #updateServiceDefConfirmModal>
+ <div class="modal-header">
+ <h4 class="modal-title">Updating Service Definition {{titleSuffix}}</h4>
+ <button type="button" class="btn-close" (click)="updateServiceDefConfirmModal.dismiss()"></button>
+ </div>
+ <div class="modal-body">
+ Are you sure you want to update this service definition?
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default btn-sm"
+ (click)="updateServiceDefConfirmModal.dismiss()">Cancel</button>
+ <button type="button" class="btn btn-primary btn-sm"
+ (click)="updateServiceDefConfirmModal.close()">Ok</button>
+ </div>
+</app-modal>
+<app-modal (onClose)="deleteServiceDefinition()" #deleteServiceDefConfirmModal>
+ <div class="modal-header">
+ <h4 class="modal-title">Deleting Service Definition {{titleSuffix}}</h4>
+ <button type="button" class="btn-close" (click)="deleteServiceDefConfirmModal.dismiss()"></button>
+ </div>
+ <div class="modal-body">
+ Are you sure you want to delete this service definition?
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default btn-sm"
+ (click)="deleteServiceDefConfirmModal.dismiss()">Cancel</button>
+ <button type="button" class="btn btn-primary btn-sm"
+ (click)="deleteServiceDefConfirmModal.close()">Ok</button>
+ </div>
+</app-modal>
diff --git a/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.ts b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.ts
index 8d17fa34a..d3c8b8918 100644
--- a/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.ts
+++ b/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition-detail.component.ts
@@ -14,74 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {Component, OnInit, ViewChild} from '@angular/core';
-import {BsModalComponent} from 'ng2-bs3-modal';
-import Swal from 'sweetalert2';
+import {Component, OnInit} from '@angular/core';
+import {FormsModule} from '@angular/forms';
+import Swal from 'sweetalert2/dist/sweetalert2.esm.all.js';
-import {ServiceDefinition} from './servicedefinition';
-import {ServiceDefinitionService} from './servicedefinition.service';
-import {ResourceTypesService} from '../resourcetypes/resourcetypes.service';
-
-import 'brace/theme/monokai';
-import 'brace/mode/xml';
+import {ServiceDefinition} from '../model/servicedefinition';
+import {ServiceDefinitionService} from '../service/servicedefinition.service';
+import {ResourceTypesService} from '../service/resourcetypes.service';
+import {ModalComponent} from '../utils/modal.component';
@Component({
selector: 'app-servicedefinition-detail',
- template: `
- <div class="panel panel-default">
- <div class="panel-heading">
- <h4 class="panel-title">{{title}} <span class="pull-right">{{titleSuffix}}</span></h4>
- </div>
- <div *ngIf="serviceDefinitionContent" class="panel-body">
- <ace-editor
- [(text)]="serviceDefinitionContent"
- [mode]="'xml'"
- [options]="options"
- [theme]="theme"
- style="min-height: 430px; width:100%; overflow: auto;"
- (textChanged)="onChange($event)">
- </ace-editor>
- <div class="panel-footer">
- <button id="deleteServiceDefinition" (click)="deleteServiceDefConfirmModal.open('sm')"
- class="btn btn-default btn-sm" type="submit">
- <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
- </button>
- <button id="updateServiceDefinition" (click)="updateServiceDefConfirmModal.open('sm')"
- class="btn btn-default btn-sm pull-right" type="submit">
- <span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>
- </button>
- </div>
- </div>
- </div>
- <bs-modal (onClose)="updateServiceDefinition()" #updateServiceDefConfirmModal>
- <bs-modal-header [showDismiss]="true">
- <h4 class="modal-title">Updating Service Definition {{titleSuffix}}</h4>
- </bs-modal-header>
- <bs-modal-body>
- Are you sure you want to update this service definition?
- </bs-modal-body>
- <bs-modal-footer>
- <button type="button" class="btn btn-default btn-sm" data-dismiss="updateServiceDefConfirmModal"
- (click)="updateServiceDefConfirmModal.dismiss()">Cancel
- </button>
- <button type="button" class="btn btn-primary btn-sm" (click)="updateServiceDefConfirmModal.close()">Ok</button>
- </bs-modal-footer>
- </bs-modal>
- <bs-modal (onClose)="deleteServiceDefinition()" #deleteServiceDefConfirmModal>
- <bs-modal-header [showDismiss]="true">
- <h4 class="modal-title">Deleting Service Definition {{titleSuffix}}</h4>
- </bs-modal-header>
- <bs-modal-body>
- Are you sure you want to delete this service definition?
- </bs-modal-body>
- <bs-modal-footer>
- <button type="button" class="btn btn-default btn-sm" data-dismiss="deleteServiceDefConfirmModal"
- (click)="deleteServiceDefConfirmModal.dismiss()">Cancel
- </button>
- <button type="button" class="btn btn-primary btn-sm" (click)="deleteServiceDefConfirmModal.close()">Ok</button>
- </bs-modal-footer>
- </bs-modal>
- `
+ templateUrl: './servicedefinition-detail.component.html',
+ styleUrls: ['./servicedefinition-detail.component.css'],
+ imports: [FormsModule, ModalComponent]
})
export class ServiceDefinitionDetailComponent implements OnInit {
@@ -90,13 +36,6 @@ export class ServiceDefinitionDetailComponent implements OnInit {
titleSuffix: string;
serviceDefinitionContent: string;
changedServiceDefinitionContent: string;
- theme: String = 'monokai';
- options: any = {useWorker: false, printMargin: false};
-
- @ViewChild('editor') editor;
-
- @ViewChild('deleteServiceDefConfirmModal')
- deleteServiceDefConfirmModal: BsModalComponent;
constructor(private serviceDefinitionService: ServiceDefinitionService, private resourceTypesService: ResourceTypesService) {
}
@@ -105,6 +44,14 @@ export class ServiceDefinitionDetailComponent implements OnInit {
this.serviceDefinitionService.selectedServiceDefinition$.subscribe(value => this.populateContent(value));
}
+ getLineNumbers(): number[] {
+ if (!this.serviceDefinitionContent) {
+ return [];
+ }
+ const count = this.serviceDefinitionContent.split('\n').length;
+ return Array.from({length: count}, (_, i) => i + 1);
+ }
+
setTitleSuffix(value: string) {
this.titleSuffix = value;
}
@@ -125,7 +72,7 @@ export class ServiceDefinitionDetailComponent implements OnInit {
updateServiceDefinition() {
this.serviceDefinitionService.updateServiceDefinition(this.changedServiceDefinitionContent ? this.changedServiceDefinitionContent
: this.serviceDefinitionContent)
- .then(response => {
+ .then(() => {
Swal.fire({
text: 'Updated successfully!',
confirmButtonColor: '#7cd1f9'
@@ -137,7 +84,7 @@ export class ServiceDefinitionDetailComponent implements OnInit {
deleteServiceDefinition() {
this.serviceDefinitionService.deleteServiceDefinition(this.serviceDefinition)
- .then(response => {
+ .then(() => {
Swal.fire({
text: 'Deleted successfully!',
confirmButtonColor: '#7cd1f9'
diff --git a/gateway-admin-ui/admin-ui/app/gateway-version.service.ts b/gateway-admin-ui/admin-ui/app/service/gateway-version.service.ts
similarity index 77%
rename from gateway-admin-ui/admin-ui/app/gateway-version.service.ts
rename to gateway-admin-ui/admin-ui/app/service/gateway-version.service.ts
index 895db02f8..490d9a5a4 100644
--- a/gateway-admin-ui/admin-ui/app/gateway-version.service.ts
+++ b/gateway-admin-ui/admin-ui/app/service/gateway-version.service.ts
@@ -15,13 +15,12 @@
* limitations under the License.
*/
import {Injectable} from '@angular/core';
-import {HttpClient, HttpHeaders} from '@angular/common/http';
+import { HttpClient, HttpHeaders } from '@angular/common/http';
+import {firstValueFrom} from 'rxjs';
-import 'rxjs/add/operator/toPromise';
+import {GatewayVersion} from '../model/gateway-version';
-import {GatewayVersion} from './gateway-version';
-
-@Injectable()
+@Injectable({providedIn: 'root'})
export class GatewayVersionService {
private apiUrl = window.location.pathname.replace(new RegExp('admin-ui/.*'), 'api/v1/');
private versionUrl = this.apiUrl + 'version';
@@ -29,15 +28,11 @@ export class GatewayVersionService {
constructor(private http: HttpClient) {
}
- getVersion(): Promise<GatewayVersion> {
+ async getVersion(): Promise<GatewayVersion> {
let headers = new HttpHeaders();
headers = this.addHeaders(headers);
- return this.http.get(this.versionUrl, {headers: headers})
- .toPromise()
- .then(response => {
- return response['ServerVersion'] as GatewayVersion;
- })
- .catch(this.handleError);
+ const response = await firstValueFrom(this.http.get(this.versionUrl, {headers: headers}));
+ return response['ServerVersion'] as GatewayVersion;
}
addHeaders(headers: HttpHeaders) {
diff --git a/gateway-admin-ui/admin-ui/app/resource/resource.service.ts b/gateway-admin-ui/admin-ui/app/service/resource.service.ts
similarity index 80%
rename from gateway-admin-ui/admin-ui/app/resource/resource.service.ts
rename to gateway-admin-ui/admin-ui/app/service/resource.service.ts
index 0b1bbdd65..ce4cfbda7 100644
--- a/gateway-admin-ui/admin-ui/app/resource/resource.service.ts
+++ b/gateway-admin-ui/admin-ui/app/service/resource.service.ts
@@ -15,14 +15,14 @@
* limitations under the License.
*/
import {Injectable} from '@angular/core';
-import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
-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()
+import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
+import { Subject, firstValueFrom } from 'rxjs';
+import {Resource} from '../model/resource';
+import {ProviderConfig} from '../model/provider-config';
+import {Descriptor} from '../model/descriptor';
+import * as yaml from 'js-yaml';
+
+@Injectable({providedIn: 'root'})
export class ResourceService {
discoveryTypes: Array<string>;
@@ -39,11 +39,6 @@ export class ResourceService {
selectedResourceSource = new Subject<Resource>();
selectedResource$ = this.selectedResourceSource.asObservable();
- changedResourceSource = new Subject<string>();
- changedResource$ = this.changedResourceSource.asObservable();
-
- changedProviderConfigurationSource = new Subject<Array<ProviderConfig>>();
- changedProviderConfiguration$ = this.changedProviderConfigurationSource.asObservable();
constructor(private http: HttpClient) {
this.initSupportedDiscoveryTypes();
@@ -51,7 +46,6 @@ export class ResourceService {
initSupportedDiscoveryTypes(): void {
if (this.discoveryTypes == null || this.discoveryTypes.length === 0) {
- let headers = this.addJsonHeaders(new HttpHeaders());
this.getServiceDiscoveryResources()
.then(response => this.discoveryTypes = response.knoxServiceDiscoveries.knoxServiceDiscovery.map(sd => sd.type))
.catch((err: HttpErrorResponse) => {
@@ -67,7 +61,7 @@ export class ResourceService {
getServiceDiscoveryResources(): Promise<any> {
let headers = this.addJsonHeaders(new HttpHeaders());
- return this.http.get(this.serviceDiscoveriesUrl, {headers: headers}).toPromise();
+ return firstValueFrom(this.http.get(this.serviceDiscoveriesUrl, {headers: headers}));
}
getResources(resType: string): Promise<Resource[]> {
@@ -89,61 +83,53 @@ export class ResourceService {
getProviderConfigResources(): Promise<Resource[]> {
let headers = this.addJsonHeaders(new HttpHeaders());
- return this.http.get(this.providersUrl, {headers: headers})
- .toPromise()
+ return firstValueFrom(this.http.get(this.providersUrl, {headers: headers}))
.then(response => response['items'] as Resource[])
.catch((err: HttpErrorResponse) => {
console.debug('ResourceService --> getProviderConfigResources() --> error: HTTP ' + err.status + ' ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
getDescriptorResources(): Promise<Resource[]> {
let headers = this.addJsonHeaders(new HttpHeaders());
- return this.http.get(this.descriptorsUrl, {headers: headers})
- .toPromise()
+ return firstValueFrom(this.http.get(this.descriptorsUrl, {headers: headers}))
.then(response => response['items'] as Resource[])
.catch((err: HttpErrorResponse) => {
console.debug('ResourceService --> getDescriptorResources() --> error: HTTP ' + err.status + ' ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
getTopologyResources(): Promise<Resource[]> {
let headers = this.addJsonHeaders(new HttpHeaders());
- return this.http.get(this.topologiesUrl, {headers: headers})
- .toPromise()
+ return firstValueFrom(this.http.get(this.topologiesUrl, {headers: headers}))
.then(response => response['topologies'].topology as Resource[])
.catch((err: HttpErrorResponse) => {
console.debug('ResourceService --> getTopologyResources() --> error: HTTP ' + err.status + ' ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
getServiceDefinitionResources(): Promise<Resource[]> {
let headers = this.addJsonHeaders(new HttpHeaders());
- return this.http.get(this.serviceDefinitionsUrl + '?serviceOnly=true', {headers: headers})
- .toPromise()
+ return firstValueFrom(this.http.get(this.serviceDefinitionsUrl + '?serviceOnly=true', {headers: headers}))
.then(response => response['serviceDefinitions'].serviceDefinition as Resource[])
.catch((err: HttpErrorResponse) => {
console.debug('ResourceService --> getServiceDefinitionResources() --> error: HTTP ' + err.status + ' ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
@@ -154,11 +140,9 @@ export class ResourceService {
href = this.serviceDefinitionsUrl + '/' + res.service['name'] + '/' + res.service['role'] + '/' + res.service['version']
+ '?serviceOnly=true';
}
- let headers = new HttpHeaders();
- headers = (resType === 'Topologies' || resType === 'Service Definitions') ? this.addXmlHeaders(headers)
- : this.addHeaders(headers, res.name);
- return this.http.get(href, {headers: headers, responseType: 'text'})
- .toPromise()
+ let headers = (resType === 'Topologies' || resType === 'Service Definitions') ? this.addXmlHeaders(new HttpHeaders())
+ : this.addHeaders(new HttpHeaders(), res.name);
+ return firstValueFrom(this.http.get(href, {headers: headers, responseType: 'text'}))
.then(response => {
console.debug('ResourceService --> Loading resource ' + res.name + ' :\n' + response);
return response;
@@ -167,9 +151,8 @@ export class ResourceService {
console.debug('ResourceService --> getResource() ' + res.name + '\n error: ' + err.status + ' ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
} else {
return Promise.resolve(null);
@@ -178,52 +161,41 @@ export class ResourceService {
saveResource(resource: Resource, content: string): Promise<string> {
let headers = this.addHeaders(new HttpHeaders(), resource.name);
-
console.debug('ResourceService --> Persisting ' + resource.name + '\n' + content);
-
- return this.http.put(resource.href, content, {headers: headers})
- .toPromise()
+ return firstValueFrom(this.http.put(resource.href, content, {headers: headers, responseType: 'text'}))
.then(() => content)
.catch((err: HttpErrorResponse) => {
console.debug('ResourceService --> saveResource() ' + resource.name + '\n error: ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
createResource(resType: string, resource: Resource, content: string): Promise<string> {
let headers = this.addHeaders(new HttpHeaders(), resource.name);
-
let url = ((resType === 'Descriptors') ? this.descriptorsUrl : this.providersUrl) + '/' + resource.name;
- return this.http.put(url, content, {headers: headers})
- .toPromise()
+ return firstValueFrom(this.http.put(url, content, {headers: headers, responseType: 'text'}))
.then(() => content)
.catch((err: HttpErrorResponse) => {
console.debug('ResourceService --> createResource() --> ' + resource.name + '\n error: ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
deleteResource(href: string): Promise<string> {
let headers = this.addJsonHeaders(new HttpHeaders());
-
- return this.http.delete(href, {headers: headers})
- .toPromise()
- .then(response => response)
+ return firstValueFrom(this.http.delete(href, {headers: headers, responseType: 'text'}))
.catch((err: HttpErrorResponse) => {
console.debug('ResourceService --> deleteResource() --> ' + href + '\n error: ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
@@ -278,8 +250,7 @@ export class ResourceService {
break;
}
case 'yaml': {
- let yaml = require('js-yaml');
- serialized = '---\n' + yaml.safeDump(tmp);
+ serialized = '---\n' + yaml.dump(tmp);
break;
}
}
@@ -300,7 +271,6 @@ export class ResourceService {
break;
}
case 'yaml': {
- let yaml = require('js-yaml');
serialized = '---\n' + yaml.dump(tmp);
break;
}
@@ -361,13 +331,6 @@ export class ResourceService {
this.selectedResourceSource.next(value);
}
- resourceChanged(value: string) {
- this.changedResourceSource.next(value);
- }
-
- providerConfigurationChanged(pc: Array<ProviderConfig>) {
- this.changedProviderConfigurationSource.next(pc);
- }
public getResourceDisplayName(res: Resource): string {
if (res) {
@@ -385,13 +348,6 @@ export class ResourceService {
return Promise.reject(error);
}
- private logHeaders(headers: HttpHeaders) {
- let debugMsg = 'ResourceService --> Request headers:\n';
- headers.keys().forEach(key => {
- debugMsg += ' ' + key + '=' + headers.get(key) + '\n';
- });
- console.debug(debugMsg);
- }
}
diff --git a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.service.ts b/gateway-admin-ui/admin-ui/app/service/resourcetypes.service.ts
similarity index 95%
rename from gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.service.ts
rename to gateway-admin-ui/admin-ui/app/service/resourcetypes.service.ts
index cc2dc4f0a..dd3785eec 100644
--- a/gateway-admin-ui/admin-ui/app/resourcetypes/resourcetypes.service.ts
+++ b/gateway-admin-ui/admin-ui/app/service/resourcetypes.service.ts
@@ -15,9 +15,9 @@
* limitations under the License.
*/
import {Injectable} from '@angular/core';
-import {Subject} from 'rxjs/Subject';
+import { Subject } from 'rxjs';
-@Injectable()
+@Injectable({providedIn: 'root'})
export class ResourceTypesService {
resourceTypes = ['Provider Configurations', 'Descriptors', 'Topologies', 'Service Definitions'];
diff --git a/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.service.ts b/gateway-admin-ui/admin-ui/app/service/servicedefinition.service.ts
similarity index 53%
rename from gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.service.ts
rename to gateway-admin-ui/admin-ui/app/service/servicedefinition.service.ts
index 5202d3515..5e8898d7f 100644
--- a/gateway-admin-ui/admin-ui/app/service-definition/servicedefinition.service.ts
+++ b/gateway-admin-ui/admin-ui/app/service/servicedefinition.service.ts
@@ -15,119 +15,79 @@
* limitations under the License.
*/
import {Injectable} from '@angular/core';
-import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
-import {RestURLBuilder} from 'rest-url-builder';
-import Swal from 'sweetalert2';
+import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
+import Swal from 'sweetalert2/dist/sweetalert2.esm.all.js';
-import 'rxjs/add/operator/toPromise';
-import {Subject} from 'rxjs/Subject';
+import { Subject, firstValueFrom } from 'rxjs';
-import {ServiceDefinition} from './servicedefinition';
+import {ServiceDefinition} from '../model/servicedefinition';
- @Injectable()
+ @Injectable({providedIn: 'root'})
export class ServiceDefinitionService {
apiUrl = window.location.pathname.replace(new RegExp('admin-ui/.*'), 'api/v1/');
serviceDefinitionsBaseUrl = this.apiUrl + 'servicedefinitions';
- serviceDefinitionUrlTemplate = this.serviceDefinitionsBaseUrl + '/:service/:role/:version';
selectedServiceDefinitionSource = new Subject<ServiceDefinition>();
selectedServiceDefinition$ = this.selectedServiceDefinitionSource.asObservable();
- urlBuilder = new RestURLBuilder();
constructor(private http: HttpClient) {
}
- getServiceDefinitions(): Promise<ServiceDefinition[]> {
- let headers = new HttpHeaders();
- headers = this.addXmlHeaders(headers);
- return this.http.get(this.serviceDefinitionsBaseUrl, { headers: headers})
- .toPromise()
- .then(response => response['serviceDefinitions'].serviceDefinition as ServiceDefinition[])
+getServiceDefinitionXml(serviceDefinition: ServiceDefinition): Promise<string> {
+ let headers = this.addXmlHeaders(new HttpHeaders());
+ let url = this.serviceDefinitionsBaseUrl + '/' + serviceDefinition.service
+ + '/' + serviceDefinition.role + '/' + serviceDefinition.version;
+ return firstValueFrom(this.http.get(url, {headers: headers, responseType: 'text'}))
.catch((err: HttpErrorResponse) => {
- console.debug('ServiceDefinitionService --> getServiceDefinitions() --> ' + this.serviceDefinitionsBaseUrl
+ console.debug('ServiceDefinitionService --> getServiceDefinitionXml() --> ' + url
+ '\n error: ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
- }
- });
- }
-
- getServiceDefinitionXml(serviceDefinition: ServiceDefinition) {
- let headers = new HttpHeaders();
- headers = this.addXmlHeaders(headers);
- let urlBuilder = this.urlBuilder.buildRestURL(this.serviceDefinitionUrlTemplate);
- urlBuilder.setNamedParameter('service', serviceDefinition.service);
- urlBuilder.setNamedParameter('role', serviceDefinition.role);
- urlBuilder.setNamedParameter('version', serviceDefinition.version);
- return this.http.get(urlBuilder.get(), {headers: headers, responseType: 'text'})
- .toPromise()
- .then(response => response)
- .catch((err: HttpErrorResponse) => {
- console.debug('ServiceDefinitionService --> getServiceDefinitionXml() --> ' + urlBuilder.get()
- + '\n error: ' + err.message);
- if (err.status === 401) {
- window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
saveNewServiceDefinition(xml: string): Promise<string> {
- let xheaders = new HttpHeaders();
- xheaders = this.addXmlHeaders(xheaders);
+ let xheaders = this.addXmlHeaders(new HttpHeaders());
let serviceDefintionXml = xml.replace('<serviceDefinitions>', '').replace('</serviceDefinitions>', '');
- return this.http.post(this.serviceDefinitionsBaseUrl, serviceDefintionXml, {headers: xheaders, responseType: 'text'})
- .toPromise()
- .then(response => response)
+ return firstValueFrom(
+ this.http.post(this.serviceDefinitionsBaseUrl, serviceDefintionXml, {headers: xheaders, responseType: 'text'}))
.catch((err: HttpErrorResponse) => {
console.debug('ServiceDefinitionService --> saveNewServiceDefinition() --> ' + this.serviceDefinitionsBaseUrl
+ '\n error: ' + err.status + ' ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
updateServiceDefinition(xml: string): Promise<string> {
- let xheaders = new HttpHeaders();
- xheaders = this.addXmlHeaders(xheaders);
+ let xheaders = this.addXmlHeaders(new HttpHeaders());
let serviceDefintionXml = xml.replace('<serviceDefinitions>', '').replace('</serviceDefinitions>', '');
- return this.http.put(this.serviceDefinitionsBaseUrl, serviceDefintionXml, {headers: xheaders, responseType: 'text'})
- .toPromise()
- .then(response => response)
+ return firstValueFrom(this.http.put(this.serviceDefinitionsBaseUrl, serviceDefintionXml, {headers: xheaders, responseType: 'text'}))
.catch((err: HttpErrorResponse) => {
console.debug('ServiceDefinitionService --> updateServiceDefinition() --> ' + this.serviceDefinitionsBaseUrl
+ '\n error: ' + err.status + ' ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
deleteServiceDefinition(serviceDefinition: ServiceDefinition): Promise<string> {
- let xheaders = new HttpHeaders();
- xheaders = this.addXmlHeaders(xheaders);
- let urlBuilder = this.urlBuilder.buildRestURL(this.serviceDefinitionUrlTemplate);
- urlBuilder.setNamedParameter('service', serviceDefinition.service);
- urlBuilder.setNamedParameter('role', serviceDefinition.role);
- urlBuilder.setNamedParameter('version', serviceDefinition.version);
- return this.http.delete(urlBuilder.get(), {headers: xheaders, responseType: 'text'})
- .toPromise()
- .then(response => response)
+ let xheaders = this.addXmlHeaders(new HttpHeaders());
+ let url = this.serviceDefinitionsBaseUrl + '/' + serviceDefinition.service
+ + '/' + serviceDefinition.role + '/' + serviceDefinition.version;
+ return firstValueFrom(this.http.delete(url, {headers: xheaders, responseType: 'text'}))
.catch((err: HttpErrorResponse) => {
- console.debug('ServiceDefinitionService --> deleteServiceDefinition() --> ' + urlBuilder.get()
+ console.debug('ServiceDefinitionService --> deleteServiceDefinition() --> ' + url
+ '\n error: ' + err.status + ' ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
@@ -135,11 +95,6 @@ export class ServiceDefinitionService {
this.selectedServiceDefinitionSource.next(value);
}
- addJsonHeaders(headers: HttpHeaders): HttpHeaders {
- return this.addCsrfHeaders(headers.append('Accept', 'application/json')
- .append('Content-Type', 'application/json'));
- }
-
addXmlHeaders(headers: HttpHeaders): HttpHeaders {
return this.addCsrfHeaders(headers.append('Accept', 'application/xml')
.append('Content-Type', 'application/xml'));
diff --git a/gateway-admin-ui/admin-ui/app/sessionInformation/session.information.service.ts b/gateway-admin-ui/admin-ui/app/service/session.information.service.ts
similarity index 83%
rename from gateway-admin-ui/admin-ui/app/sessionInformation/session.information.service.ts
rename to gateway-admin-ui/admin-ui/app/service/session.information.service.ts
index 95a3cdc8f..50d4af3a3 100644
--- a/gateway-admin-ui/admin-ui/app/sessionInformation/session.information.service.ts
+++ b/gateway-admin-ui/admin-ui/app/service/session.information.service.ts
@@ -15,13 +15,13 @@
* limitations under the License.
*/
import {Injectable} from '@angular/core';
-import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
-import Swal from 'sweetalert2';
+import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
+import {firstValueFrom} from 'rxjs';
+import Swal from 'sweetalert2/dist/sweetalert2.esm.all.js';
-import 'rxjs/add/operator/toPromise';
-import {SessionInformation} from './session.information';
+import {SessionInformation} from '../model/session-information';
-@Injectable()
+@Injectable({providedIn: 'root'})
export class SessionInformationService {
pathParts = window.location.pathname.split('/');
topologyContext = '/' + this.pathParts[1] + '/' + this.pathParts[2] + '/';
@@ -30,18 +30,15 @@ export class SessionInformationService {
constructor(private http: HttpClient) {}
getSessionInformation(): Promise<SessionInformation> {
- let headers = new HttpHeaders();
- headers = this.addJsonHeaders(headers);
- return this.http.get(this.sessionUrl, { headers: headers})
- .toPromise()
+ let headers = this.addJsonHeaders(new HttpHeaders());
+ return firstValueFrom(this.http.get(this.sessionUrl, {headers: headers}))
.then(response => response['sessioninfo'] as SessionInformation)
.catch((err: HttpErrorResponse) => {
console.debug('HomepageService --> getSessionInformation() --> ' + this.sessionUrl + '\n error: ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
diff --git a/gateway-admin-ui/admin-ui/app/topology.service.ts b/gateway-admin-ui/admin-ui/app/service/topology.service.ts
similarity index 67%
rename from gateway-admin-ui/admin-ui/app/topology.service.ts
rename to gateway-admin-ui/admin-ui/app/service/topology.service.ts
index a4831a63d..0c0fc1211 100644
--- a/gateway-admin-ui/admin-ui/app/topology.service.ts
+++ b/gateway-admin-ui/admin-ui/app/service/topology.service.ts
@@ -15,13 +15,12 @@
* limitations under the License.
*/
import {Injectable} from '@angular/core';
-import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
+import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
-import 'rxjs/add/operator/toPromise';
-import {Subject} from 'rxjs/Subject';
-import {Topology} from './topology';
+import { Subject, firstValueFrom } from 'rxjs';
+import {Topology} from '../model/topology';
-@Injectable()
+@Injectable({providedIn: 'root'})
export class TopologyService {
apiUrl = window.location.pathname.replace(new RegExp('admin-ui/.*'), 'api/v1/');
topologiesUrl = this.apiUrl + 'topologies';
@@ -34,89 +33,66 @@ export class TopologyService {
}
getTopologies(): Promise<Topology[]> {
- let headers = new HttpHeaders();
- headers = this.addJsonHeaders(headers);
- return this.http.get(this.topologiesUrl, {
- headers: headers
- })
- .toPromise()
+ let headers = this.addJsonHeaders(new HttpHeaders());
+ return firstValueFrom(this.http.get(this.topologiesUrl, {headers: headers}))
.then(response => response['topologies'].topology as Topology[])
.catch((err: HttpErrorResponse) => {
- console.debug('TopologyService --> getTopologies() --> ' + '\n error: ' + err.message);
+ console.debug('TopologyService --> getTopologies() --> \n error: ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
getTopology(href: string): Promise<string> {
- let headers = new HttpHeaders();
- headers = this.addXmlHeaders(headers);
- return this.http.get(href, {
- headers: headers, responseType: 'text'
- })
- .toPromise()
- .then(response => response)
+ let headers = this.addXmlHeaders(new HttpHeaders());
+ return firstValueFrom(this.http.get(href, {headers: headers, responseType: 'text'}))
.catch((err: HttpErrorResponse) => {
console.debug('TopologyService --> getTopology() --> ' + href + '\n error: ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
saveTopology(url: string, xml: string): Promise<string> {
- let xheaders = new HttpHeaders();
- xheaders = this.addXmlHeaders(xheaders);
- return this.http.put(url, xml, {headers: xheaders, responseType: 'text'})
- .toPromise()
+ let xheaders = this.addXmlHeaders(new HttpHeaders());
+ return firstValueFrom(this.http.put(url, xml, {headers: xheaders, responseType: 'text'}))
.then(() => xml)
.catch((err: HttpErrorResponse) => {
- console.debug('TopologyService --> getTopology() --> \n error: ' + err.status + ' ' + err.message);
+ console.debug('TopologyService --> saveTopology() --> \n error: ' + err.status + ' ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
createTopology(name: string, xml: string): Promise<string> {
- let xheaders = new HttpHeaders();
- xheaders = this.addXmlHeaders(xheaders);
+ let xheaders = this.addXmlHeaders(new HttpHeaders());
let url = this.topologiesUrl + '/' + name;
- return this.http.put(url, xml, {headers: xheaders, responseType: 'text'})
- .toPromise()
+ return firstValueFrom(this.http.put(url, xml, {headers: xheaders, responseType: 'text'}))
.then(() => xml)
.catch((err: HttpErrorResponse) => {
console.debug('TopologyService --> createTopology() --> \n error: ' + err.status + ' ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
deleteTopology(href: string): Promise<string> {
- let headers = new HttpHeaders();
- headers = this.addJsonHeaders(headers);
- return this.http.delete(href, {
- headers: headers, responseType: 'text'
- })
- .toPromise()
- .then(response => response)
+ let headers = this.addJsonHeaders(new HttpHeaders());
+ return firstValueFrom(this.http.delete(href, {headers: headers, responseType: 'text'}))
.catch((err: HttpErrorResponse) => {
- console.debug('TopologyService --> getTopology() --> ' + href + '\n error: ' + err.message);
+ console.debug('TopologyService --> deleteTopology() --> ' + href + '\n error: ' + err.message);
if (err.status === 401) {
window.location.assign(document.location.pathname);
- } else {
- return this.handleError(err);
}
+ return this.handleError(err);
});
}
diff --git a/gateway-admin-ui/admin-ui/app/sessionInformation/session.information.component.html b/gateway-admin-ui/admin-ui/app/session-information/session.information.component.html
similarity index 100%
rename from gateway-admin-ui/admin-ui/app/sessionInformation/session.information.component.html
rename to gateway-admin-ui/admin-ui/app/session-information/session.information.component.html
diff --git a/gateway-admin-ui/admin-ui/app/sessionInformation/session.information.component.ts b/gateway-admin-ui/admin-ui/app/session-information/session.information.component.ts
similarity index 91%
rename from gateway-admin-ui/admin-ui/app/sessionInformation/session.information.component.ts
rename to gateway-admin-ui/admin-ui/app/session-information/session.information.component.ts
index e21e61264..9f7bd7bb0 100644
--- a/gateway-admin-ui/admin-ui/app/sessionInformation/session.information.component.ts
+++ b/gateway-admin-ui/admin-ui/app/session-information/session.information.component.ts
@@ -16,10 +16,12 @@
*/
import {Component, OnInit, Pipe, PipeTransform} from '@angular/core';
import {DomSanitizer} from '@angular/platform-browser';
-import {SessionInformationService} from './session.information.service';
-import {SessionInformation} from './session.information';
+import {SessionInformationService} from '../service/session.information.service';
+import {SessionInformation} from '../model/session-information';
-@Pipe({ name: 'safeHtml' })
+@Pipe({
+ name: 'safeHtml'
+})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
@@ -31,13 +33,12 @@ export class SafeHtmlPipe implements PipeTransform {
@Component({
selector: 'app-session-information',
templateUrl: './session.information.component.html',
- providers: [SessionInformationService]
+ imports: [SafeHtmlPipe]
})
export class SessionInformationComponent implements OnInit {
sessionInformation: SessionInformation;
- logoutSupported = true;
constructor(private sessionInformationService: SessionInformationService) {
this['showSessionInformation'] = true;
diff --git a/gateway-admin-ui/admin-ui/app/topology-detail.component.ts b/gateway-admin-ui/admin-ui/app/topology-detail.component.ts
deleted file mode 100644
index f1e4f98be..000000000
--- a/gateway-admin-ui/admin-ui/app/topology-detail.component.ts
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
-import {Topology} from './topology';
-import {TopologyService} from './topology.service';
-import {ResourceTypesService} from './resourcetypes/resourcetypes.service';
-import {BsModalComponent} from 'ng2-bs3-modal';
-import {ValidationUtils} from './utils/validation-utils';
-import * as ace from 'ace-builds';
-
-@Component({
- selector: 'app-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"> Read Only (generated file) </span> <span
- class="pull-right">{{titleSuffix}}</span></h4>
- </div>
- <div [style.display]="getEditorVisibility()" class="panel-body">
- <ace-editor
- #editor
- [(text)]="topologyContent"
- [options]="options"
- [theme]="theme"
- [readOnly]="!showEditOptions"
- style="min-height: 430px; width:100%; overflow: auto;"
- (textChanged)="onChange($event)">
- </ace-editor>
- <div 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" *ngIf="showEditOptions" (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" *ngIf="showEditOptions" (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>
- <bs-modal (onClose)="createTopology()" #duplicateModal>
- <bs-modal-header [showDismiss]="true">
- <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]="!isValidNewTopologyName()"
- (click)="duplicateModal.close()">Ok
- </button>
- </bs-modal-footer>
- </bs-modal>
- <bs-modal (onClose)="deleteTopology()" #deleteConfirmModal>
- <bs-modal-header [showDismiss]="true">
- <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, AfterViewInit {
- title = 'Topology Detail';
- titleSuffix: string;
- topology: Topology;
- topologyContent: string;
- changedTopology: string;
- newTopologyName: string;
- showEditOptions = true;
- theme: String = 'monokai';
- options: any = {useWorker: false, printMargin: false};
-
- @ViewChild('duplicateModal')
- duplicateModal: BsModalComponent;
-
- @ViewChild('deleteConfirmModal')
- deleteConfirmModal: BsModalComponent;
-
- @ViewChild('editor')
- editor: ElementRef<HTMLElement>;
-
- constructor(private topologyService: TopologyService, private resourceTypesService: ResourceTypesService) {
- }
-
- ngOnInit(): void {
- this.topologyService.selectedTopology$.subscribe(value => this.populateContent(value));
- }
-
- ngAfterViewInit(): void {
- ace.config.set(
- 'basePath',
- 'https://unpkg.com/ace-builds@1.4.12/src-noconflict'
- );
- const aceEditor = ace.edit(this.editor.nativeElement);
- aceEditor.session.setMode('xml');
- }
-
- getEditorVisibility(): string {
- return this.topologyContent ? 'block' : 'none';
- }
-
- setTitle(value: string) {
- this.titleSuffix = value;
- }
-
- onChange(code: any) {
- this.changedTopology = code;
- }
-
- saveTopology() {
- this.topologyService.saveTopology(this.topology.href, this.changedTopology)
- .then(value => this.topologyService.changedTopology(this.topology.name));
- }
-
- createTopology() {
- this.topologyService.createTopology(this.newTopologyName,
- (this.changedTopology ? this.changedTopology : this.topologyContent))
- .then(() => {
- this.topologyService.changedTopology(this.newTopologyName);
- // This refreshes the list of topologies
- this.resourceTypesService.selectResourceType('Topologies');
- });
- }
-
- deleteTopology() {
- this.topologyService.deleteTopology(this.topology.href)
- .then(() => {
- this.topologyService.changedTopology(this.topology.name);
- // This refreshes the list of topologies
- this.resourceTypesService.selectResourceType('Topologies');
- // This refreshes the topology content panel to the first one in the list
- this.topologyService.getTopologies()
- .then(topologies => {
- this.topologyService.selectedTopology(topologies[0]);
- });
- });
- }
-
- populateContent(topology: Topology) {
- this.topology = topology;
- this.setTitle(topology.name);
- if (this.topology) {
- if (this.topology.href) {
- this.topologyService.getTopology(this.topology.href)
- .then(content => this.topologyContent = content)
- .then(() => this.makeReadOnly(this.topologyContent, 'generated'));
- }
- }
- }
-
- isValidNewTopologyName(): boolean {
- return ValidationUtils.isValidResourceName(this.newTopologyName);
- }
-
- /*
- * Parse the XML and depending on the
- * provided tag value make the editor read only
- */
- makeReadOnly(text, tag) {
- let parser = new DOMParser();
- let parsed = parser.parseFromString(text, 'text/xml');
-
- let tagValue = parsed.getElementsByTagName(tag);
- let result = tagValue[0].childNodes[0].nodeValue;
-
- if (result === 'true') {
- this.showEditOptions = false;
- this.options = {readOnly: true, useWorker: false, printMargin: false, highlightActiveLine: false, highlightGutterLine: false};
- } else {
- this.showEditOptions = true;
- this.options = {readOnly: false, useWorker: false, printMargin: false};
- }
-
- }
-
-
-}
diff --git a/gateway-admin-ui/admin-ui/app/topology-detail/topology-detail.component.css b/gateway-admin-ui/admin-ui/app/topology-detail/topology-detail.component.css
new file mode 100644
index 000000000..ff44ea768
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/topology-detail/topology-detail.component.css
@@ -0,0 +1,80 @@
+.code-editor-scroll {
+ height: 65vh;
+ overflow: auto;
+ background-color: #272822;
+ border-radius: 4px 4px 0 0;
+}
+
+.code-editor-wrapper {
+ display: flex;
+ align-items: stretch;
+ min-height: 100%;
+}
+
+.code-editor-gutter {
+ min-width: 40px;
+ padding: 10px 8px 10px 0;
+ background-color: #1e1f1c;
+ text-align: right;
+ user-select: none;
+ border-right: 1px solid #3e3d32;
+ flex-shrink: 0;
+}
+
+.line-number {
+ font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
+ font-size: 12px;
+ line-height: 18px;
+ color: #75715e;
+}
+
+.code-editor {
+ flex: 1;
+ padding: 10px 12px;
+ background-color: #272822;
+ color: #f8f8f2;
+ border: none;
+ outline: none;
+ resize: none;
+ font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
+ font-size: 12px;
+ line-height: 18px;
+ tab-size: 4;
+ white-space: pre;
+ overflow: hidden;
+}
+
+.code-editor:read-only {
+ opacity: 0.85;
+}
+
+.code-editor::selection {
+ background-color: #49483e;
+}
+
+.editor-toolbar {
+ padding: 8px 12px;
+ background-color: #1e1f1c;
+ border-top: 1px solid #3e3d32;
+ border-radius: 0 0 4px 4px;
+}
+
+.editor-toolbar .btn {
+ background-color: #3e3d32;
+ border-color: #555;
+ color: #f8f8f2;
+}
+
+.editor-toolbar .btn:hover:not(:disabled) {
+ background-color: #555;
+ border-color: #75715e;
+}
+
+.editor-toolbar .btn:disabled {
+ opacity: 0.4;
+}
+
+.editor-toolbar .material-icons {
+ color: #f8f8f2;
+ font-size: 16px;
+}
diff --git a/gateway-admin-ui/admin-ui/app/topology-detail/topology-detail.component.html b/gateway-admin-ui/admin-ui/app/topology-detail/topology-detail.component.html
new file mode 100644
index 000000000..6a4c9cd2d
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/topology-detail/topology-detail.component.html
@@ -0,0 +1,77 @@
+<div class="panel panel-default" style="margin-top: 10px;">
+ <div class="panel-heading">
+ <h4 class="panel-title">{{title}}
+ @if (showEditOptions === false) {
+ <span style="padding-left: 15%;" class="text-danger text-center"> Read Only (generated file) </span>
+ }
+ <span class="pull-right">{{titleSuffix}}</span>
+ </h4>
+ </div>
+ <div [style.display]="getEditorVisibility()" class="panel-body" style="padding: 0;">
+ <div class="code-editor-scroll">
+ <div class="code-editor-wrapper">
+ <div class="code-editor-gutter">
+ @for (line of getLineNumbers(); track line) {
+ <div class="line-number">{{line}}</div>
+ }
+ </div>
+ <textarea
+ class="code-editor"
+ [(ngModel)]="topologyContent"
+ [readOnly]="!showEditOptions"
+ [attr.rows]="getLineNumbers().length || 1"
+ spellcheck="false"
+ (input)="onChange($event.target.value)">
+ </textarea>
+ </div>
+ </div>
+ <div class="editor-toolbar">
+ <button id="duplicateTopology" (click)="duplicateModal.open('sm')" class="btn btn-default btn-sm"
+ title="Duplicate Topology" type="submit">
+ <span class="material-icons">content_copy</span>
+ </button>
+ @if (showEditOptions) {
+ <button id="deleteTopology" (click)="deleteConfirmModal.open('sm')"
+ class="btn btn-default btn-sm" title="Delete Topology" type="submit">
+ <span class="material-icons">delete</span>
+ </button>
+ }
+ @if (showEditOptions) {
+ <button id="saveTopology" (click)="saveTopology()" class="btn btn-default btn-sm pull-right"
+ title="Save Topology" [disabled]="!changedTopology" type="submit">
+ <span class="material-icons">save</span>
+ </button>
+ }
+ </div>
+ </div>
+ <app-modal (onClose)="createTopology()" #duplicateModal>
+ <div class="modal-header">
+ <h4 class="modal-title">Create a copy</h4>
+ <button type="button" class="btn-close" (click)="duplicateModal.dismiss()"></button>
+ </div>
+ <div class="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>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default btn-sm" (click)="duplicateModal.dismiss()">Cancel</button>
+ <button type="button" class="btn btn-primary btn-sm" [disabled]="!isValidNewTopologyName()"
+ (click)="duplicateModal.close()">Ok</button>
+ </div>
+ </app-modal>
+ <app-modal (onClose)="deleteTopology()" #deleteConfirmModal>
+ <div class="modal-header">
+ <h4 class="modal-title">Deleting Topology {{titleSuffix}}</h4>
+ <button type="button" class="btn-close" (click)="deleteConfirmModal.dismiss()"></button>
+ </div>
+ <div class="modal-body">
+ Are you sure you want to delete the topology?
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default btn-sm" (click)="deleteConfirmModal.dismiss()">Cancel</button>
+ <button type="button" class="btn btn-primary btn-sm" (click)="deleteConfirmModal.close()">Ok</button>
+ </div>
+ </app-modal>
+</div>
diff --git a/gateway-admin-ui/admin-ui/app/topology-detail/topology-detail.component.ts b/gateway-admin-ui/admin-ui/app/topology-detail/topology-detail.component.ts
new file mode 100644
index 000000000..3ac6c9efd
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/topology-detail/topology-detail.component.ts
@@ -0,0 +1,118 @@
+/*
+ * 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 {FormsModule} from '@angular/forms';
+import {Topology} from '../model/topology';
+import {TopologyService} from '../service/topology.service';
+import {ResourceTypesService} from '../service/resourcetypes.service';
+import {ValidationUtils} from '../utils/validation-utils';
+import {ModalComponent} from '../utils/modal.component';
+
+@Component({
+ selector: 'app-topology-detail',
+ templateUrl: './topology-detail.component.html',
+ styleUrls: ['./topology-detail.component.css'],
+ imports: [FormsModule, ModalComponent]
+})
+export class TopologyDetailComponent implements OnInit {
+ title = 'Topology Detail';
+ titleSuffix: string;
+ topology: Topology;
+ topologyContent: string;
+ changedTopology: string;
+ newTopologyName: string;
+ showEditOptions = true;
+
+ constructor(private topologyService: TopologyService, private resourceTypesService: ResourceTypesService) {
+ }
+
+ ngOnInit(): void {
+ this.topologyService.selectedTopology$.subscribe(value => this.populateContent(value));
+ }
+
+ getEditorVisibility(): string {
+ return this.topologyContent ? 'block' : 'none';
+ }
+
+ getLineNumbers(): number[] {
+ if (!this.topologyContent) {
+ return [];
+ }
+ const count = this.topologyContent.split('\n').length;
+ return Array.from({length: count}, (_, i) => i + 1);
+ }
+
+ setTitle(value: string) {
+ this.titleSuffix = value;
+ }
+
+ onChange(code: any) {
+ this.changedTopology = code;
+ }
+
+ saveTopology() {
+ this.topologyService.saveTopology(this.topology.href, this.changedTopology)
+ .then(() => this.topologyService.changedTopology(this.topology.name));
+ }
+
+ createTopology() {
+ this.topologyService.createTopology(this.newTopologyName,
+ (this.changedTopology ? this.changedTopology : this.topologyContent))
+ .then(() => {
+ this.topologyService.changedTopology(this.newTopologyName);
+ this.resourceTypesService.selectResourceType('Topologies');
+ });
+ }
+
+ deleteTopology() {
+ this.topologyService.deleteTopology(this.topology.href)
+ .then(() => {
+ this.topologyService.changedTopology(this.topology.name);
+ this.resourceTypesService.selectResourceType('Topologies');
+ this.topologyService.getTopologies()
+ .then(topologies => {
+ this.topologyService.selectedTopology(topologies[0]);
+ });
+ });
+ }
+
+ populateContent(topology: Topology) {
+ this.topology = topology;
+ this.setTitle(topology.name);
+ if (this.topology) {
+ if (this.topology.href) {
+ this.topologyService.getTopology(this.topology.href)
+ .then(content => this.topologyContent = content)
+ .then(() => this.makeReadOnly(this.topologyContent, 'generated'));
+ }
+ }
+ }
+
+ isValidNewTopologyName(): boolean {
+ return ValidationUtils.isValidResourceName(this.newTopologyName);
+ }
+
+ makeReadOnly(text, tag) {
+ let parser = new DOMParser();
+ let parsed = parser.parseFromString(text, 'text/xml');
+
+ let tagValue = parsed.getElementsByTagName(tag);
+ let result = tagValue[0].childNodes[0].nodeValue;
+
+ this.showEditOptions = result !== 'true';
+ }
+}
diff --git a/gateway-admin-ui/admin-ui/app/topology/topology.component.html b/gateway-admin-ui/admin-ui/app/topology/topology.component.html
new file mode 100644
index 000000000..447af8140
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/topology/topology.component.html
@@ -0,0 +1,19 @@
+<div class="table-responsive" style="max-height: 400px; width:100%; overflow: auto;">
+ <table class="table table-striped table-hover">
+ <thead>
+ <tr>
+ <th>Topology Name</th>
+ <th>Timestamp</th>
+ </tr>
+ </thead>
+ <tbody>
+ @for (topology of topologies; track topology.name) {
+ <tr [class.selected]="topology === selectedTopology"
+ (click)="onSelect(topology)">
+ <td>{{topology.name}}</td>
+ <td>{{topology.timestamp | date:'medium'}}</td>
+ </tr>
+ }
+ </tbody>
+ </table>
+</div>
diff --git a/gateway-admin-ui/admin-ui/app/topology.component.ts b/gateway-admin-ui/admin-ui/app/topology/topology.component.ts
similarity index 60%
rename from gateway-admin-ui/admin-ui/app/topology.component.ts
rename to gateway-admin-ui/admin-ui/app/topology/topology.component.ts
index bb279df21..f4338ba42 100644
--- a/gateway-admin-ui/admin-ui/app/topology.component.ts
+++ b/gateway-admin-ui/admin-ui/app/topology/topology.component.ts
@@ -15,32 +15,15 @@
* limitations under the License.
*/
import {Component, OnInit} from '@angular/core';
-import {Topology} from './topology';
-import {TopologyService} from './topology.service';
+import {DatePipe} from '@angular/common';
+import {Topology} from '../model/topology';
+import {TopologyService} from '../service/topology.service';
@Component({
selector: 'app-topology',
- template: `
- <div class="table-responsive" style="max-height: 400px; width:100%; overflow: auto;">
- <table class="table table-striped table-hover">
- <thead>
- <tr>
- <th>Topology Name</th>
- <th>Timestamp</th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let topology of topologies"
- [class.selected]="topology === selectedTopology"
- (click)="onSelect(topology)">
- <td>{{topology.name}}</td>
- <td>{{topology.timestamp | date:'medium'}}</td>
- </tr>
- </tbody>
- </table>
- </div>
- `
+ templateUrl: './topology.component.html',
+ imports: [DatePipe]
})
export class TopologyComponent implements OnInit {
@@ -58,7 +41,7 @@ export class TopologyComponent implements OnInit {
ngOnInit(): void {
this.getTopologies();
- this.topologyService.changedTopology$.subscribe(value => this.getTopologies());
+ this.topologyService.changedTopology$.subscribe(() => this.getTopologies());
}
onSelect(topology: Topology): void {
@@ -66,4 +49,3 @@ export class TopologyComponent implements OnInit {
this.topologyService.selectedTopology(topology);
}
}
-
diff --git a/gateway-admin-ui/admin-ui/app/utils/json-pretty.pipe.ts b/gateway-admin-ui/admin-ui/app/utils/json-pretty.pipe.ts
index 8d531225e..f1f5b4d6b 100644
--- a/gateway-admin-ui/admin-ui/app/utils/json-pretty.pipe.ts
+++ b/gateway-admin-ui/admin-ui/app/utils/json-pretty.pipe.ts
@@ -18,7 +18,9 @@ import {Pipe, PipeTransform} from '@angular/core';
declare let vkbeautify: any;
-@Pipe({name: 'jsonpretty'})
+@Pipe({
+ name: 'jsonpretty'
+})
export class JsonPrettyPipe implements PipeTransform {
transform(value: string): string {
diff --git a/gateway-admin-ui/admin-ui/app/utils/modal.component.html b/gateway-admin-ui/admin-ui/app/utils/modal.component.html
new file mode 100644
index 000000000..feb4e4ee1
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/utils/modal.component.html
@@ -0,0 +1,10 @@
+<div class="modal" [class.show]="visible" [style.display]="visible ? 'block' : 'none'" tabindex="-1">
+ <div class="modal-dialog" [class.modal-sm]="size === 'sm'" [class.modal-lg]="size === 'lg'">
+ <div class="modal-content">
+ <ng-content></ng-content>
+ </div>
+ </div>
+</div>
+@if (visible) {
+ <div class="modal-backdrop fade show"></div>
+}
diff --git a/gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.ts b/gateway-admin-ui/admin-ui/app/utils/modal.component.ts
similarity index 61%
rename from gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.ts
rename to gateway-admin-ui/admin-ui/app/utils/modal.component.ts
index c0a447164..be6f2d0f3 100644
--- a/gateway-admin-ui/admin-ui/app/descriptor/descriptor.component.ts
+++ b/gateway-admin-ui/admin-ui/app/utils/modal.component.ts
@@ -14,16 +14,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {Component, OnInit} from '@angular/core';
+import {Component, EventEmitter, Input, Output} from '@angular/core';
@Component({
- selector: 'app-descriptor',
- templateUrl: './descriptor.component.html',
- styleUrls: ['./descriptor.component.css']
+ selector: 'app-modal',
+ templateUrl: './modal.component.html'
})
-export class DescriptorComponent {
+export class ModalComponent {
+ @Input() size: string = 'md';
+ @Output() onClose = new EventEmitter<void>();
- constructor() {
+ visible = false;
+
+ open(size?: string) {
+ if (size) {
+ this.size = size;
+ }
+ this.visible = true;
+ }
+
+ close() {
+ this.visible = false;
+ this.onClose.emit();
}
+ dismiss() {
+ this.visible = false;
+ }
}
diff --git a/gateway-admin-ui/admin-ui/app/utils/tab.component.css b/gateway-admin-ui/admin-ui/app/utils/tab.component.css
new file mode 100644
index 000000000..d5e3c5d33
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/utils/tab.component.css
@@ -0,0 +1,3 @@
+.pane {
+ padding: 1em;
+}
diff --git a/gateway-admin-ui/admin-ui/app/utils/tab.component.html b/gateway-admin-ui/admin-ui/app/utils/tab.component.html
new file mode 100644
index 000000000..ee8aa2d1b
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/utils/tab.component.html
@@ -0,0 +1,2 @@
+<div [hidden]="!active" class="pane">
+</div>
diff --git a/gateway-admin-ui/admin-ui/app/utils/tab.component.ts b/gateway-admin-ui/admin-ui/app/utils/tab.component.ts
index 2fd74bfa2..0ad871aa6 100644
--- a/gateway-admin-ui/admin-ui/app/utils/tab.component.ts
+++ b/gateway-admin-ui/admin-ui/app/utils/tab.component.ts
@@ -18,15 +18,8 @@ import {Component, Input} from '@angular/core';
@Component({
selector: 'app-tab',
- styles: [`
- .pane {
- padding: 1em;
- }
- `],
- template: `
- <div [hidden]="!active" class="pane">
- </div>
- `
+ templateUrl: './tab.component.html',
+ styleUrls: ['./tab.component.css']
})
export class TabComponent {
@Input('tabTitle') title: string;
diff --git a/gateway-admin-ui/admin-ui/app/utils/tabs.component.html b/gateway-admin-ui/admin-ui/app/utils/tabs.component.html
new file mode 100644
index 000000000..fa8b00b01
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/app/utils/tabs.component.html
@@ -0,0 +1,7 @@
+<ul class="nav nav-tabs">
+ @for (tab of tabs; track tab.title) {
+ <li (click)="selectTab(tab)" [class.active]="tab.active">
+ <a>{{tab.title}}</a>
+ </li>
+ }
+</ul>
diff --git a/gateway-admin-ui/admin-ui/app/utils/tabs.component.ts b/gateway-admin-ui/admin-ui/app/utils/tabs.component.ts
index fbfb44728..fef064879 100644
--- a/gateway-admin-ui/admin-ui/app/utils/tabs.component.ts
+++ b/gateway-admin-ui/admin-ui/app/utils/tabs.component.ts
@@ -19,35 +19,22 @@ import {TabComponent} from './tab.component';
@Component({
selector: 'app-tabs',
- template: `
- <ul class="nav nav-tabs">
- <li *ngFor="let tab of tabs" (click)="selectTab(tab)" [class.active]="tab.active">
- <a>{{tab.title}}</a>
- </li>
- </ul>
-
- `
+ templateUrl: './tabs.component.html'
})
export class TabsComponent implements AfterContentInit {
@ContentChildren(TabComponent) tabs: QueryList<TabComponent>;
- // contentChildren are set
ngAfterContentInit() {
- // get all active tabs
let activeTabs = this.tabs.filter((tab) => tab.active);
- // if there is no active tab set, activate the first
if (activeTabs.length === 0) {
this.selectTab(this.tabs.first);
}
}
selectTab(tab: TabComponent) {
- // deactivate all tabs
this.tabs.toArray().forEach(t => t.active = false);
-
- // activate the tab the user has clicked on.
tab.active = true;
}
diff --git a/gateway-admin-ui/admin-ui/app/utils/validation-utils.ts b/gateway-admin-ui/admin-ui/app/utils/validation-utils.ts
index a471a9cfd..59ba3daf2 100644
--- a/gateway-admin-ui/admin-ui/app/utils/validation-utils.ts
+++ b/gateway-admin-ui/admin-ui/app/utils/validation-utils.ts
@@ -72,7 +72,7 @@ export class ValidationUtils {
if (value) {
try {
parsed = JSON.parse(value);
- } catch (e) {
+ } catch (_e) {
// just return undefined
}
}
diff --git a/gateway-admin-ui/admin-ui/app/utils/xml.pipe.ts b/gateway-admin-ui/admin-ui/app/utils/xml.pipe.ts
index 5a82b2ce6..977c3a9e1 100644
--- a/gateway-admin-ui/admin-ui/app/utils/xml.pipe.ts
+++ b/gateway-admin-ui/admin-ui/app/utils/xml.pipe.ts
@@ -18,7 +18,9 @@ import {Pipe, PipeTransform} from '@angular/core';
declare let vkbeautify: any;
-@Pipe({name: 'xml'})
+@Pipe({
+ name: 'xml'
+})
export class XmlPipe implements PipeTransform {
transform(value: string): string {
diff --git a/gateway-admin-ui/admin-ui/assets/sticky-footer.css b/gateway-admin-ui/admin-ui/assets/sticky-footer.css
deleted file mode 100644
index 01eb6d403..000000000
--- a/gateway-admin-ui/admin-ui/assets/sticky-footer.css
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Sticky footer styles
--------------------------------------------------- */
-html {
- position: relative;
- min-height: 100%;
-}
-
-body {
- /* Margin bottom by footer height */
- margin-bottom: 60px;
-}
-
-.footer {
- position: absolute;
- bottom: 0;
- width: 100%;
- /* Set the fixed height of the footer here */
- height: 60px;
- background-color: #f5f5f5;
-}
-
-.jumbotron {
- padding: 0.5em 0.6em;
-}
diff --git a/gateway-admin-ui/admin-ui/index.html b/gateway-admin-ui/admin-ui/index.html
index ab2d882cf..ca83a15fb 100644
--- a/gateway-admin-ui/admin-ui/index.html
+++ b/gateway-admin-ui/admin-ui/index.html
@@ -19,46 +19,38 @@
<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">
- <!-- Custom styles for this template -->
- <link href="assets/sticky-footer.css" rel="stylesheet">
- <script src="assets/vkbeautify.js"></script>
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
+ <link rel="preconnect" href="https://fonts.googleapis.com">
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
</head>
<body>
-<div class="navbar-wrapper">
- <div class="container-fluid">
+ <nav class="navbar navbar-expand-lg navbar-dark bg-dark pt-0 top-navbar">
+ <div class="container-fluid align-items-start">
+ <a class="navbar-brand pt-1 pb-0 ps-0 pe-0 me-3 d-flex" href="#">
+ <img src="assets/knox-logo-transparent.gif" alt="Apache Knox Home" style="max-width:200px; margin-top:-5px;">
+ </a>
+
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarContent"
+ aria-controls="navbarContent" aria-expanded="false" aria-label="Toggle navigation">
+ <span class="navbar-toggler-icon"></span>
+ </button>
- <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 class="collapse navbar-collapse" id="navbarContent">
+ <div class="ms-auto d-flex flex-column pt-0">
+ <app-session-information></app-session-information>
</div>
- <app-session-information></app-session-information>
</div>
- </nav>
-
- </div>
+ </div>
+ </nav>
<!-- Content -->
<app-resource-management></app-resource-management>
- <div class="container-fluid" style="padding-top: 50px !important">
- </div>
-
<footer class="footer">
<div class="container-fluid">
- <div>Knox Manager
- <app-gateway-version></app-gateway-version>
- </div>
+ <span class="footer-title">Knox Manager</span>
+ <app-gateway-version></app-gateway-version>
</div>
</footer>
</body>
diff --git a/gateway-admin-ui/admin-ui/main.ts b/gateway-admin-ui/admin-ui/main.ts
index 3ed873ee4..e00dad4c2 100644
--- a/gateway-admin-ui/admin-ui/main.ts
+++ b/gateway-admin-ui/admin-ui/main.ts
@@ -16,13 +16,29 @@
*/
import './polyfills.ts';
-import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
-import {enableProdMode} from '@angular/core';
-import {environment} from './environments/environment';
-import {AppModule} from './app/';
+import { enableProdMode, provideZoneChangeDetection } from '@angular/core';
+import { environment } from './environments/environment';
+import { bootstrapApplication } from '@angular/platform-browser';
+import { provideHttpClient } from '@angular/common/http';
+import { SessionInformationComponent } from './app/session-information/session.information.component';
+import { GatewayVersionComponent } from './app/gateway-version/gateway-version.component';
+import { AppComponent } from './app/app.component';
if (environment.production) {
- enableProdMode();
+ enableProdMode();
}
-platformBrowserDynamic().bootstrapModule(AppModule);
+const bootstrapComponents = [
+ SessionInformationComponent,
+ GatewayVersionComponent,
+ AppComponent
+];
+
+bootstrapComponents.forEach(component => {
+ bootstrapApplication(component, {
+ providers: [
+ provideZoneChangeDetection(),
+ provideHttpClient()
+ ]
+ }).catch(err => console.error(err));
+});
diff --git a/gateway-admin-ui/admin-ui/app/service-definition/rewrite.rule.ts b/gateway-admin-ui/admin-ui/material-theme.scss
similarity index 86%
rename from gateway-admin-ui/admin-ui/app/service-definition/rewrite.rule.ts
rename to gateway-admin-ui/admin-ui/material-theme.scss
index 2f1e7014b..382c0c98a 100644
--- a/gateway-admin-ui/admin-ui/app/service-definition/rewrite.rule.ts
+++ b/gateway-admin-ui/admin-ui/material-theme.scss
@@ -14,9 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+@use '@angular/material' as mat;
-export class RewriteRule {
- dir: string;
- name: string;
- pattern: string;
+:root {
+ @include mat.theme((
+ color: (
+ primary: mat.$green-palette
+ )
+ ));
}
diff --git a/gateway-admin-ui/admin-ui/polyfills.ts b/gateway-admin-ui/admin-ui/polyfills.ts
index 78cba4747..aebd58c4e 100644
--- a/gateway-admin-ui/admin-ui/polyfills.ts
+++ b/gateway-admin-ui/admin-ui/polyfills.ts
@@ -14,22 +14,4 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-// This file includes polyfills needed by Angular 2 and is loaded before
-// the app. You can add your own extra polyfills to this file.
-import 'core-js/es6/symbol';
-import 'core-js/es6/object';
-import 'core-js/es6/function';
-import 'core-js/es6/parse-int';
-import 'core-js/es6/parse-float';
-import 'core-js/es6/number';
-import 'core-js/es6/math';
-import 'core-js/es6/string';
-import 'core-js/es6/date';
-import 'core-js/es6/array';
-import 'core-js/es6/regexp';
-import 'core-js/es6/map';
-import 'core-js/es6/set';
-import 'core-js/es6/reflect';
-
-import 'core-js/es7/reflect';
-import 'zone.js/dist/zone';
+import 'zone.js';
diff --git a/gateway-admin-ui/admin-ui/styles.css b/gateway-admin-ui/admin-ui/styles.css
deleted file mode 100644
index a7ad3e612..000000000
--- a/gateway-admin-ui/admin-ui/styles.css
+++ /dev/null
@@ -1,9 +0,0 @@
-/* You can add global styles to this file, and also import other style files */
-
-.navbar-static-top {
- min-height: 110px;
-}
-
-.clickable {
- cursor: pointer;
-}
diff --git a/gateway-admin-ui/admin-ui/styles.scss b/gateway-admin-ui/admin-ui/styles.scss
new file mode 100644
index 000000000..e48e1dea2
--- /dev/null
+++ b/gateway-admin-ui/admin-ui/styles.scss
@@ -0,0 +1,354 @@
+/*
+ * 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.
+ */
+
+/* Global styles */
+
+// Green theme palette
+$primary: #4caf50;
+$primary-dark: #388e3c;
+$primary-light: #c8e6c9;
+$primary-lighter: #e8f5e9;
+$primary-lightest: #f1f8e9;
+
+$accent: #ff9800;
+$warn: #f44336;
+
+$text-primary: #333;
+$text-secondary: #555;
+$text-muted: #999;
+$border-color: #ddd;
+$border-light: #eee;
+
+.top-navbar {
+ min-height: 5vw;
+}
+
+.clickable {
+ cursor: pointer;
+}
+
+body {
+ margin: 0;
+ padding-bottom: 40px;
+ font-size: 14px;
+}
+
+// Form input styling
+input[type="text"],
+input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="submit"]):not([type="button"]) {
+ padding: 3px 8px;
+ border: 1px solid $border-color;
+ border-radius: 4px;
+ font-size: 13px;
+ color: $text-primary;
+ background-color: #fff;
+ transition: border-color 0.15s, box-shadow 0.15s;
+ margin-right: 6px;
+
+ &:focus {
+ outline: none;
+ border-color: $primary;
+ box-shadow: 0 0 0 2px rgba($primary, 0.15);
+ }
+
+ &::placeholder {
+ color: $text-muted;
+ }
+}
+
+input[type="checkbox"] {
+ accent-color: $primary;
+ cursor: pointer;
+}
+
+.footer {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 40px;
+ line-height: 40px;
+ background-color: #f5f5f5;
+ border-top: 1px solid #e0e0e0;
+ z-index: 1000;
+}
+
+.footer .container-fluid {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ height: 100%;
+}
+
+.footer-title {
+ font-size: 12px;
+ font-weight: 600;
+ color: $text-primary;
+}
+
+
+a {
+ color: $primary-dark;
+ text-decoration: none;
+}
+
+// Bootstrap 5 compatibility for BS3 classes
+.btn-default {
+ color: $text-primary;
+ background-color: #fff;
+ border-color: #ccc;
+}
+
+.btn-default:hover {
+ color: $text-primary;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+
+.btn-primary {
+ color: #fff;
+ background-color: $primary;
+ border-color: $primary;
+}
+
+.btn-primary:hover,
+.btn-primary:focus,
+.btn-primary:active {
+ color: #fff;
+ background-color: $primary-dark;
+ border-color: $primary-dark;
+}
+
+.btn-primary:disabled {
+ background-color: $primary-light;
+ border-color: $primary-light;
+}
+
+// Select / form-control styling
+select.form-control {
+ padding: 3px 8px;
+ border: 1px solid $border-color;
+ border-radius: 4px;
+ font-size: 13px;
+ color: $text-primary;
+ background-color: #fff;
+
+ &:focus {
+ outline: none;
+ border-color: $primary;
+ box-shadow: 0 0 0 2px rgba($primary, 0.15);
+ }
+}
+
+.pull-left {
+ float: left !important;
+}
+
+.pull-right {
+ float: right !important;
+}
+
+// Panel styling (BS3 compat)
+.panel {
+ border: 1px solid $border-color;
+ border-radius: 4px;
+ margin-bottom: 15px;
+ background-color: #fff;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+}
+
+.panel-default > .panel-heading {
+ color: $text-primary;
+ background-color: #f5f5f5;
+ border-bottom: 1px solid $border-color;
+ padding: 10px 15px;
+}
+
+.panel-body {
+ padding: 15px;
+}
+
+.panel-title {
+ margin: 0;
+ font-size: 15px;
+ font-weight: 500;
+}
+
+// Modal styling
+.modal {
+ z-index: 1050;
+}
+
+.modal-backdrop {
+ z-index: 1040;
+}
+
+.modal-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 12px 16px;
+ border-bottom: 1px solid #dee2e6;
+ background-color: #f8f9fa;
+}
+
+.modal-title {
+ font-weight: 500;
+ color: $text-primary;
+}
+
+.modal-footer {
+ padding: 12px 16px;
+ border-top: 1px solid #dee2e6;
+ background-color: #f8f9fa;
+}
+
+// Icon button alignment
+.btn-xs {
+ padding: 2px 5px;
+ line-height: 1;
+ vertical-align: middle;
+ display: inline-block;
+}
+
+.btn-xs .material-icons {
+ vertical-align: middle;
+ line-height: 1;
+ display: inline-block;
+}
+
+.inline-glyph {
+ display: inline-block;
+ vertical-align: middle;
+ line-height: 1;
+}
+
+// Material Icons base
+.material-icons {
+ font-size: 16px;
+ vertical-align: middle;
+ line-height: 1;
+ color: $text-secondary;
+ transition: color 0.15s;
+}
+
+// Expand/collapse toggle icons
+span.clickable.material-icons,
+span.clickable.inline-glyph.material-icons {
+ font-size: 18px;
+ color: #666;
+}
+
+span.clickable.material-icons:hover,
+span.clickable.inline-glyph.material-icons:hover {
+ color: $primary;
+}
+
+// Icons inside buttons
+.btn .material-icons {
+ font-size: 14px;
+ color: inherit;
+}
+
+// Inline action icon buttons
+.inline-glyph .material-icons {
+ color: #666;
+}
+
+.inline-glyph:hover .material-icons {
+ color: $primary;
+}
+
+// Add action
+[title*="Add"] .material-icons,
+[title*="Create"] .material-icons {
+ color: $primary;
+}
+
+[title*="Add"]:hover .material-icons,
+[title*="Create"]:hover .material-icons {
+ color: $primary-dark;
+}
+
+// Remove/delete action
+[title*="Remove"] .material-icons,
+[title*="Delete"] .material-icons {
+ color: $text-muted;
+}
+
+[title*="Remove"]:hover .material-icons,
+[title*="Delete"]:hover .material-icons {
+ color: $warn;
+}
+
+// Discard/refresh
+button[title*="Discard"] .material-icons {
+ color: $accent;
+}
+
+button[title*="Discard"]:hover .material-icons {
+ color: #e68900;
+}
+
+// Save/update
+button[title*="Update"] .material-icons,
+button[title*="Save"] .material-icons {
+ color: $primary;
+}
+
+button[title*="Update"]:hover .material-icons,
+button[title*="Save"]:hover .material-icons {
+ color: $primary-dark;
+}
+
+// Validation error messages
+.validation-error {
+ display: inline-block;
+ margin-top: 2px;
+ margin-left: 4px;
+ padding: 2px 8px;
+ font-size: 12px;
+ color: $warn;
+ background-color: #fff5f5;
+ border: 1px solid rgba($warn, 0.3);
+ border-radius: 3px;
+}
+
+.required-marker {
+ color: $warn;
+ margin-left: 2px;
+}
+
+.required-footnote {
+ font-size: 12px;
+ color: $text-muted;
+ font-style: italic;
+}
+
+.required-footnote::before {
+ content: "* ";
+ color: $warn;
+}
+
+// Material table/paginator overrides
+.mat-mdc-table {
+ background-color: white !important;
+}
+
+.mat-mdc-paginator {
+ background-color: white !important;
+}
diff --git a/gateway-admin-ui/admin-ui/tsconfig.json b/gateway-admin-ui/admin-ui/tsconfig.json
index c56d60198..268b33345 100644
--- a/gateway-admin-ui/admin-ui/tsconfig.json
+++ b/gateway-admin-ui/admin-ui/tsconfig.json
@@ -4,16 +4,11 @@
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
- "lib": [
- "es2017",
- "dom"
- ],
- "mapRoot": "./",
- "module": "es6",
- "moduleResolution": "node",
+ "module": "ES2022",
+ "moduleResolution": "bundler",
"outDir": "../dist/out-tsc",
"sourceMap": true,
- "target": "es5",
+ "target": "ES2022",
"typeRoots": [
"../node_modules/@types"
]
diff --git a/gateway-admin-ui/admin-ui/typings.d.ts b/gateway-admin-ui/admin-ui/typings.d.ts
deleted file mode 100644
index 32bf19d41..000000000
--- a/gateway-admin-ui/admin-ui/typings.d.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// Typings reference file, you can add your own global typings here
-// https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html
diff --git a/gateway-admin-ui/angular.json b/gateway-admin-ui/angular.json
index 72f6510b7..c2cdfd1aa 100644
--- a/gateway-admin-ui/angular.json
+++ b/gateway-admin-ui/angular.json
@@ -36,12 +36,14 @@
"prefix": "app",
"architect": {
"build": {
- "builder": "@angular-devkit/build-angular:browser",
+ "builder": "@angular/build:application",
"options": {
- "outputPath": "target/classes/admin-ui/app",
+ "outputPath": {
+ "base": "target/classes/admin-ui/app",
+ "browser": ""
+ },
"index": "admin-ui/index.html",
- "main": "admin-ui/main.ts",
- "polyfills": "admin-ui/polyfills.ts",
+ "polyfills": ["admin-ui/polyfills.ts"],
"tsConfig": "admin-ui/tsconfig.json",
"assets": [
"admin-ui/favicon.ico",
@@ -49,18 +51,16 @@
],
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
- "admin-ui/styles.css"
+ "admin-ui/material-theme.scss",
+ "admin-ui/styles.scss"
],
"scripts": [
- "node_modules/jquery/dist/jquery.min.js",
- "node_modules/bootstrap/dist/js/bootstrap.js",
- "node_modules/ace-builds/src-min/ace.js",
- "node_modules/ace-builds/src-min/theme-monokai.js"
- ]
+ "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
+ ],
+ "browser": "admin-ui/main.ts"
},
"configurations": {
"production": {
- "buildOptimizer": false,
"aot": false,
"fileReplacements": [
{
@@ -71,10 +71,8 @@
"outputHashing": "all"
},
"development": {
- "buildOptimizer": false,
"aot": false,
"optimization": false,
- "vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
@@ -83,25 +81,21 @@
"defaultConfiguration": "production"
},
"serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
+ "builder": "@angular/build:dev-server",
"configurations": {
"production": {
- "browserTarget": "admin-ui:build:production"
+ "buildTarget": "admin-ui:build:production"
},
"development": {
- "browserTarget": "admin-ui:build:development"
+ "buildTarget": "admin-ui:build:development"
}
},
- "options": {
- "browserTarget": "admin-ui:build",
- "proxyConfig": "proxy.conf.json"
- },
"defaultConfiguration": "development"
},
"extract-i18n": {
- "builder": "@angular-devkit/build-angular:extract-i18n",
+ "builder": "@angular/build:extract-i18n",
"options": {
- "browserTarget": "admin-ui:build"
+ "buildTarget": "admin-ui:build"
}
},
"lint": {
@@ -115,12 +109,5 @@
}
}
}
- },
- "defaultProject": "admin-ui",
- "cli": {
- "schematicCollections": [
- "@angular-eslint/schematics",
- "@angular-eslint/schematics"
- ]
}
}
diff --git a/gateway-admin-ui/eslint.config.js b/gateway-admin-ui/eslint.config.js
new file mode 100644
index 000000000..12b8d3c08
--- /dev/null
+++ b/gateway-admin-ui/eslint.config.js
@@ -0,0 +1,76 @@
+import js from "@eslint/js";
+import tseslint from "typescript-eslint";
+import angular from "@angular-eslint/eslint-plugin";
+import tsParser from "@typescript-eslint/parser";
+
+export default [
+ {
+ ignores: ["**/dist/**", "**/node_modules/**"],
+ },
+
+ js.configs.recommended,
+
+ {
+ files: ["**/*.ts"],
+ languageOptions: {
+ parser: tsParser,
+ parserOptions: {
+ project: ["./admin-ui/tsconfig.json"],
+ tsconfigRootDir: import.meta.dirname,
+ },
+ globals: {
+ console: "readonly",
+ window: "readonly",
+ document: "readonly",
+ setTimeout: "readonly",
+ atob: "readonly",
+ require: "readonly"
+ },
+ },
+ plugins: {
+ "@typescript-eslint": tseslint.plugin,
+ "@angular-eslint": angular,
+ },
+ rules: {
+ "@typescript-eslint/naming-convention": [
+ "error",
+ {selector: "class", format: ["PascalCase"]},
+ ],
+
+ curly: "error",
+ eqeqeq: ["error", "always", {null: "ignore"}],
+ "guard-for-in": "error",
+ "max-len": ["error", {code: 140}],
+ "no-bitwise": "error",
+ "no-caller": "error",
+ "no-console": "off",
+ "no-debugger": "error",
+ "no-empty": "error",
+ "no-eval": "error",
+ "no-fallthrough": "error",
+ "no-trailing-spaces": "error",
+ "no-unused-vars": ["error", {argsIgnorePattern: "^_", varsIgnorePattern: "^_", caughtErrorsIgnorePattern: "^_"}],
+ "no-unused-expressions": "error",
+ "no-unused-labels": "error",
+ "no-var": "error",
+ quotes: ["error", "single"],
+ radix: "error",
+ semi: ["error", "always"],
+ "spaced-comment": "error",
+ "brace-style": ["error", "1tbs", {allowSingleLine: true}],
+
+ "@angular-eslint/directive-selector": [
+ "error",
+ {type: "attribute", prefix: "app", style: "camelCase"},
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {type: "element", prefix: "app", style: "kebab-case"},
+ ],
+ "@angular-eslint/no-output-rename": "error",
+ "@angular-eslint/use-pipe-transform-interface": "error",
+ "@angular-eslint/component-class-suffix": "error",
+ "@angular-eslint/directive-class-suffix": "error",
+ },
+ },
+];
\ No newline at end of file
diff --git a/gateway-admin-ui/package.json b/gateway-admin-ui/package.json
index 5f74ec23e..08f86584b 100644
--- a/gateway-admin-ui/package.json
+++ b/gateway-admin-ui/package.json
@@ -2,57 +2,44 @@
"name": "ng-knox-ui",
"version": "1.0.0",
"license": "Apache-2.0",
+ "type": "module",
"scripts": {
- "start": "ng serve",
+ "start": "ng serve --verbose=true",
"build": "ng build",
"build-prod": "ng build --configuration production",
"lint": "eslint admin-ui"
},
"private": true,
"dependencies": {
- "@angular/common": "^13.0.1",
- "@angular/compiler": "^13.0.1",
- "@angular/core": "^13.0.1",
- "@angular/forms": "^13.0.1",
- "@angular/platform-browser": "^13.0.1",
- "@angular/platform-browser-dynamic": "^13.0.1",
- "@angular/router": "^13.0.1",
- "angular2-datatable": "^0.6.0",
- "bootstrap": "^3.4.1",
- "core-js": "^2.6.4",
- "jquery": "^3.5.1",
- "js-yaml": "^3.13.1",
- "ng2-ace-editor": "0.3.7",
- "ace-builds": "^1.4.12",
- "ng2-bs3-modal": "^0.15.0",
- "ng2-validation": "^4.2.0",
- "popper.js": "^1.14.7",
- "rest-url-builder": "^1.0.6",
- "rxjs": "^6.6.7",
- "rxjs-compat": "^6.6.7",
- "sweetalert2": "^11.6.5",
- "ts-helpers": "^1.1.1",
- "vkbeautify": "^0.99.3",
- "zone.js": "~0.11.4"
+ "@angular/cdk": "^21.2.14",
+ "@angular/common": "^21.0.5",
+ "@angular/compiler": "^21.0.5",
+ "@angular/core": "^21.0.5",
+ "@angular/forms": "^21.0.5",
+ "@angular/material": "^21.2.14",
+ "@angular/platform-browser": "^21.0.5",
+ "@angular/platform-browser-dynamic": "^21.0.5",
+ "@angular/router": "^21.0.5",
+ "bootstrap": "^5.3.8",
+ "core-js": "^3.46.0",
+ "sweetalert2": "^11.26.3",
+ "zone.js": "^0.15.1"
},
"devDependencies": {
- "@angular-devkit/build-angular": "^13.3.11",
- "@angular-eslint/builder": "14.1.2",
- "@angular-eslint/eslint-plugin": "14.1.2",
- "@angular-eslint/eslint-plugin-template": "14.1.2",
- "@angular-eslint/schematics": "14.1.2",
- "@angular-eslint/template-parser": "14.1.2",
- "@angular/cli": "^14.2.9",
- "@angular/compiler-cli": "^13.0.1",
- "@angular/language-service": "^5.2.0",
- "@types/jasmine": "~2.5.53",
- "@types/jasminewd2": "~2.0.2",
- "@types/node": "16.18.11",
- "@typescript-eslint/eslint-plugin": "5.37.0",
- "@typescript-eslint/parser": "5.37.0",
- "eslint": "^8.23.1",
- "ts-node": "~3.2.0",
- "typescript": "~4.4.4",
- "webdriver-manager": "10.2.5"
+ "@angular-eslint/builder": "21.1.0",
+ "@angular-eslint/eslint-plugin": "21.1.0",
+ "@angular-eslint/eslint-plugin-template": "21.1.0",
+ "@angular-eslint/schematics": "21.1.0",
+ "@angular-eslint/template-parser": "21.1.0",
+ "@angular/build": "^21.0.3",
+ "@angular/cli": "^21.0.3",
+ "@angular/compiler-cli": "^21.0.5",
+ "@angular/language-service": "^21.0.5",
+ "@eslint/js": "^9.39.0",
+ "@types/node": "^24.5.2",
+ "eslint": "^9.39.0",
+ "ts-node": "~10.9.0",
+ "typescript": "~5.9.3",
+ "typescript-eslint": "^8.46.2"
}
-}
+}
\ No newline at end of file
diff --git a/gateway-admin-ui/pom.xml b/gateway-admin-ui/pom.xml
index ff41c08de..6a435c458 100644
--- a/gateway-admin-ui/pom.xml
+++ b/gateway-admin-ui/pom.xml
@@ -37,7 +37,11 @@
<configuration>
<filesets>
<fileset>
- <directory>node_modules</directory>
+ <directory>${project.basedir}</directory>
+ <includes>
+ <include>package-lock.json</include>
+ <include>node_modules/**</include>
+ </includes>
</fileset>
</filesets>
</configuration>
@@ -65,7 +69,7 @@
<goal>npm</goal>
</goals>
<configuration>
- <arguments>install --legacy-peer-deps</arguments>
+ <arguments>install</arguments>
</configuration>
</execution>
<execution>
diff --git a/knox-token-generation-ui/token-generation/app/sessionInformation/session.information.component.html b/knox-token-generation-ui/token-generation/app/sessionInformation/session.information.component.html
index 7250e0166..719af147b 100644
--- a/knox-token-generation-ui/token-generation/app/sessionInformation/session.information.component.html
+++ b/knox-token-generation-ui/token-generation/app/sessionInformation/session.information.component.html
@@ -12,6 +12,5 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!-- The text color is the same as the Cloudera logo's color -->
<div style="text-align: right; color: rgb(130, 180, 93);">Logged in as {{ getUser() }}</div>
<div style="margin-left: 15%; text-align: center; color: rgb(130,180, 93); max-width: 70%; word-wrap: break-word;" [innerHTML]="getBannerText() | safeHtml"></div>
diff --git a/knox-token-management-ui/token-management/app/sessioninformation/session.information.component.html b/knox-token-management-ui/token-management/app/sessioninformation/session.information.component.html
index 30a7de284..9dd131f11 100644
--- a/knox-token-management-ui/token-management/app/sessioninformation/session.information.component.html
+++ b/knox-token-management-ui/token-management/app/sessioninformation/session.information.component.html
@@ -12,7 +12,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!-- The text color is the same as the Cloudera logo's color -->
<div style="text-align: right; color: rgb(130, 180, 93);">Logged in as {{ getUser() }}</div>
<div style="margin-left: 15%; text-align: center; color: rgb(130,180, 93); max-width: 70%; word-wrap: break-word;" [innerHTML]="getBannerText() | safeHtml"></div>