keycloak-uncached
Changes
services/src/main/java/org/keycloak/services/resources/account/AccountCredentialResource.java 10(+8 -2)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java 7(+4 -3)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/account-service/account.service.ts 14(+8 -6)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/password-page/password-page.component.html 8(+4 -4)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/password-page/password-page.component.ts 25(+22 -3)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/ngx-translate/translate.util.ts 10(+8 -2)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/notification/inline-notification.component.css 29(+29 -0)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/page/side-nav-item.ts 33(+0 -33)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/side-nav/side-nav.component.css 0(+0 -0)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/side-nav/side-nav.component.html 71(+0 -71)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/side-nav/side-nav.component.ts 115(+0 -115)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/top-nav/notification.component.css 0(+0 -0)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/top-nav/notification.component.html 12(+0 -12)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/top-nav/notification.component.ts 43(+0 -43)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/top-nav/toast.notifier.ts 75(+0 -75)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/top-nav/top-nav.component.css 0(+0 -0)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/top-nav/top-nav.component.html 42(+0 -42)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/top-nav/top-nav.component.ts 69(+0 -69)
themes/src/main/resources/theme/keycloak-preview/account/resources/app/vertical-nav/vertical-nav.component.html 3(+1 -2)
Details
diff --git a/core/src/main/java/org/keycloak/representations/idm/ErrorRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ErrorRepresentation.java
index f9c9071..64f3484 100644
--- a/core/src/main/java/org/keycloak/representations/idm/ErrorRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ErrorRepresentation.java
@@ -22,6 +22,7 @@ package org.keycloak.representations.idm;
*/
public class ErrorRepresentation {
private String errorMessage;
+ private Object[] params;
public ErrorRepresentation() {
}
@@ -33,4 +34,12 @@ public class ErrorRepresentation {
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
+
+ public Object[] getParams() {
+ return this.params;
+ }
+
+ public void setParams(Object[] params) {
+ this.params = params;
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/ErrorResponse.java b/services/src/main/java/org/keycloak/services/ErrorResponse.java
index cb1ad54..492541f 100755
--- a/services/src/main/java/org/keycloak/services/ErrorResponse.java
+++ b/services/src/main/java/org/keycloak/services/ErrorResponse.java
@@ -32,8 +32,13 @@ public class ErrorResponse {
}
public static Response error(String message, Response.Status status) {
+ return ErrorResponse.error(message, null, status);
+ }
+
+ public static Response error(String message, Object[] params, Response.Status status) {
ErrorRepresentation error = new ErrorRepresentation();
error.setErrorMessage(message);
+ error.setParams(params);
return Response.status(status).entity(error).type(MediaType.APPLICATION_JSON).build();
}
diff --git a/services/src/main/java/org/keycloak/services/resources/account/AccountCredentialResource.java b/services/src/main/java/org/keycloak/services/resources/account/AccountCredentialResource.java
index 3af53c5..125de8b 100644
--- a/services/src/main/java/org/keycloak/services/resources/account/AccountCredentialResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/account/AccountCredentialResource.java
@@ -20,6 +20,8 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
+import org.keycloak.models.ModelException;
+import org.keycloak.services.messages.Messages;
public class AccountCredentialResource {
@@ -62,10 +64,14 @@ public class AccountCredentialResource {
UserCredentialModel cred = UserCredentialModel.password(update.getCurrentPassword());
if (!session.userCredentialManager().isValid(realm, user, cred)) {
event.error(org.keycloak.events.Errors.INVALID_USER_CREDENTIALS);
- return ErrorResponse.error(Errors.INVALID_CREDENTIALS, Response.Status.BAD_REQUEST);
+ return ErrorResponse.error(Messages.INVALID_PASSWORD_EXISTING, Response.Status.BAD_REQUEST);
}
- session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password(update.getNewPassword(), false));
+ try {
+ session.userCredentialManager().updateCredential(realm, user, UserCredentialModel.password(update.getNewPassword(), false));
+ } catch (ModelException e) {
+ return ErrorResponse.error(e.getMessage(), e.getParameters(), Response.Status.BAD_REQUEST);
+ }
return Response.ok().build();
}
diff --git a/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java b/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java
index 32d88de..48e55ee 100755
--- a/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java
+++ b/services/src/main/java/org/keycloak/services/resources/account/AccountRestService.java
@@ -54,6 +54,7 @@ import javax.ws.rs.core.UriInfo;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import org.keycloak.services.messages.Messages;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -146,27 +147,27 @@ public class AccountRestService {
if (usernameChanged) {
UserModel existing = session.users().getUserByUsername(userRep.getUsername(), realm);
if (existing != null) {
- return ErrorResponse.exists(Errors.USERNAME_EXISTS);
+ return ErrorResponse.exists(Messages.USERNAME_EXISTS);
}
user.setUsername(userRep.getUsername());
}
} else if (usernameChanged) {
- return ErrorResponse.error(Errors.READ_ONLY_USERNAME, Response.Status.BAD_REQUEST);
+ return ErrorResponse.error(Messages.READ_ONLY_USERNAME, Response.Status.BAD_REQUEST);
}
boolean emailChanged = userRep.getEmail() != null && !userRep.getEmail().equals(user.getEmail());
if (emailChanged && !realm.isDuplicateEmailsAllowed()) {
UserModel existing = session.users().getUserByEmail(userRep.getEmail(), realm);
if (existing != null) {
- return ErrorResponse.exists(Errors.EMAIL_EXISTS);
+ return ErrorResponse.exists(Messages.EMAIL_EXISTS);
}
}
if (realm.isRegistrationEmailAsUsername() && !realm.isDuplicateEmailsAllowed()) {
UserModel existing = session.users().getUserByUsername(userRep.getEmail(), realm);
if (existing != null) {
- return ErrorResponse.exists(Errors.USERNAME_EXISTS);
+ return ErrorResponse.exists(Messages.USERNAME_EXISTS);
}
}
@@ -200,7 +201,7 @@ public class AccountRestService {
return Cors.add(request, Response.ok()).auth().allowedOrigins(auth.getToken()).build();
} catch (ReadOnlyException e) {
- return ErrorResponse.error(Errors.READ_ONLY_USER, Response.Status.BAD_REQUEST);
+ return ErrorResponse.error(Messages.READ_ONLY_USER, Response.Status.BAD_REQUEST);
}
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java
index 6dbade1..52ffe3e 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountRestServiceTest.java
@@ -41,6 +41,7 @@ import java.util.List;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.*;
+import org.keycloak.services.messages.Messages;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -119,7 +120,7 @@ public class AccountRestServiceTest extends AbstractTestRealmKeycloakTest {
assertEquals("bobby@localhost", user.getEmail());
user.setEmail("john-doh@localhost");
- updateError(user, 409, "email_exists");
+ updateError(user, 409, Messages.EMAIL_EXISTS);
user.setEmail("test-user@localhost");
user = updateAndGet(user);
@@ -131,7 +132,7 @@ public class AccountRestServiceTest extends AbstractTestRealmKeycloakTest {
assertEquals("updatedusername", user.getUsername());
user.setUsername("john-doh@localhost");
- updateError(user, 409, "username_exists");
+ updateError(user, 409, Messages.USERNAME_EXISTS);
user.setUsername("test-user@localhost");
user = updateAndGet(user);
@@ -142,7 +143,7 @@ public class AccountRestServiceTest extends AbstractTestRealmKeycloakTest {
adminClient.realm("test").update(realmRep);
user.setUsername("updatedUsername2");
- updateError(user, 400, "username_read_only");
+ updateError(user, 400, Messages.READ_ONLY_USERNAME);
}
private UserRepresentation updateAndGet(UserRepresentation user) throws IOException {
diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/account-service/account.service.ts b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/account-service/account.service.ts
index 860408d..f13d921 100644
--- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/account-service/account.service.ts
+++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/account-service/account.service.ts
@@ -18,8 +18,10 @@
import {Injectable} from '@angular/core';
import {Http, Response, RequestOptionsArgs} from '@angular/http';
-import {ToastNotifier, ToastNotification} from '../top-nav/toast.notifier';
+import {KeycloakNotificationService} from '../notification/keycloak-notification.service';
import {KeycloakService} from '../keycloak-service/keycloak.service';
+
+import {NotificationType} from 'patternfly-ng/notification';
/**
*
@@ -31,8 +33,8 @@ export class AccountServiceClient {
private accountUrl: string;
constructor(protected http: Http,
- protected kcSvc: KeycloakService,
- protected notifier: ToastNotifier) {
+ protected kcSvc: KeycloakService,
+ protected kcNotifySvc: KeycloakNotificationService) {
this.accountUrl = kcSvc.authServerUrl() + 'realms/' + kcSvc.realm() + '/account';
}
@@ -56,7 +58,7 @@ export class AccountServiceClient {
private handleAccountUpdated(responseHandler: Function, res: Response, successMessage?: string) {
let message: string = "Your account has been updated.";
if (successMessage) message = successMessage;
- this.notifier.emit(new ToastNotification(message, "success"));
+ this.kcNotifySvc.notify(message, NotificationType.SUCCESS);
responseHandler(res);
}
@@ -102,8 +104,8 @@ export class AccountServiceClient {
if (not500Error && response.json().hasOwnProperty('error_description')) {
message = response.json().error_description;
}
-
- this.notifier.emit(new ToastNotification(message, "error"));
+
+ this.kcNotifySvc.notify(message, NotificationType.DANGER, response.json().params);
}
}
diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/app.module.ts b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/app.module.ts
index 82a2eec..ce17228 100644
--- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/app.module.ts
+++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/app.module.ts
@@ -28,30 +28,28 @@ import { KeycloakService } from './keycloak-service/keycloak.service';
import { KEYCLOAK_HTTP_PROVIDER } from './keycloak-service/keycloak.http';
import {KeycloakGuard} from './keycloak-service/keycloak.guard';
-import {ResponsivenessService} from './responsiveness-service/responsiveness.service'
+import {ResponsivenessService} from './responsiveness-service/responsiveness.service';
+import {KeycloakNotificationService} from './notification/keycloak-notification.service';
import { AccountServiceClient } from './account-service/account.service';
import {TranslateUtil} from './ngx-translate/translate.util';
import { DeclaredVarTranslateLoader } from './ngx-translate/declared.var.translate.loader';
import { AppComponent } from './app.component';
-import { TopNavComponent } from './top-nav/top-nav.component';
-import { NotificationComponent } from './top-nav/notification.component';
-import { ToastNotifier } from './top-nav/toast.notifier';
-import { SideNavComponent } from './side-nav/side-nav.component';
import {VerticalNavComponent} from './vertical-nav/vertical-nav.component';
+import {InlineNotification} from './notification/inline-notification-component';
+
+import { VerticalNavigationModule } from 'patternfly-ng/navigation';
+import {InlineNotificationModule} from 'patternfly-ng/notification/inline-notification';
-import { NavigationModule } from 'patternfly-ng/navigation';
/* Routing Module */
import { AppRoutingModule } from './app-routing.module';
const decs = [
AppComponent,
- TopNavComponent,
- NotificationComponent,
- SideNavComponent,
VerticalNavComponent,
+ InlineNotification,
];
export const ORIGINAL_INCOMING_URL: Location = window.location;
@@ -62,7 +60,8 @@ export const ORIGINAL_INCOMING_URL: Location = window.location;
BrowserModule,
FormsModule,
HttpModule,
- NavigationModule,
+ VerticalNavigationModule,
+ InlineNotificationModule,
TranslateModule.forRoot({
loader: {provide: TranslateLoader, useClass: DeclaredVarTranslateLoader}
}),
@@ -73,9 +72,9 @@ export const ORIGINAL_INCOMING_URL: Location = window.location;
KeycloakGuard,
KEYCLOAK_HTTP_PROVIDER,
ResponsivenessService,
+ KeycloakNotificationService,
AccountServiceClient,
TranslateUtil,
- ToastNotifier,
{ provide: LocationStrategy, useClass: HashLocationStrategy }
],
bootstrap: [AppComponent]
diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/password-page/password-page.component.html b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/password-page/password-page.component.html
index c10d780..399c2c1 100644
--- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/password-page/password-page.component.html
+++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/password-page/password-page.component.html
@@ -27,23 +27,23 @@
<input readonly="" value="this is not a login form" style="display: none;" type="password">
<div class="form-group">
<label for="password" class="control-label">{{'currentPassword' | translate}}</label><span class="required">*</span>
- <input ngModel class="form-control" #password id="password" name="currentPassword" autofocus="" autocomplete="off" type="password">
+ <input ngModel required class="form-control" #password id="password" name="currentPassword" autofocus="" autocomplete="off" type="password">
</div>
<div class="form-group">
<label for="password-new" class="control-label">{{'passwordNew' | translate}}</label><span class="required">*</span>
- <input ngModel class="form-control" id="newPassword" name="newPassword" autocomplete="off" type="password">
+ <input ngModel required class="form-control" id="newPassword" name="newPassword" autocomplete="off" type="password">
</div>
<div class="form-group">
<label for="password-confirm" class="control-label">{{'passwordConfirm' | translate}}</label><span class="required">*</span>
- <input ngModel class="form-control" id="confirmation" name="confirmation" autocomplete="off" type="password">
+ <input ngModel required class="form-control" id="confirmation" name="confirmation" autocomplete="off" type="password">
</div>
<div class="form-group">
<div id="kc-form-buttons" class="submit">
<div class="">
- <button type="submit" class="btn btn-primary btn-lg" name="submitAction">{{'doSave' | translate}}</button>
+ <button [disabled]="!formGroup.form.valid" type="submit" class="btn btn-primary btn-lg" name="submitAction">{{'doSave' | translate}}</button>
</div>
</div>
</div>
diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/password-page/password-page.component.ts b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/password-page/password-page.component.ts
index 177298f..dc2684b 100644
--- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/password-page/password-page.component.ts
+++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/content/password-page/password-page.component.ts
@@ -18,7 +18,10 @@ import {Component, OnInit, ViewChild, Renderer2} from '@angular/core';
import {Response} from '@angular/http';
import {FormGroup} from '@angular/forms';
+import {NotificationType} from 'patternfly-ng/notification';
+
import {AccountServiceClient} from '../../account-service/account.service';
+import {KeycloakNotificationService} from '../../notification/keycloak-notification.service';
@Component({
selector: 'app-password-page',
@@ -30,18 +33,34 @@ export class PasswordPageComponent implements OnInit {
@ViewChild('formGroup') private formGroup: FormGroup;
private lastPasswordUpdate: number;
- constructor(private accountSvc: AccountServiceClient, private renderer: Renderer2) {
+ constructor(private accountSvc: AccountServiceClient,
+ private renderer: Renderer2,
+ protected kcNotifySvc: KeycloakNotificationService,) {
this.accountSvc.doGetRequest("/credentials/password", (res: Response) => this.handleGetResponse(res));
}
public changePassword() {
console.log("posting: " + JSON.stringify(this.formGroup.value));
+ if (!this.confirmationMatches()) return;
this.accountSvc.doPostRequest("/credentials/password", (res: Response) => this.handlePostResponse(res), this.formGroup.value);
this.renderer.selectRootElement('#password').focus();
}
+ private confirmationMatches(): boolean {
+ const newPassword: string = this.formGroup.value['newPassword'];
+ const confirmation: string = this.formGroup.value['confirmation'];
+
+ const matches: boolean = newPassword === confirmation;
+
+ if (!matches) {
+ this.kcNotifySvc.notify('notMatchPasswordMessage', NotificationType.DANGER)
+ }
+
+ return matches;
+ }
+
protected handlePostResponse(res: Response) {
- console.log('**** response from account POST ***');
+ console.log('**** response from password POST ***');
console.log(JSON.stringify(res));
console.log('***************************************');
this.formGroup.reset();
@@ -49,7 +68,7 @@ export class PasswordPageComponent implements OnInit {
}
protected handleGetResponse(res: Response) {
- console.log('**** response from account POST ***');
+ console.log('**** response from password GET ***');
console.log(JSON.stringify(res));
console.log('***************************************');
this.lastPasswordUpdate = res.json()['lastUpdate'];
diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/ngx-translate/translate.util.ts b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/ngx-translate/translate.util.ts
index 947c2a3..ad833c2 100644
--- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/ngx-translate/translate.util.ts
+++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/ngx-translate/translate.util.ts
@@ -27,13 +27,19 @@ export class TranslateUtil {
constructor(private translator: TranslateService) {
}
- public translate(key: string) : string {
+ public translate(key: string, params?: Array<any>): string {
// remove Freemarker syntax
if (key.startsWith('${') && key.endsWith('}')) {
key = key.substring(2, key.length - 1);
}
- return this.translator.instant(key);
+ const ngTranslateParams = {};
+ for (let i in params) {
+ let paramName: string = 'param_' + i;
+ ngTranslateParams[paramName] = params[i];
+ }
+
+ return this.translator.instant(key, ngTranslateParams);
}
}
diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/notification/inline-notification.component.css b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/notification/inline-notification.component.css
new file mode 100644
index 0000000..18a4765
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/notification/inline-notification.component.css
@@ -0,0 +1,29 @@
+.faux-layout {
+ position: fixed;
+ top: 37px;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: #f5f5f5;
+ padding-top: 15px;
+ z-index: 1100;
+}
+.example-page-container.container-fluid {
+ position: fixed;
+ top: 37px;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: #f5f5f5;
+ padding-top: 15px;
+}
+
+.hide-vertical-nav {
+ margin-top: 15px;
+ margin-left: 30px;
+}
+
+.navbar-brand-txt {
+ line-height: 34px;
+}
+
diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/vertical-nav/vertical-nav.component.html b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/vertical-nav/vertical-nav.component.html
index e11d960..6bc27d1 100644
--- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/vertical-nav/vertical-nav.component.html
+++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/vertical-nav/vertical-nav.component.html
@@ -34,12 +34,11 @@
</div>
</pfng-vertical-navigation>
-
-
<div #contentContainer
class="container-fluid container-cards-pf container-pf-nav-pf-vertical example-page-container">
<div class="row">
<div class="col-sm-12">
+ <inline-notification></inline-notification>
<router-outlet></router-outlet>
</div>
</div>
diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/vertical-nav/vertical-nav.component.ts b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/vertical-nav/vertical-nav.component.ts
index 3ff0d5b..62a23f2 100644
--- a/themes/src/main/resources/theme/keycloak-preview/account/resources/app/vertical-nav/vertical-nav.component.ts
+++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/app/vertical-nav/vertical-nav.component.ts
@@ -1,107 +1,107 @@
-import {Component, OnInit, ViewEncapsulation, ViewChild} from '@angular/core';
-import {NavigationItemConfig, VerticalNavigationComponent} from 'patternfly-ng/navigation';
-import {TranslateUtil} from '../ngx-translate/translate.util';
-import {KeycloakService} from '../keycloak-service/keycloak.service';
-import {Features} from '../page/features';
-import {Referrer} from "../page/referrer";
-
-declare const baseUrl: string;
-declare const resourceUrl: string;
-declare const features: Features;
-declare const availableLocales: Array<Object>;
-
-@Component({
- encapsulation: ViewEncapsulation.None,
- selector: 'vertical-nav',
- styleUrls: ['./vertical-nav.component.css'],
- templateUrl: './vertical-nav.component.html'
-})
-export class VerticalNavComponent implements OnInit {
- @ViewChild('pfVerticalNav') pfVerticalNav: VerticalNavigationComponent;
-
- public resourceUrl: string = resourceUrl;
- public availableLocales: Array<Object> = availableLocales;
-
- private referrer: Referrer;
-
- navigationItems: NavigationItemConfig[];
-
- constructor(private keycloakService: KeycloakService,
- private translateUtil: TranslateUtil, ) {
- this.referrer = new Referrer(translateUtil);
- }
-
- ngOnInit(): void {
- this.navigationItems = [
- {
- title: this.translateUtil.translate('personalInfoHtmlTitle'),
- iconStyleClass: 'fa fa-user-circle',
- url: 'account',
- mobileItem: false
- },
- {
- title: this.translateUtil.translate('accountSecurityTitle'),
- iconStyleClass: 'fa fa-shield',
- children: this.makeSecurityChildren(),
- },
- {
- title: this.translateUtil.translate('applicationsHtmlTitle'),
- iconStyleClass: 'fa fa-th',
- url: 'applications',
- }
- ];
-
- if (features.isMyResourcesEnabled) {
- this.navigationItems.push(
- {
- title: this.translateUtil.translate('myResources'),
- iconStyleClass: 'fa fa-file-o',
- url: 'my-resources',
- }
- );
- }
- }
-
- private makeSecurityChildren(): Array<NavigationItemConfig> {
- const children: Array<NavigationItemConfig> = [
- {
- title: this.translateUtil.translate('changePasswordHtmlTitle'),
- iconStyleClass: 'fa fa-shield',
- url: 'password',
- },
- {
- title: this.translateUtil.translate('authenticatorTitle'),
- iconStyleClass: 'fa fa-shield',
- url: 'authenticator',
- },
- {
- title: this.translateUtil.translate('device-activity'),
- iconStyleClass: 'fa fa-shield',
- url: 'device-activity',
- }
- ];
-
- if (features.isLinkedAccountsEnabled) {
- children.push({
- title: this.translateUtil.translate('linkedAccountsHtmlTitle'),
- iconStyleClass: 'fa fa-shield',
- url: 'linked-accounts',
- });
- };
-
- return children;
- }
-
- private logout() {
- this.keycloakService.logout(baseUrl);
- }
-
- private isShowLocales(): boolean {
- return features.isInternationalizationEnabled && (this.availableLocales.length > 1);
- }
-
- private changeLocale(newLocale: string) {
- this.keycloakService.login({kcLocale: newLocale});
- }
-
-}
\ No newline at end of file
+import {Component, OnInit, ViewEncapsulation, ViewChild} from '@angular/core';
+import {NavigationItemConfig, VerticalNavigationComponent} from 'patternfly-ng/navigation';
+import {TranslateUtil} from '../ngx-translate/translate.util';
+import {KeycloakService} from '../keycloak-service/keycloak.service';
+import {Features} from '../page/features';
+import {Referrer} from "../page/referrer";
+
+declare const baseUrl: string;
+declare const resourceUrl: string;
+declare const features: Features;
+declare const availableLocales: Array<Object>;
+
+@Component({
+ encapsulation: ViewEncapsulation.None,
+ selector: 'vertical-nav',
+ styleUrls: ['./vertical-nav.component.css'],
+ templateUrl: './vertical-nav.component.html'
+})
+export class VerticalNavComponent implements OnInit {
+ @ViewChild('pfVerticalNav') pfVerticalNav: VerticalNavigationComponent;
+
+ public resourceUrl: string = resourceUrl;
+ public availableLocales: Array<Object> = availableLocales;
+
+ private referrer: Referrer;
+
+ navigationItems: NavigationItemConfig[];
+
+ constructor(private keycloakService: KeycloakService,
+ private translateUtil: TranslateUtil ) {
+ this.referrer = new Referrer(translateUtil);
+ }
+
+ ngOnInit(): void {
+ this.navigationItems = [
+ {
+ title: this.translateUtil.translate('personalInfoHtmlTitle'),
+ iconStyleClass: 'fa fa-user-circle',
+ url: 'account',
+ mobileItem: false
+ },
+ {
+ title: this.translateUtil.translate('accountSecurityTitle'),
+ iconStyleClass: 'fa fa-shield',
+ children: this.makeSecurityChildren(),
+ },
+ {
+ title: this.translateUtil.translate('applicationsHtmlTitle'),
+ iconStyleClass: 'fa fa-th',
+ url: 'applications',
+ }
+ ];
+
+ if (features.isMyResourcesEnabled) {
+ this.navigationItems.push(
+ {
+ title: this.translateUtil.translate('myResources'),
+ iconStyleClass: 'fa fa-file-o',
+ url: 'my-resources',
+ }
+ );
+ }
+ }
+
+ private makeSecurityChildren(): Array<NavigationItemConfig> {
+ const children: Array<NavigationItemConfig> = [
+ {
+ title: this.translateUtil.translate('changePasswordHtmlTitle'),
+ iconStyleClass: 'fa fa-shield',
+ url: 'password',
+ },
+ {
+ title: this.translateUtil.translate('authenticatorTitle'),
+ iconStyleClass: 'fa fa-shield',
+ url: 'authenticator',
+ },
+ {
+ title: this.translateUtil.translate('device-activity'),
+ iconStyleClass: 'fa fa-shield',
+ url: 'device-activity',
+ }
+ ];
+
+ if (features.isLinkedAccountsEnabled) {
+ children.push({
+ title: this.translateUtil.translate('linkedAccountsHtmlTitle'),
+ iconStyleClass: 'fa fa-shield',
+ url: 'linked-accounts',
+ });
+ };
+
+ return children;
+ }
+
+ private logout() {
+ this.keycloakService.logout(baseUrl);
+ }
+
+ private isShowLocales(): boolean {
+ return features.isInternationalizationEnabled && (this.availableLocales.length > 1);
+ }
+
+ private changeLocale(newLocale: string) {
+ this.keycloakService.login({kcLocale: newLocale});
+ }
+
+}
diff --git a/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js b/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js
index 60683b9..4b0ae94 100644
--- a/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js
+++ b/themes/src/main/resources/theme/keycloak-preview/account/resources/systemjs.config.js
@@ -31,6 +31,9 @@
// patternfly-ng
'patternfly-ng/navigation': 'npm:patternfly-ng/bundles/patternfly-ng.umd.min.js',
'patternfly-ng/utilities': 'npm:patternfly-ng/bundles/patternfly-ng.umd.min.js',
+ 'patternfly-ng/notification': 'npm:patternfly-ng/bundles/patternfly-ng.umd.min.js',
+ 'patternfly-ng/notification/inline-notification': 'npm:patternfly-ng/bundles/patternfly-ng.umd.min.js',
+ 'patternfly-ng/notification/notification-service': 'npm:patternfly-ng/bundles/patternfly-ng.umd.min.js',
// unused patternfly-ng dependencies
'angular-tree-component': '@empty',
@@ -44,10 +47,6 @@
'ngx-bootstrap/dropdown': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js',
'ngx-bootstrap/popover': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js',
'ngx-bootstrap/tooltip': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js',
-
- // patternfly-ng currently requires us to install transpiler. Need to get rid of this.
- 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js',
- 'systemjs-babel-build': 'npm:systemjs-plugin-babel/systemjs-babel-browser.js'
},
bundles: {