Skip to content

Commit

Permalink
Merge pull request #34002 from phillip-kruger/dev-ui-allow-external-l…
Browse files Browse the repository at this point in the history
…ink-in-submenu

Dev UI: OIDC Updates
  • Loading branch information
phillip-kruger authored Jun 15, 2023
2 parents 1c8d564 + 4e5a52a commit 212ef5a
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -81,7 +82,9 @@ void produceProviderComponent(Optional<KeycloakDevServicesConfigBuildItem> confi
@SuppressWarnings("unchecked")
Map<String, String> users = (Map<String, String>) configProps.get().getProperties().get("oidc.users");

var cardPage = createProviderWebComponent(
String keycloakAdminUrl = configProps.get().getConfig().get("keycloak.url");

CardPageBuildItem cardPageBuildItem = createProviderWebComponent(
recorder,
capabilities,
"Keycloak",
Expand All @@ -97,11 +100,17 @@ void produceProviderComponent(Optional<KeycloakDevServicesConfigBuildItem> 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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class OidcPropertiesState extends LitState {
hideImplicitLoggedIn: false,
hideImplLoggedOut: false,
swaggerUiPath: null,
graphQlUiPath: null,
graphqlUiPath: null,
oidcProviderName: null,
oidcApplicationType: null,
oidcGrantType: null,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -161,6 +148,9 @@ export class QwcOidcProvider extends QwcHotReloadElement {
.hidden {
display: none;
}
.heading {
font-size: larger;
}
.error-color {
color: var(--lumo-error-text-color);
}
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -351,27 +340,6 @@ export class QwcOidcProvider extends QwcHotReloadElement {
}

_renderProvider() {
const content = this._content();
if (propertiesState.keycloakAdminUrl) {
return html `
<vaadin-horizontal-layout
theme="spacing padding"
style="align-items: center"
>
${content}
<vaadin-button class="keycloak-btn" theme="tertiary"
@click=${() => QwcOidcProvider._goToKeycloakUrl()}>
<vaadin-icon icon="font-awesome-solid:key" slot="prefix" class="btn-icon"></vaadin-icon>
Keycloak Admin
</vaadin-button>
</vaadin-horizontal-layout>
`;
}

return content;
}

_content() {
if (QwcOidcProvider._isServiceOrHybridApp()) {
switch (propertiesState.oidcGrantType) {
case 'password':
Expand All @@ -395,7 +363,7 @@ export class QwcOidcProvider extends QwcHotReloadElement {
return html`
<vaadin-vertical-layout theme="spacing padding" class="height-4xl container">
${servicePathForm}
<vaadin-button class="container-btn-mn-lf container-btn" theme="primary success"
<vaadin-button theme="primary success"
@click=${() => this._signInToService()}>
Log into your Web Application
</vaadin-button>
Expand Down Expand Up @@ -454,7 +422,7 @@ export class QwcOidcProvider extends QwcHotReloadElement {
${extraFields}
${servicePathForm}
<vaadin-horizontal-layout class="full-width">
<vaadin-horizontal-layout class="container-btn-mn-lf full-width">
<vaadin-horizontal-layout class="full-width">
<vaadin-button class="fill-space margin-right-auto" theme="primary" title="Test service"
@click=${testSvcFun}>
Test service
Expand Down Expand Up @@ -668,12 +636,18 @@ export class QwcOidcProvider extends QwcHotReloadElement {
<vaadin-vertical-layout theme="spacing padding" class="height-4xl container"
?hidden="${propertiesState.hideImplLoggedOut}">
${keycloakRealms}
<vaadin-button class="container-btn-mn-lf container-btn" theme="primary success"
title="Log into Single Page Application to Get Access and ID Tokens"
@click=${() => this._signInToOidcProviderAndGetTokens()}>
<vaadin-icon icon="font-awesome-solid:user" slot="prefix" class="btn-icon"></vaadin-icon>
Log into Single Page Application
</vaadin-button>
<vaadin-form-layout class="txt-field-form full-width">
<vaadin-form-item class="full-width">
<vaadin-button theme="primary success"
title="Log into Single Page Application to Get Access and ID Tokens"
@click=${() => this._signInToOidcProviderAndGetTokens()}>
<vaadin-icon icon="font-awesome-solid:user" slot="prefix" class="btn-icon"></vaadin-icon>
Log into Single Page Application
</vaadin-button>
</vaadin-form-item>
</vaadin-form-layout>
</vaadin-vertical-layout>
<vaadin-horizontal-layout theme="spacing padding" class="height-4xl container vertical-center"
?hidden="${propertiesState.hideLogInErr}">
Expand All @@ -688,7 +662,7 @@ export class QwcOidcProvider extends QwcHotReloadElement {
<vaadin-vertical-layout class="full-width" ?hidden="${propertiesState.hideImplicitLoggedIn}">
<vaadin-vertical-layout class="height-4xl container">
<vaadin-horizontal-layout class="black-5pct vertical-center" theme="padding">
<span class="margin-right-auto default-cursor">Your tokens</span>
<span class="margin-right-auto default-cursor heading">Your tokens</span>
<span class="margin-right-space-m ${classMap({'display-none': !propertiesState.userName})}">
Logged in as ${propertiesState.userName}</span>
<vaadin-button theme="tertiary small" title="Click to logout and start again"
Expand Down Expand Up @@ -756,7 +730,7 @@ export class QwcOidcProvider extends QwcHotReloadElement {
</vaadin-vertical-layout>
<vaadin-vertical-layout theme="spacing" class="height-4xl container margin-top-space-m">
<vaadin-horizontal-layout class="black-5pct vertical-center" theme="padding">
<span class="margin-right-auto default-cursor">Test your service</span>
<span class="margin-right-auto default-cursor heading">Test your service</span>
<vaadin-button theme="tertiary small" title="Test in Swagger UI"
@click=${() => QwcOidcProvider._navigateToSwaggerUi()}
?hidden="${!propertiesState.swaggerIsAvailable}">
Expand All @@ -775,7 +749,7 @@ export class QwcOidcProvider extends QwcHotReloadElement {
<vaadin-vertical-layout theme="padding">
${servicePathForm}
<vaadin-horizontal-layout class="full-width">
<vaadin-horizontal-layout class="container-btn-mn-lf full-width">
<vaadin-horizontal-layout class="full-width">
<vaadin-button class="fill-space" theme="primary" title="Test With Access Token"
@click=${() => this._testServiceWithAccessToken()}>
With Access Token
Expand Down Expand Up @@ -933,10 +907,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');
Expand Down Expand Up @@ -1133,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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,17 +195,16 @@ export class QwcExtensionLink extends QwcHotReloadElement {
<vaadin-icon class="icon" icon="${this.iconName}"></vaadin-icon>
${this.displayName}
</span>
${this._renderBadge()}
</a>
${this._renderBadge()}
`;
}else{
return html`<a class="extensionLink" ?router-ignore=true>
<span class="iconAndName">
<vaadin-icon class="icon" icon="font-awesome-solid:spinner"></vaadin-icon>
loading ...
</span>
${this._renderBadge()}
</a>`;
</a>${this._renderBadge()}`;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,7 @@ export class QwcHeader extends observeState(LitElement) {
if(subMenu){
this._rightSideNav = html`<vaadin-tabs selected="${subMenu.index}">
${subMenu.links.map(link =>
html`<vaadin-tab>
${this._renderSubMenuLink(link)}
</vaadin-tab>`
html`${this._renderTab(subMenu.index, link)}`
)}
</vaadin-tabs>`;
}else{
Expand All @@ -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`<vaadin-tab>
${this._renderSubMenuLink(index, link)}
</vaadin-tab>`;
}
}

_renderSubMenuLink(index, link){

let relativePath = link.page.id.replace(link.page.namespace + "/", "");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class Page {
private final Map<String, String> 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
Expand All @@ -36,6 +37,7 @@ protected Page(String icon,
String componentLink,
Map<String, String> metadata,
boolean embed,
boolean includeInSubMenu,
boolean internalComponent,
String namespace,
String namespaceLabel,
Expand All @@ -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;
Expand Down Expand Up @@ -125,6 +128,10 @@ public boolean isEmbed() {
return embed;
}

public boolean isIncludeInSubMenu() {
return includeInSubMenu;
}

public boolean isInternal() {
return this.internalComponent && this.extensionId == null;
}
Expand All @@ -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}";
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public abstract class PageBuilder<T> {
protected String componentLink;
protected Map<String, String> 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;
Expand Down Expand Up @@ -128,6 +129,7 @@ public Page build() {
componentLink,
metadata,
embed,
includeInSubMenu,
internalComponent,
namespace,
namespaceLabel,
Expand Down

0 comments on commit 212ef5a

Please sign in to comment.