KEYCLOAK-14531 Welcome cards should be driven by content.json
`content.js` is now `content.json` it's used in freemarker to create the cards
This commit is contained in:
parent
1b988cc12e
commit
55291bad76
10 changed files with 111 additions and 114 deletions
|
@ -30,11 +30,14 @@ import javax.ws.rs.Path;
|
|||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Scanner;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
@ -104,7 +107,15 @@ public class AccountConsole {
|
|||
map.put("msgJSON", messagesToJsonString(messages));
|
||||
map.put("supportedLocales", supportedLocales(messages));
|
||||
map.put("properties", theme.getProperties());
|
||||
|
||||
map.put("theme", (Function<String, String>) file -> {
|
||||
try {
|
||||
final InputStream resource = theme.getResourceAsStream(file);
|
||||
return new Scanner(resource, "UTF-8").useDelimiter("\\A").next();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("could not load file", e);
|
||||
}
|
||||
});
|
||||
|
||||
EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
|
||||
map.put("isEventsEnabled", eventStore != null && realm.isEventsEnabled());
|
||||
map.put("isAuthorizationEnabled", true);
|
||||
|
|
|
@ -64,14 +64,14 @@ public abstract class AbstractLoggedInPage extends AbstractAccountPage {
|
|||
}
|
||||
|
||||
/**
|
||||
* This is currently used only by navigation menu to identify nav items. See content.js in themes module for IDs.
|
||||
* This is currently used only by navigation menu to identify nav items. See content.json in themes module for IDs.
|
||||
*
|
||||
* @return page ID
|
||||
*/
|
||||
public abstract String getPageId();
|
||||
|
||||
/**
|
||||
* In case the page is placed is a subpage, i.e. placed in a subsection. See content.js in themes module for IDs.
|
||||
* In case the page is placed is a subpage, i.e. placed in a subsection. See content.json in themes module for IDs.
|
||||
*
|
||||
* @return parent page ID
|
||||
*/
|
||||
|
|
|
@ -41,21 +41,21 @@ public class WelcomeScreen extends AbstractAccountPage {
|
|||
@FindBy(xpath = "//*[@id='" + ROOT_ELEMENT_ID + "']//header")
|
||||
private WelcomeScreenHeader header;
|
||||
|
||||
@FindBy(xpath = "//*[@id='landingPersonalInfoLink']/a")
|
||||
@FindBy(xpath = "//*[@id='landingpersonal-infoLink']/a")
|
||||
private WebElement personalInfoLink;
|
||||
@FindBy(xpath = "//*[@id='landingChangePasswordLink']/a")
|
||||
private WebElement changePasswordLink;
|
||||
@FindBy(xpath = "//*[@id='landingAuthenticatorLink']/a")
|
||||
private WebElement authenticatorLink;
|
||||
@FindBy(xpath = "//*[@id='landingDeviceActivityLink']/a")
|
||||
@FindBy(xpath = "//*[@id='landingdevice-activityLink']/a")
|
||||
private WebElement deviceActivityLink;
|
||||
@FindBy(xpath = "//*[@id='landingLinkedAccountsLink']/a")
|
||||
@FindBy(xpath = "//*[@id='landinglinked-accountsLink']/a")
|
||||
private WebElement linkedAccountsLink;
|
||||
@FindBy(xpath = "//*[@id='landingApplicationsLink']/a")
|
||||
@FindBy(xpath = "//*[@id='landingapplicationsLink']/a")
|
||||
private WebElement applicationsLink;
|
||||
@FindBy(id = "landingMyResourcesCard")
|
||||
@FindBy(id = "landingresourcesCard")
|
||||
private WebElement myResourcesCard;
|
||||
@FindBy(xpath = "//*[@id='landingMyResourcesLink']/a")
|
||||
@FindBy(xpath = "//*[@id='landingresourcesLink']/a")
|
||||
private WebElement myResourcesLink;
|
||||
@FindBy(id = "landingLogo")
|
||||
private WebElement logoLink;
|
||||
|
|
|
@ -99,6 +99,10 @@
|
|||
</#list>
|
||||
</#if>
|
||||
|
||||
<script>
|
||||
var content = <#include "resources/content.json"/>
|
||||
</script>
|
||||
|
||||
<#if properties.styles?has_content>
|
||||
<#list properties.styles?split(' ') as style>
|
||||
<link href="${resourceUrl}/${style}" rel="stylesheet"/>
|
||||
|
@ -222,52 +226,26 @@
|
|||
</section>
|
||||
<section class="pf-c-page__main-section">
|
||||
<div class="pf-l-gallery pf-m-gutter">
|
||||
<div class="pf-l-gallery__item">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-content">
|
||||
<h2><i class="pf-icon pf-icon-user"></i> ${msg("personalInfoHtmlTitle")}</h2>
|
||||
<h6>${msg("personalInfoIntroMessage")}</h6>
|
||||
</div>
|
||||
<div class="pf-c-card__body pf-c-content">
|
||||
<h5 id="landingPersonalInfoLink" onclick="toggleReact()"><a href="#personal-info">${msg("personalInfoHtmlTitle")}</a></h5>
|
||||
<#assign content=theme.apply("/content.json")?eval>
|
||||
<#list content as item>
|
||||
<div class="pf-l-gallery__item">
|
||||
<div class="pf-c-card" id="landing${item.id}Card">
|
||||
<div class="pf-c-card__header pf-c-content">
|
||||
<h2><i class="pf-icon ${item.icon}"></i> ${msg(item.label)}</h2>
|
||||
<h6>${msg(item.descriptionLabel)}</h6>
|
||||
</div>
|
||||
<div class="pf-c-card__body pf-c-content">
|
||||
<#if item.content??>
|
||||
<#list item.content as sub>
|
||||
<h5 id="landing${sub.id}Link" onclick="toggleReact()"><a href="#${sub.path}">${msg(sub.label)}</a></h5>
|
||||
</#list>
|
||||
<#else>
|
||||
<h5 id="landing${item.id}Link" onclick="toggleReact()"><a href="#${item.path}">${msg(item.label)}</a></h5>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-l-gallery__item">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-content">
|
||||
<h2><i class="pf-icon pf-icon-security"></i> ${msg("accountSecurityTitle")}</h2>
|
||||
<h6>${msg("accountSecurityIntroMessage")}</h6>
|
||||
</div>
|
||||
<div class="pf-c-card__body pf-c-content">
|
||||
<h5 id="landingSigningInLink" onclick="toggleReact()"><a href="#security/signingin">${msg("signingIn")}</a></h5>
|
||||
<h5 id="landingDeviceActivityLink" onclick="toggleReact()"><a href="#security/device-activity">${msg("deviceActivityHtmlTitle")}</a></h5>
|
||||
<h5 id="landingLinkedAccountsLink" style="display:none" onclick="toggleReact()"><a href="#security/linked-accounts">${msg("linkedAccountsHtmlTitle")}</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-l-gallery__item">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-content">
|
||||
<h2><i class="pf-icon pf-icon-applications"></i> ${msg("applicationsHtmlTitle")}</h2>
|
||||
<h6>${msg("applicationsIntroMessage")}</h6>
|
||||
</div>
|
||||
<div class="pf-c-card__body pf-c-content">
|
||||
<h5 id="landingApplicationsLink" onclick="toggleReact()"><a href="#applications">${msg("applicationsHtmlTitle")}</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pf-l-gallery__item" id="landingMyResourcesCard" style="display:none">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-content">
|
||||
<h2><i class="pf-icon pf-icon-repository"></i> ${msg("myResources")}</h2>
|
||||
<h6>${msg("resourceIntroMessage")}</h6>
|
||||
</div>
|
||||
<div class="pf-c-card__body pf-c-content">
|
||||
<h5 id="landingMyResourcesLink" onclick="toggleReact()"><a href="#resources">${msg("myResources")}</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</#list>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
@ -275,13 +253,13 @@
|
|||
</div>
|
||||
|
||||
<script>
|
||||
if (features.isLinkedAccountsEnabled) {
|
||||
document.getElementById("landingLinkedAccountsLink").style.display='block';
|
||||
if (!features.isLinkedAccountsEnabled) {
|
||||
document.getElementById("landinglinked-accountsLink").style.display='none';
|
||||
};
|
||||
|
||||
// Hidden until feature is complete.
|
||||
if (features.isMyResourcesEnabled) {
|
||||
document.getElementById("landingMyResourcesCard").style.display='block';
|
||||
if (!features.isMyResourcesEnabled) {
|
||||
document.getElementById("landingresourcesCard").style.display='none';
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
# Don't ignore these
|
||||
!WelcomePageScripts.js
|
||||
!content.js
|
||||
!content.json
|
||||
|
||||
public/app.css
|
||||
public/base.css
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
|
||||
var content = [
|
||||
{
|
||||
id: 'personal-info',
|
||||
path: 'personal-info',
|
||||
label: 'personalInfoHtmlTitle',
|
||||
modulePath: '/content/account-page/AccountPage.js',
|
||||
componentName: 'AccountPage'
|
||||
},
|
||||
{
|
||||
id: 'security',
|
||||
label: 'Account Security',
|
||||
content: [
|
||||
{
|
||||
id: 'signingin',
|
||||
path: 'security/signingin',
|
||||
label: 'signingIn',
|
||||
modulePath: '/content/signingin-page/SigningInPage.js',
|
||||
componentName: 'SigningInPage',
|
||||
},
|
||||
{
|
||||
id: 'device-activity',
|
||||
path: 'security/device-activity',
|
||||
label: 'device-activity',
|
||||
modulePath: '/content/device-activity-page/DeviceActivityPage.js',
|
||||
componentName: 'DeviceActivityPage'
|
||||
},
|
||||
{
|
||||
id: 'linked-accounts',
|
||||
path: 'security/linked-accounts',
|
||||
label: 'linkedAccountsHtmlTitle',
|
||||
modulePath: '/content/linked-accounts-page/LinkedAccountsPage.js',
|
||||
componentName: 'LinkedAccountsPage',
|
||||
hidden: !features.isLinkedAccountsEnabled
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'applications',
|
||||
path: 'applications',
|
||||
label: 'applications',
|
||||
modulePath: '/content/applications-page/ApplicationsPage.js',
|
||||
componentName: 'ApplicationsPage'
|
||||
},
|
||||
{
|
||||
id: 'resources',
|
||||
path: 'resources',
|
||||
label: 'resources',
|
||||
modulePath: '/content/my-resources-page/MyResourcesPage.js',
|
||||
componentName: 'MyResourcesPage',
|
||||
hidden: !features.isMyResourcesEnabled
|
||||
}
|
||||
];
|
|
@ -0,0 +1,60 @@
|
|||
[
|
||||
{
|
||||
"id": "personal-info",
|
||||
"path": "personal-info",
|
||||
"icon": "pf-icon-user",
|
||||
"label": "personalInfoHtmlTitle",
|
||||
"descriptionLabel": "personalInfoIntroMessage",
|
||||
"modulePath": "/content/account-page/AccountPage.js",
|
||||
"componentName": "AccountPage"
|
||||
},
|
||||
{
|
||||
"id": "security",
|
||||
"icon": "pf-icon-security",
|
||||
"label": "Account Security",
|
||||
"descriptionLabel": "accountSecurityIntroMessage",
|
||||
"content": [
|
||||
{
|
||||
"id": "signingin",
|
||||
"path": "security/signingin",
|
||||
"label": "signingIn",
|
||||
"modulePath": "/content/signingin-page/SigningInPage.js",
|
||||
"componentName": "SigningInPage"
|
||||
},
|
||||
{
|
||||
"id": "device-activity",
|
||||
"path": "security/device-activity",
|
||||
"label": "device-activity",
|
||||
"modulePath": "/content/device-activity-page/DeviceActivityPage.js",
|
||||
"componentName": "DeviceActivityPage"
|
||||
},
|
||||
{
|
||||
"id": "linked-accounts",
|
||||
"path": "security/linked-accounts",
|
||||
"label": "linkedAccountsHtmlTitle",
|
||||
"modulePath": "/content/linked-accounts-page/LinkedAccountsPage.js",
|
||||
"componentName": "LinkedAccountsPage",
|
||||
"hidden": "isLinkedAccountsEnabled"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "applications",
|
||||
"icon": "pf-icon-applications",
|
||||
"path": "applications",
|
||||
"label": "applications",
|
||||
"descriptionLabel": "applicationsIntroMessage",
|
||||
"modulePath": "/content/applications-page/ApplicationsPage.js",
|
||||
"componentName": "ApplicationsPage"
|
||||
},
|
||||
{
|
||||
"id": "resources",
|
||||
"icon": "pf-icon-repository",
|
||||
"path": "resources",
|
||||
"label": "resources",
|
||||
"descriptionLabel": "resourceIntroMessage",
|
||||
"modulePath": "/content/my-resources-page/MyResourcesPage.js",
|
||||
"componentName": "MyResourcesPage",
|
||||
"hidden": "isMyResourcesEnabled"
|
||||
}
|
||||
]
|
|
@ -24,7 +24,7 @@ export interface ContentItem {
|
|||
id?: string;
|
||||
label: string;
|
||||
labelParams?: string[];
|
||||
hidden?: boolean;
|
||||
hidden?: string;
|
||||
groupId: string; // computed value
|
||||
itemId: string; // computed value
|
||||
};
|
||||
|
|
|
@ -31,6 +31,7 @@ declare const keycloak: KeycloakClient;
|
|||
|
||||
declare let isReactLoading: boolean;
|
||||
declare function toggleReact(): void;
|
||||
declare const features: { [key: string]: boolean; };
|
||||
|
||||
export interface MainProps {}
|
||||
export class Main extends React.Component<MainProps> {
|
||||
|
@ -66,7 +67,7 @@ function removeHidden(items: ContentItem[]): ContentItem[] {
|
|||
const visible: ContentItem[] = [];
|
||||
|
||||
for (let item of items) {
|
||||
if (item.hidden) continue;
|
||||
if (item.hidden && !features[item.hidden]) continue;
|
||||
|
||||
if (isExpansion(item)) {
|
||||
visible.push(item);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
parent=base
|
||||
deprecatedMode=false
|
||||
scripts=welcome-page-scripts.js content.js
|
||||
scripts=welcome-page-scripts.js
|
||||
developmentMode=false
|
||||
|
||||
# This is the logo in upper lefthand corner.
|
||||
|
|
Loading…
Reference in a new issue