From 1c9c5feb080fe6c904c4fc18c591eac785297971 Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Tue, 13 Jun 2023 12:39:53 +1000 Subject: [PATCH 1/4] Dev UI: Allow external links in submenu Signed-off-by: Phillip Kruger --- .../keycloak/KeycloakDevConsoleProcessor.java | 15 ++++++++--- .../resources/dev-ui/qwc-oidc-provider.js | 25 ------------------- .../dev-ui/controller/router-controller.js | 16 ++++++++++++ .../dev-ui/qwc/qwc-extension-link.js | 5 ++-- .../resources/dev-ui/qwc/qwc-extensions.js | 2 ++ .../devui/spi/page/ExternalPageBuilder.java | 6 +++++ .../java/io/quarkus/devui/spi/page/Page.java | 10 +++++++- .../quarkus/devui/spi/page/PageBuilder.java | 2 ++ 8 files changed, 49 insertions(+), 32 deletions(-) diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevConsoleProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevConsoleProcessor.java index df812885e00d1..3aa2515cb9a4f 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevConsoleProcessor.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevConsoleProcessor.java @@ -19,6 +19,7 @@ import io.quarkus.devconsole.spi.DevConsoleTemplateInfoBuildItem; import io.quarkus.devui.spi.JsonRPCProvidersBuildItem; import io.quarkus.devui.spi.page.CardPageBuildItem; +import io.quarkus.devui.spi.page.Page; import io.quarkus.oidc.deployment.OidcBuildTimeConfig; import io.quarkus.oidc.deployment.devservices.AbstractDevConsoleProcessor; import io.quarkus.oidc.deployment.devservices.OidcAuthorizationCodePostHandler; @@ -81,7 +82,9 @@ void produceProviderComponent(Optional confi @SuppressWarnings("unchecked") Map users = (Map) configProps.get().getProperties().get("oidc.users"); - var cardPage = createProviderWebComponent( + String keycloakAdminUrl = configProps.get().getConfig().get("keycloak.url"); + + CardPageBuildItem cardPageBuildItem = createProviderWebComponent( recorder, capabilities, "Keycloak", @@ -97,11 +100,17 @@ void produceProviderComponent(Optional confi oidcConfig.devui.grantOptions, nonApplicationRootPathBuildItem, configurationBuildItem, - configProps.get().getConfig().get("keycloak.url"), + keycloakAdminUrl, users, configProps.get().getProperties().get("keycloak.realms"), configProps.get().isContainerRestarted()); - cardPageProducer.produce(cardPage); + + // Also add Admin page + cardPageBuildItem.addPage(Page.externalPageBuilder("Keycloak Admin") + .icon("font-awesome-solid:key") + .doNotEmbed(true) + .url(keycloakAdminUrl)); + cardPageProducer.produce(cardPageBuildItem); } } diff --git a/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js b/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js index 6b34773c2071c..96ef5fb13f2d4 100644 --- a/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js +++ b/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js @@ -351,27 +351,6 @@ export class QwcOidcProvider extends QwcHotReloadElement { } _renderProvider() { - const content = this._content(); - if (propertiesState.keycloakAdminUrl) { - return html ` - - ${content} - QwcOidcProvider._goToKeycloakUrl()}> - - Keycloak Admin - - - `; - } - - return content; - } - - _content() { if (QwcOidcProvider._isServiceOrHybridApp()) { switch (propertiesState.oidcGrantType) { case 'password': @@ -933,10 +912,6 @@ export class QwcOidcProvider extends QwcHotReloadElement { return result; } - static _goToKeycloakUrl() { - window.open(propertiesState.keycloakAdminUrl, '_blank').focus(); - } - static _areTokensInUrl() { return QwcOidcProvider._getHashQueryStringParam('id_token') && QwcOidcProvider._getHashQueryStringParam('access_token'); diff --git a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/controller/router-controller.js b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/controller/router-controller.js index 7b609d8b56270..d2a85ae23bd3e 100644 --- a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/controller/router-controller.js +++ b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/controller/router-controller.js @@ -122,6 +122,22 @@ export class RouterController { return false; } + addExternalLink(page){ + let path = this.getPageUrlFor(page); + if (!this.isExistingPath(path)) { + RouterController.pageMap.set(path, page); + if(RouterController.namespaceMap.has(page.namespace)){ + // Existing + RouterController.namespaceMap.get(page.namespace).push(page); + }else{ + // New + let namespacePages = []; + namespacePages.push(page); + RouterController.namespaceMap.set(page.namespace, namespacePages); + } + } + } + addRouteForMenu(page, defaultSelection){ this.addRoute(page.id, page.componentName, page.title, page, defaultSelection); } diff --git a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-extension-link.js b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-extension-link.js index c5d670deb9e5e..c514dfd82b43e 100644 --- a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-extension-link.js +++ b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-extension-link.js @@ -195,8 +195,8 @@ export class QwcExtensionLink extends QwcHotReloadElement { ${this.displayName} - ${this._renderBadge()} + ${this._renderBadge()} `; }else{ return html` @@ -204,8 +204,7 @@ export class QwcExtensionLink extends QwcHotReloadElement { loading ... - ${this._renderBadge()} - `; + ${this._renderBadge()}`; } } diff --git a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-extensions.js b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-extensions.js index 6b845302c3c86..7c97fa002e869 100644 --- a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-extensions.js +++ b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-extensions.js @@ -58,6 +58,8 @@ export class QwcExtensions extends observeState(LitElement) { if(page.embed){ // we need to register with the router import(page.componentRef); this.routerController.addRouteForExtension(page); + }else if(page.includeInSubMenu){ // we need to add the link to the submenu + this.routerController.addExternalLink(page); } }); diff --git a/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/ExternalPageBuilder.java b/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/ExternalPageBuilder.java index 5736a46757260..aad52ee93d1cb 100644 --- a/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/ExternalPageBuilder.java +++ b/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/ExternalPageBuilder.java @@ -65,7 +65,13 @@ public ExternalPageBuilder mimeType(String mimeType) { } public ExternalPageBuilder doNotEmbed() { + return doNotEmbed(false); + } + + public ExternalPageBuilder doNotEmbed(boolean includeInSubMenu) { super.embed = false; + super.includeInSubMenu = includeInSubMenu; return this; } + } \ No newline at end of file diff --git a/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/Page.java b/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/Page.java index d80b959c6a287..f088c06773dfe 100644 --- a/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/Page.java +++ b/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/Page.java @@ -21,6 +21,7 @@ public class Page { private final Map metadata; // Key value Metadata private final boolean embed; // if the component is embedded in the page. true in all cases except maybe external pages + private final boolean includeInSubMenu; // if this link should be added to the submenu. true in all cases except maybe external pages private final boolean internalComponent; // True if this component is provided by dev-ui (usually provided by the extension) private String namespace = null; // The namespace can be the extension path or, if internal, qwc @@ -36,6 +37,7 @@ protected Page(String icon, String componentLink, Map metadata, boolean embed, + boolean includeInSubMenu, boolean internalComponent, String namespace, String namespaceLabel, @@ -50,6 +52,7 @@ protected Page(String icon, this.componentLink = componentLink; this.metadata = metadata; this.embed = embed; + this.includeInSubMenu = includeInSubMenu; this.internalComponent = internalComponent; this.namespace = namespace; this.namespaceLabel = namespaceLabel; @@ -125,6 +128,10 @@ public boolean isEmbed() { return embed; } + public boolean isIncludeInSubMenu() { + return includeInSubMenu; + } + public boolean isInternal() { return this.internalComponent && this.extensionId == null; } @@ -149,7 +156,8 @@ public String toString() { + ", \n\tnamespaceLabel=" + namespaceLabel + ", \n\tcomponentName=" + componentName + ", \n\tcomponentLink=" + componentLink - + ", \n\tembed=" + embed + "\n}"; + + ", \n\tembed=" + embed + + ", \n\tincludeInSubMenu=" + includeInSubMenu + "\n}"; } /** diff --git a/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/PageBuilder.java b/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/PageBuilder.java index add47ae44c884..1a0acf35d278a 100644 --- a/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/PageBuilder.java +++ b/extensions/vertx-http/dev-ui-spi/src/main/java/io/quarkus/devui/spi/page/PageBuilder.java @@ -21,6 +21,7 @@ public abstract class PageBuilder { protected String componentLink; protected Map metadata = new HashMap<>(); protected boolean embed = true; // default + protected boolean includeInSubMenu = true; // default protected boolean internalComponent = false; // default protected String namespace = null; protected String namespaceLabel = null; @@ -128,6 +129,7 @@ public Page build() { componentLink, metadata, embed, + includeInSubMenu, internalComponent, namespace, namespaceLabel, From 50498dad2a75e9450a80f22c3c2c487180cc5987 Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Tue, 13 Jun 2023 13:28:30 +1000 Subject: [PATCH 2/4] Dev UI: Make sure theme works in OIDC Signed-off-by: Phillip Kruger --- .../resources/dev-ui/qwc-oidc-provider.js | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js b/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js index 96ef5fb13f2d4..e330526fdd26b 100644 --- a/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js +++ b/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js @@ -123,26 +123,13 @@ export class QwcOidcProvider extends QwcHotReloadElement { .full-width { width: 100%; } - @media (min-width: 1200px) { - .container { - max-width: 1140px; - } - } + .container { width: 93%; margin: auto; align-items: stretch; - border: 1px solid rgba(0,0,0,.125); - border-radius: var(--lumo-border-radius-l); - } - @media (min-width: 768px) { - .container-btn-mn-lf { - margin-left: 16.666667%; - } - } - .container-btn { - --lumo-success-color: #28a745; } + .frm-field { width: 83.333333%; margin-left: 20px; @@ -161,6 +148,9 @@ export class QwcOidcProvider extends QwcHotReloadElement { .hidden { display: none; } + .heading { + font-size: larger; + } .error-color { color: var(--lumo-error-text-color); } @@ -174,7 +164,7 @@ export class QwcOidcProvider extends QwcHotReloadElement { color: var(--lumo-primary-text-color); } .black-5pct { - background-color: var(--lumo-shade-5pct); + background-color: var(--lumo-contrast-10pct); } .margin-l-m { margin-left: var(--lumo-space-m); @@ -210,11 +200,10 @@ export class QwcOidcProvider extends QwcHotReloadElement { } } .decoded-token, .encoded-token { - background-color: var(--lumo-contrast-90pct); - color: var(--lumo-success-contrast-color); padding: 0 var(--lumo-space-m); word-break: break-word; word-wrap: break-word; + background-color: var(--lumo-contrast-5pct); } .decoded-token pre { white-space: break-spaces; @@ -374,7 +363,7 @@ export class QwcOidcProvider extends QwcHotReloadElement { return html` ${servicePathForm} - this._signInToService()}> Log into your Web Application @@ -433,7 +422,7 @@ export class QwcOidcProvider extends QwcHotReloadElement { ${extraFields} ${servicePathForm} - + Test service @@ -647,12 +636,18 @@ export class QwcOidcProvider extends QwcHotReloadElement { ${keycloakRealms} - this._signInToOidcProviderAndGetTokens()}> - - Log into Single Page Application - + + + this._signInToOidcProviderAndGetTokens()}> + + Log into Single Page Application + + + + + @@ -667,7 +662,7 @@ export class QwcOidcProvider extends QwcHotReloadElement { - Your tokens + Your tokens Logged in as ${propertiesState.userName} - Test your service + Test your service QwcOidcProvider._navigateToSwaggerUi()} ?hidden="${!propertiesState.swaggerIsAvailable}"> @@ -754,7 +749,7 @@ export class QwcOidcProvider extends QwcHotReloadElement { ${servicePathForm} - + this._testServiceWithAccessToken()}> With Access Token From 6563ae61025b5a5a61c8df4bbd67a93f9d5d629d Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Tue, 13 Jun 2023 13:57:37 +1000 Subject: [PATCH 3/4] Dev UI: Fix GraphQL Link in OIDC Signed-off-by: Phillip Kruger --- .../src/main/resources/dev-ui/qwc-oidc-provider.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js b/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js index e330526fdd26b..855e0748477b7 100644 --- a/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js +++ b/extensions/oidc/deployment/src/main/resources/dev-ui/qwc-oidc-provider.js @@ -26,7 +26,7 @@ class OidcPropertiesState extends LitState { hideImplicitLoggedIn: false, hideImplLoggedOut: false, swaggerUiPath: null, - graphQlUiPath: null, + graphqlUiPath: null, oidcProviderName: null, oidcApplicationType: null, oidcGrantType: null, @@ -83,7 +83,7 @@ class OidcPropertiesState extends LitState { propertiesState.keycloakAdminUrl = response.result.keycloakAdminUrl; propertiesState.keycloakRealms = response.result.keycloakRealms; propertiesState.swaggerUiPath = response.result.swaggerUiPath; - propertiesState.graphQlUiPath = response.result.graphQlUiPath; + propertiesState.graphqlUiPath = response.result.graphqlUiPath; return { // logout === true will trigger query params removal @@ -1103,7 +1103,7 @@ export class QwcOidcProvider extends QwcHotReloadElement { } static _navigateToGraphQLUiWithToken(token) { - let url = propertiesState.graphQlUiPath; + let url = propertiesState.graphqlUiPath; const headerJson = '{"authorization": "Bearer ' + token + '"}'; url += '/?' + encodeURIComponent('headers') + '=' + encodeURIComponent(headerJson); window.open(url, '_blank').focus(); From 4e5a52a64bed4d9b6bc29c69fcc8f90495a9ffe4 Mon Sep 17 00:00:00 2001 From: Phillip Kruger Date: Wed, 14 Jun 2023 13:18:43 +1000 Subject: [PATCH 4/4] Dev UI: External links should not be a tab in the sub-menu Signed-off-by: Phillip Kruger --- .../main/resources/dev-ui/qwc/qwc-header.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-header.js b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-header.js index 720e89e91b5f2..f2eb0235d4877 100644 --- a/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-header.js +++ b/extensions/vertx-http/dev-ui-resources/src/main/resources/dev-ui/qwc/qwc-header.js @@ -237,9 +237,7 @@ export class QwcHeader extends observeState(LitElement) { if(subMenu){ this._rightSideNav = html` ${subMenu.links.map(link => - html` - ${this._renderSubMenuLink(link)} - ` + html`${this._renderTab(subMenu.index, link)}` )} `; }else{ @@ -251,7 +249,19 @@ export class QwcHeader extends observeState(LitElement) { } } - _renderSubMenuLink(link){ + _renderTab(index, link){ + if(!link.page.embed && link.page.includeInSubMenu){ + return html` + ${this._renderSubMenuLink(index, link)} + `; + }else{ + return html` + ${this._renderSubMenuLink(index, link)} + `; + } + } + + _renderSubMenuLink(index, link){ let relativePath = link.page.id.replace(link.page.namespace + "/", "");