This is an automated email from the ASF dual-hosted git repository.
smolnar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new 20fa65948 KNOX-3003 - Services with more than one serviceUrl metadata
are grouped on the Knox Home page (#838)
20fa65948 is described below
commit 20fa65948804a4ddedd246c61d896005c47b0104
Author: Sandor Molnar <[email protected]>
AuthorDate: Fri Feb 2 12:24:26 2024 +0100
KNOX-3003 - Services with more than one serviceUrl metadata are grouped on
the Knox Home page (#838)
---
.../service/metadata/KnoxMetadataResource.java | 10 ++-
.../gateway/service/metadata/ServiceModel.java | 79 +++++++++++++---------
.../gateway/service/metadata/ServiceModelTest.java | 26 ++++---
knox-homepage-ui/home/app/topologies/service.ts | 2 +-
.../topologies/topology.information.component.css | 4 ++
.../topologies/topology.information.component.html | 76 +++++++++++++++++----
.../topologies/topology.information.component.ts | 27 ++++++++
7 files changed, 163 insertions(+), 61 deletions(-)
diff --git
a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
index ec826c62b..d50283c39 100644
---
a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
+++
b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
@@ -229,9 +229,8 @@ public class KnoxMetadataResource {
Set<ServiceModel> apiServices = new HashSet<>();
Set<ServiceModel> uiServices = new HashSet<>();
topology.getServices().stream().filter(service ->
!UNREAL_SERVICES.contains(service.getRole())).forEach(service -> {
- service.getUrls().forEach(serviceUrl -> {
- ServiceModel serviceModel = getServiceModel(request,
config.getGatewayPath(), topology.getName(), service,
getServiceMetadata(serviceDefinitionRegistry, service),
- serviceUrl);
+ if (!service.getUrls().isEmpty()) {
+ final ServiceModel serviceModel = getServiceModel(request,
config.getGatewayPath(), topology.getName(), service,
getServiceMetadata(serviceDefinitionRegistry, service));
if (ServiceModel.Type.UI == serviceModel.getType()) {
uiServices.add(serviceModel);
} else if (ServiceModel.Type.API_AND_UI ==
serviceModel.getType()) {
@@ -240,7 +239,7 @@ public class KnoxMetadataResource {
} else {
apiServices.add(serviceModel);
}
- });
+ }
});
topologies.addTopology(topology.getName(),
isPinnedTopology(topology.getName(), config),
config.getApiServicesViewVersionOnHomepage(), new TreeSet<>(apiServices), new
TreeSet<>(uiServices));
}
@@ -264,14 +263,13 @@ public class KnoxMetadataResource {
return serviceDefinition.isPresent() ?
serviceDefinition.get().getService().getMetadata() : null;
}
- private ServiceModel getServiceModel(HttpServletRequest request, String
gatewayPath, String topologyName, Service service, Metadata serviceMetadata,
String serviceUrl) {
+ private ServiceModel getServiceModel(HttpServletRequest request, String
gatewayPath, String topologyName, Service service, Metadata serviceMetadata) {
final ServiceModel serviceModel = new ServiceModel();
serviceModel.setRequest(request);
serviceModel.setGatewayPath(gatewayPath);
serviceModel.setTopologyName(topologyName);
serviceModel.setService(service);
serviceModel.setServiceMetadata(serviceMetadata);
- serviceModel.setServiceUrl(serviceUrl);
return serviceModel;
}
diff --git
a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/ServiceModel.java
b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/ServiceModel.java
index 5e35d27ff..600347531 100644
---
a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/ServiceModel.java
+++
b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/ServiceModel.java
@@ -17,12 +17,18 @@
*/
package org.apache.knox.gateway.service.metadata;
+import static java.lang.String.format;
+import static java.util.Locale.ROOT;
+
import java.io.UncheckedIOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
+import java.util.TreeSet;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.annotation.XmlAccessType;
@@ -60,7 +66,6 @@ public class ServiceModel implements Comparable<ServiceModel>
{
private String gatewayPath;
private Service service;
private Metadata serviceMetadata;
- private String serviceUrl;
public void setRequest(HttpServletRequest request) {
this.request = request;
@@ -82,10 +87,6 @@ public class ServiceModel implements
Comparable<ServiceModel> {
this.serviceMetadata = serviceMetadata;
}
- public void setServiceUrl(String serviceUrl) {
- this.serviceUrl = serviceUrl;
- }
-
@XmlElement
public String getServiceName() {
return this.service == null ? "" : service.getRole();
@@ -124,40 +125,52 @@ public class ServiceModel implements
Comparable<ServiceModel> {
return serviceMetadata == null ? ("/" +
getServiceName().toLowerCase(Locale.ROOT)) : serviceMetadata.getContext();
}
- @XmlElement
- public String getServiceUrl() {
- String context = getContext();
+ @XmlElement(name = "serviceUrls")
+ public List<String> getServiceUrls() {
+ final Set<String> resolvedServiceUrls = new TreeSet<>();
+ final String context = getContext();
+
if (HIVE_SERVICE_NAME.equals(getServiceName())) {
- return String.format(Locale.ROOT, HIVE_SERVICE_URL_TEMPLATE,
request.getServerName(), request.getServerPort(), gatewayPath, topologyName);
+ resolvedServiceUrls.add(format(ROOT, HIVE_SERVICE_URL_TEMPLATE,
request.getServerName(), request.getServerPort(), gatewayPath, topologyName));
} else if (IMPALA_SERVICE_NAME.equals(getServiceName())) {
- return String.format(Locale.ROOT, IMPALA_SERVICE_URL_TEMPLATE,
request.getServerName(), request.getServerPort(), gatewayPath, topologyName);
+ resolvedServiceUrls.add(format(ROOT, IMPALA_SERVICE_URL_TEMPLATE,
request.getServerName(), request.getServerPort(), gatewayPath, topologyName));
} else {
- return getServiceUrl(context);
+ if (service != null && service.getUrls() != null &&
!service.getUrls().isEmpty()) {
+ this.service.getUrls().forEach(serviceUrl -> {
+ resolvedServiceUrls.add(getServiceUrl(context, serviceUrl));
+ });
+ } else {
+ // fall back to the service URL fetched from the 'service' instance,
if any
+ resolvedServiceUrls.add(getServiceUrl(context, null));
+ }
}
+ return Arrays.asList(resolvedServiceUrls.toArray(new String[0]));
}
- private String getServiceUrl(String context) {
- final String resolvedContext = resolvePlaceholdersFromBackendUrl(context);
+ private String getServiceUrl(String context, String serviceUrl) {
+ final String resolvedContext = resolvePlaceholdersFromBackendUrl(context,
serviceUrl);
return String.format(Locale.ROOT, SERVICE_URL_TEMPLATE,
request.getScheme(), request.getServerName(), request.getServerPort(),
gatewayPath, topologyName, resolvedContext);
}
- private String resolvePlaceholdersFromBackendUrl(String resolveable) {
+ private String resolvePlaceholdersFromBackendUrl(String resolveable, String
serviceUrl) {
String toBeResolved = resolveable;
if (toBeResolved != null) {
- final String backendUrlString = getBackendServiceUrl();
+ final String backendUrlString = getBackendServiceUrl(serviceUrl);
- if (toBeResolved.indexOf("{{BACKEND_HOST}}") > -1) {
- toBeResolved = toBeResolved.replace("{{BACKEND_HOST}}",
backendUrlString);
- }
+ if (StringUtils.isNotBlank(backendUrlString)) {
+ if (toBeResolved.indexOf("{{BACKEND_HOST}}") > -1) {
+ toBeResolved = toBeResolved.replace("{{BACKEND_HOST}}",
backendUrlString);
+ }
- if (toBeResolved.indexOf("{{SCHEME}}") > -1 ||
toBeResolved.indexOf("{{HOST}}") > -1 || toBeResolved.indexOf("{{PORT}}") > -1)
{
- try {
- final URL backendUrl = new URL(backendUrlString);
- toBeResolved = toBeResolved.replace("{{SCHEME}}",
backendUrl.getProtocol());
- toBeResolved = toBeResolved.replace("{{HOST}}",
backendUrl.getHost());
- toBeResolved = toBeResolved.replace("{{PORT}}",
String.valueOf(backendUrl.getPort()));
- } catch (MalformedURLException e) {
- throw new UncheckedIOException("Error while converting " +
backendUrlString + " to a URL", e);
+ if (toBeResolved.indexOf("{{SCHEME}}") > -1 ||
toBeResolved.indexOf("{{HOST}}") > -1 || toBeResolved.indexOf("{{PORT}}") > -1)
{
+ try {
+ final URL backendUrl = new URL(backendUrlString);
+ toBeResolved = toBeResolved.replace("{{SCHEME}}",
backendUrl.getProtocol());
+ toBeResolved = toBeResolved.replace("{{HOST}}",
backendUrl.getHost());
+ toBeResolved = toBeResolved.replace("{{PORT}}",
String.valueOf(backendUrl.getPort()));
+ } catch (MalformedURLException e) {
+ throw new UncheckedIOException("Error while converting '" +
backendUrlString + "' to a URL", e);
+ }
}
}
}
@@ -165,7 +178,7 @@ public class ServiceModel implements
Comparable<ServiceModel> {
return toBeResolved;
}
- String getBackendServiceUrl() {
+ String getBackendServiceUrl(String serviceUrl) {
final String backendServiceUrl = serviceUrl == null ? (service == null ?
"" : service.getUrl()) : serviceUrl;
return backendServiceUrl == null ? "" : backendServiceUrl;
}
@@ -183,7 +196,9 @@ public class ServiceModel implements
Comparable<ServiceModel> {
} else {
final String method = StringUtils.isBlank(sample.getMethod()) ?
"GET" : sample.getMethod();
final String path = sample.getPath().startsWith("/") ?
sample.getPath() : ("/" + sample.getPath());
- resolvedSample.setValue(String.format(Locale.ROOT,
CURL_SAMPLE_TEMPLATE, method, getServiceUrl(), path));
+ final String serviceUrl = getServiceUrls().isEmpty() ? (service ==
null ? "$SERVICE_URL" : service.getUrl())
+ : getServiceUrls().stream().findFirst().get();
+ resolvedSample.setValue(String.format(Locale.ROOT,
CURL_SAMPLE_TEMPLATE, method, serviceUrl, path));
}
samples.add(resolvedSample);
});
@@ -201,19 +216,19 @@ public class ServiceModel implements
Comparable<ServiceModel> {
}
final ServiceModel serviceModel = (ServiceModel) obj;
return new EqualsBuilder().append(topologyName,
serviceModel.topologyName).append(gatewayPath,
serviceModel.gatewayPath).append(getServiceName(),
serviceModel.getServiceName())
- .append(getVersion(),
serviceModel.getVersion()).append(serviceMetadata,
serviceModel.serviceMetadata).append(getServiceUrl(),
serviceModel.getServiceUrl()).isEquals();
+ .append(getVersion(),
serviceModel.getVersion()).append(serviceMetadata,
serviceModel.serviceMetadata).append(getServiceUrls(),
serviceModel.getServiceUrls()).isEquals();
}
@Override
public int hashCode() {
- return new HashCodeBuilder(17,
37).append(topologyName).append(gatewayPath).append(getServiceName()).append(getVersion()).append(serviceMetadata).append(getServiceUrl())
+ return new HashCodeBuilder(17,
37).append(topologyName).append(gatewayPath).append(getServiceName()).append(getVersion()).append(serviceMetadata).append(getServiceUrls())
.toHashCode();
}
@Override
public String toString() {
return new ToStringBuilder(this,
ToStringStyle.SHORT_PREFIX_STYLE).append(topologyName).append(gatewayPath).append(getServiceName()).append(getVersion())
- .append(serviceMetadata).append(getServiceUrl()).toString();
+ .append(serviceMetadata).append(getServiceUrls()).toString();
}
@Override
@@ -221,7 +236,7 @@ public class ServiceModel implements
Comparable<ServiceModel> {
final int byServiceName =
getServiceName().compareTo(other.getServiceName());
if (byServiceName == 0) {
final int byVersion = getVersion().compareTo(getVersion());
- return byVersion == 0 ?
getBackendServiceUrl().compareTo(other.getBackendServiceUrl()) : byVersion;
+ return byVersion == 0 ? Integer.compare(getServiceUrls().size(),
other.getServiceUrls().size()) : byVersion;
}
return byServiceName;
}
diff --git
a/gateway-service-metadata/src/test/java/org/apache/knox/gateway/service/metadata/ServiceModelTest.java
b/gateway-service-metadata/src/test/java/org/apache/knox/gateway/service/metadata/ServiceModelTest.java
index 77ff7c3e2..9db82fc31 100644
---
a/gateway-service-metadata/src/test/java/org/apache/knox/gateway/service/metadata/ServiceModelTest.java
+++
b/gateway-service-metadata/src/test/java/org/apache/knox/gateway/service/metadata/ServiceModelTest.java
@@ -158,7 +158,7 @@ public class ServiceModelTest {
serviceModel.setService(service);
EasyMock.expect(service.getRole()).andReturn(HIVE_SERVICE_NAME).anyTimes();
EasyMock.replay(service);
- assertEquals(String.format(Locale.ROOT, HIVE_SERVICE_URL_TEMPLATE,
SERVER_NAME, SERVER_PORT, gatewayPath, topologyName),
serviceModel.getServiceUrl());
+ assertEquals(String.format(Locale.ROOT, HIVE_SERVICE_URL_TEMPLATE,
SERVER_NAME, SERVER_PORT, gatewayPath, topologyName),
getFirstServiceUrl(serviceModel));
}
@Test
@@ -173,7 +173,7 @@ public class ServiceModelTest {
serviceModel.setService(service);
EasyMock.expect(service.getRole()).andReturn(IMPALA_SERVICE_NAME).anyTimes();
EasyMock.replay(service);
- assertEquals(String.format(Locale.ROOT, IMPALA_SERVICE_URL_TEMPLATE,
SERVER_NAME, SERVER_PORT, gatewayPath, topologyName),
serviceModel.getServiceUrl());
+ assertEquals(String.format(Locale.ROOT, IMPALA_SERVICE_URL_TEMPLATE,
SERVER_NAME, SERVER_PORT, gatewayPath, topologyName),
getFirstServiceUrl(serviceModel));
}
public HttpServletRequest setUpHttpRequestMock() {
@@ -198,7 +198,7 @@ public class ServiceModelTest {
final String context = "/testContext";
EasyMock.expect(metadata.getContext()).andReturn(context).anyTimes();
EasyMock.replay(metadata);
- assertEquals(String.format(Locale.ROOT, SERVICE_URL_TEMPLATE,
SERVER_SCHEME, SERVER_NAME, SERVER_PORT, gatewayPath, topologyName, context),
serviceModel.getServiceUrl());
+ assertEquals(String.format(Locale.ROOT, SERVICE_URL_TEMPLATE,
SERVER_SCHEME, SERVER_NAME, SERVER_PORT, gatewayPath, topologyName, context),
getFirstServiceUrl(serviceModel));
}
@Test
@@ -214,20 +214,24 @@ public class ServiceModelTest {
serviceModel.setService(service);
EasyMock.expect(service.getRole()).andReturn("service").anyTimes();
final String backendHost = "https://localhost:5555";
- EasyMock.expect(service.getUrl()).andReturn(backendHost); // backend host
comes from the service object
+ EasyMock.expect(service.getUrl()).andReturn(backendHost).anyTimes(); //
backend host comes from the service object
final Metadata metadata = EasyMock.createNiceMock(Metadata.class);
serviceModel.setServiceMetadata(metadata);
final String context = "/testContext?backendHost={{BACKEND_HOST}}";
EasyMock.expect(metadata.getContext()).andReturn(context).anyTimes();
EasyMock.replay(service, metadata);
assertEquals(String.format(Locale.ROOT, SERVICE_URL_TEMPLATE,
SERVER_SCHEME, SERVER_NAME, SERVER_PORT, gatewayPath, topologyName,
- context.replace("{{BACKEND_HOST}}", backendHost)),
serviceModel.getServiceUrl());
+ context.replace("{{BACKEND_HOST}}", backendHost)),
getFirstServiceUrl(serviceModel));
final String serviceUrl = "https://serviceHost:8888";
- serviceModel.setServiceUrl(serviceUrl); // backend host comes from the
given service URL
+ final Service serviceWithServiceUrls =
EasyMock.createNiceMock(Service.class);
+ // backend host comes from the given service URLs
+
EasyMock.expect(serviceWithServiceUrls.getUrls()).andReturn(Arrays.asList(serviceUrl)).anyTimes();
+ EasyMock.replay(serviceWithServiceUrls);
+ serviceModel.setService(serviceWithServiceUrls);
assertEquals(
String.format(Locale.ROOT, SERVICE_URL_TEMPLATE, SERVER_SCHEME,
SERVER_NAME, SERVER_PORT, gatewayPath, topologyName,
context.replace("{{BACKEND_HOST}}", serviceUrl)),
- serviceModel.getServiceUrl());
+ getFirstServiceUrl(serviceModel));
}
@Test
@@ -242,7 +246,7 @@ public class ServiceModelTest {
final Service service = EasyMock.createNiceMock(Service.class);
serviceModel.setService(service);
EasyMock.expect(service.getRole()).andReturn("service").anyTimes();
- EasyMock.expect(service.getUrl()).andReturn("https://localhost:5555");
+
EasyMock.expect(service.getUrl()).andReturn("https://localhost:5555").anyTimes();
final Metadata metadata = EasyMock.createNiceMock(Metadata.class);
serviceModel.setServiceMetadata(metadata);
@@ -251,7 +255,7 @@ public class ServiceModelTest {
EasyMock.replay(service, metadata);
assertEquals(String.format(Locale.ROOT, SERVICE_URL_TEMPLATE,
SERVER_SCHEME, SERVER_NAME, SERVER_PORT, gatewayPath, topologyName,
- context.replace("{{SCHEME}}", "https").replace("{{HOST}}",
"localhost").replace("{{PORT}}", "5555")), serviceModel.getServiceUrl());
+ context.replace("{{SCHEME}}", "https").replace("{{HOST}}",
"localhost").replace("{{PORT}}", "5555")), getFirstServiceUrl(serviceModel));
}
@Test
@@ -285,4 +289,8 @@ public class ServiceModelTest {
assertEquals(samples.get(0).getValue(), "curl -iv -X PUT
\"https://localhost:8443/gateway/sandbox/testContext/sampleStartsWithSlashPath/operation\"");
assertEquals(samples.get(1).getValue(), "curl -iv -X GET
\"https://localhost:8443/gateway/sandbox/testContext/sampleStartsWithoutSlashPath/operation\"");
}
+
+ private String getFirstServiceUrl(ServiceModel serviceModel) {
+ return serviceModel.getServiceUrls().isEmpty() ? "" :
serviceModel.getServiceUrls().get(0);
+ }
}
diff --git a/knox-homepage-ui/home/app/topologies/service.ts
b/knox-homepage-ui/home/app/topologies/service.ts
index dca781aef..d38b17f13 100644
--- a/knox-homepage-ui/home/app/topologies/service.ts
+++ b/knox-homepage-ui/home/app/topologies/service.ts
@@ -20,7 +20,7 @@ export class Service {
description: string;
serviceName: string;
version: string;
- serviceUrl: string;
+ serviceUrls: string[];
shortDesc: string;
type: string;
context: string;
diff --git
a/knox-homepage-ui/home/app/topologies/topology.information.component.css
b/knox-homepage-ui/home/app/topologies/topology.information.component.css
index eb2de0363..5d2f9cd2e 100644
--- a/knox-homepage-ui/home/app/topologies/topology.information.component.css
+++ b/knox-homepage-ui/home/app/topologies/topology.information.component.css
@@ -34,3 +34,7 @@ mat-grid-tile-footer figcaption h3 {
transition: all 0.3s linear;
visibility: visible;
}
+
+/deep/ .groupServiceInformationModal {
+ width: 80%;
+}
\ No newline at end of file
diff --git
a/knox-homepage-ui/home/app/topologies/topology.information.component.html
b/knox-homepage-ui/home/app/topologies/topology.information.component.html
index 9086f087b..510945441 100644
--- a/knox-homepage-ui/home/app/topologies/topology.information.component.html
+++ b/knox-homepage-ui/home/app/topologies/topology.information.component.html
@@ -38,18 +38,31 @@
<!-- UI services -->
<mat-grid-list cols="4" rowHeight="130px">
<mat-grid-tile *ngFor="let service of topology.uiServices.service"
[colspan]="1" [rowspan]="1">
- <a href="{{service.serviceUrl}}" target="_blank"
*ngIf="!this['enableServiceText_' + service.serviceName.toLowerCase()]">
+
+ <!-- Services with 1 service URL -->
+ <div *ngIf="service.serviceUrls.length === 1">
+ <a href="{{service.serviceUrls[0]}}" target="_blank"
*ngIf="!this['enableServiceText_' + service.serviceName.toLowerCase()]">
+ <img
src="assets/service-logos/{{service.serviceName.toLowerCase()}}.png"
height="50px" (error)="enableServiceText('enableServiceText_' +
service.serviceName.toLowerCase())"/>
+ </a>
+ <a href="{{service.serviceUrls[0]}}" target="_blank"
*ngIf="this['enableServiceText_' + service.serviceName.toLowerCase()]">
+ {{service.shortDesc}}
+ </a>
+ <mat-grid-tile-footer class="tile-shortDesc">
+ <h3>{{service.shortDesc}} <span class="small"
*ngIf="service.version">(v{{service.version}})</span></h3>
+ </mat-grid-tile-footer>
+ <mat-grid-tile-footer class="tile-longDesc"
style="height:100px;">
+ <h3>{{service.description}}</h3>
+ </mat-grid-tile-footer>
+ </div>
+
+ <!-- Services with more than 1 service URL -->
+ <div *ngIf="service.serviceUrls.length > 1"
(click)="openGroupServiceInformationModal(service)">
<img
src="assets/service-logos/{{service.serviceName.toLowerCase()}}.png"
height="50px" (error)="enableServiceText('enableServiceText_' +
service.serviceName.toLowerCase())"/>
- </a>
- <a href="{{service.serviceUrl}}" target="_blank"
*ngIf="this['enableServiceText_' + service.serviceName.toLowerCase()]">
- {{service.shortDesc}}
- </a>
- <mat-grid-tile-footer class="tile-shortDesc">
- <h3>{{service.shortDesc}} <span class="small"
*ngIf="service.version">(v{{service.version}})</span></h3>
- </mat-grid-tile-footer>
- <mat-grid-tile-footer class="tile-longDesc"
style="height:100px;">
- <h3>{{service.description}}</h3>
- </mat-grid-tile-footer>
+ <mat-grid-tile-footer class="tile-shortDesc">
+ <h3>{{service.shortDesc}}
({{service.serviceUrls.length}})</h3>
+ </mat-grid-tile-footer>
+ </div>
+
</mat-grid-tile>
</mat-grid-list>
@@ -75,7 +88,10 @@
{{service.shortDesc}} <span class="small"
*ngIf="service.version">(v{{service.version}})</span>
</td>
<td>
- <a
href="{{service.serviceUrl}}">{{service.serviceUrl}}</a>
+ <ng-container *ngFor="let serviceUrl of
service.serviceUrls">
+ <a href="{{serviceUrl}}">{{serviceUrl}}</a>
+ <br *ngIf="service.serviceUrls.length > 1" />
+ </ng-container>
</td>
</tr>
</tbody>
@@ -141,7 +157,7 @@
<div *ngIf="!selectedApiService.samples ||
selectedApiService.samples.sample.length < 1">
<tr><td style="font-weight: bold;">There is no any
sample found in service metadata</td></tr>
<tr>
- <td> You may check out the service's
documentation and find out how to use its REST API. The service's URL is <a
href="{{selectedApiService.serviceUrl}}"
target="_blank">{{selectedApiService.serviceUrl}}</a></td>
+ <td> You may check out the service's
documentation and find out how to use its REST API. The service's URL is <a
href="{{selectedApiService.serviceUrls[0]}}"
target="_blank">{{selectedApiService.serviceUrls[0]}}</a></td>
</tr>
</div>
</table>
@@ -149,8 +165,42 @@
</tr>
</table>
</div>
+
</bs-modal-body>
<bs-modal-footer>
<button type="button" class="btn btn-primary btn-sm"
(click)="apiServiceInformationModal.close()">Close</button>
</bs-modal-footer>
</bs-modal>
+
+
+<bs-modal #groupServiceInformationModal
cssClass="groupServiceInformationModal" [animation]="true">
+ <bs-modal-header [showDismiss]="true" *ngIf="selectedGroupService">
+ <h4 class="modal-title">{{selectedGroupService.shortDesc}} <span
class="small"
*ngIf="selectedGroupService.version">(v{{selectedGroupService.version}})</span></h4>
+ </bs-modal-header>
+ <bs-modal-body *ngIf="selectedGroupService">
+ <span>
+ {{selectedGroupService.description}}
+ </span>
+ <br/><br/>
+ <span align="center">
+ <input type="text" placeholder="Search by hostname, port..."
(input)="filterServiceUrls($event.target.value)" style="width: 50%">
+ </span>
+
+ <mat-grid-list cols="4" rowHeight="130px">
+ <mat-grid-tile *ngFor="let serviceUrl of filteredServiceUrls"
[colspan]="1" [rowspan]="1">
+ <a href="{{serviceUrl}}" target="_blank"
*ngIf="!this['enableServiceText_' +
selectedGroupService.serviceName.toLowerCase()]">
+ <img
src="assets/service-logos/{{selectedGroupService.serviceName.toLowerCase()}}.png"
height="50px" (error)="enableServiceText('enableServiceText_' +
selectedGroupService.serviceName.toLowerCase())"/>
+ </a>
+ <a href="{{serviceUrl}}" target="_blank"
*ngIf="this['enableServiceText_' +
selectedGroupService.serviceName.toLowerCase()]">
+ {{selectedGroupService.shortDesc}}
+ </a>
+ <mat-grid-tile-footer class="tile-shortDesc">
+ <h3>{{selectedGroupService.shortDesc}}
{{getServiceUrlHostAndPort(serviceUrl)}}</h3>
+ </mat-grid-tile-footer>
+ </mat-grid-tile>
+ </mat-grid-list>
+ </bs-modal-body>
+ <bs-modal-footer>
+ <button type="button" class="btn btn-primary btn-sm"
(click)="groupServiceInformationModal.close()">Close</button>
+ </bs-modal-footer>
+</bs-modal>
diff --git
a/knox-homepage-ui/home/app/topologies/topology.information.component.ts
b/knox-homepage-ui/home/app/topologies/topology.information.component.ts
index d267f7566..bbb18763b 100644
--- a/knox-homepage-ui/home/app/topologies/topology.information.component.ts
+++ b/knox-homepage-ui/home/app/topologies/topology.information.component.ts
@@ -34,9 +34,14 @@ export class TopologyInformationsComponent implements OnInit
{
@ViewChild('apiServiceInformationModal')
apiServiceInformationModal: BsModalComponent;
+ @ViewChild('groupServiceInformationModal')
+ groupServiceInformationModal: BsModalComponent;
+
topologies: TopologyInformation[];
desiredTopologies: string[];
selectedApiService: Service;
+ selectedGroupService: Service;
+ filteredServiceUrls: string[];
setTopologies(topologies: TopologyInformation[]) {
this.topologies = topologies;
@@ -106,4 +111,26 @@ export class TopologyInformationsComponent implements
OnInit {
this.apiServiceInformationModal.open('lg');
}
+ openGroupServiceInformationModal(groupService: Service) {
+ this.selectedGroupService = groupService;
+ this.filteredServiceUrls = this.selectedGroupService.serviceUrls;
+ this.groupServiceInformationModal.open();
+ }
+
+ getServiceUrlHostAndPort(serviceUrl: string): string {
+ let hostStart = serviceUrl.indexOf('host=');
+ if (hostStart > 0 ) {
+ return ' - ' + serviceUrl.slice(hostStart).replace('host=',
'').replace('&port=', ':')
+ .replace('https://', '').replace('http://', '');
+ }
+ return '';
+ }
+
+ filterServiceUrls(filterText: string): void {
+ if (filterText === '') {
+ this.filteredServiceUrls =
this.selectedGroupService.serviceUrls;
+ } else {
+ this.filteredServiceUrls =
this.selectedGroupService.serviceUrls.filter(serviceUrl =>
serviceUrl.includes(filterText));
+ }
+ }
}