From 09ce9d97f63018014f132b1b4643924d887d7514 Mon Sep 17 00:00:00 2001 From: Waldemar Reusch Date: Thu, 16 Mar 2023 11:32:11 +0100 Subject: [PATCH] feat(storybook): update formatting; introduce new pages; update keycloakify --- package.json | 2 +- .../pages/IdpReviewUserProfile.stories.tsx | 8 +- .../pages/IdpReviewUserProfile.tsx | 2 +- src/keycloak-theme/pages/Info.stories.tsx | 7 +- src/keycloak-theme/pages/Login.stories.tsx | 24 +- .../pages/LoginConfigTotp.stories.tsx | 12 +- .../pages/LoginIdpLinkConfirm.stories.tsx | 8 +- .../pages/LoginIdpLinkEmail.stories.tsx | 8 +- src/keycloak-theme/pages/LoginOtp.stories.tsx | 8 +- .../pages/LoginPageExpired.stories.tsx | 8 +- .../pages/LoginPassword.stories.tsx | 10 +- .../pages/LoginResetPassword.stories.tsx | 10 +- .../pages/LoginUpdatePassword.stories.tsx | 8 +- .../pages/LoginUsername.stories.tsx | 17 ++ src/keycloak-theme/pages/LoginUsername.tsx | 158 +++++++++++++ .../pages/LoginVerifyEmail.stories.tsx | 16 ++ src/keycloak-theme/pages/LoginVerifyEmail.tsx | 32 +++ .../pages/LogoutConfirm.stories.tsx | 16 ++ src/keycloak-theme/pages/LogoutConfirm.tsx | 58 +++++ .../pages/MyExtraPage1.stories.tsx | 8 +- .../pages/MyExtraPage2.stories.tsx | 10 +- src/keycloak-theme/pages/Register.stories.tsx | 12 +- .../pages/RegisterUserProfile.stories.tsx | 9 +- .../pages/RegisterUserProfile.tsx | 2 +- src/keycloak-theme/pages/Terms.stories.tsx | 5 +- .../pages/UpdateUserProfile.stories.tsx | 16 ++ .../pages/UpdateUserProfile.tsx | 67 ++++++ .../pages/WebauthnAuthenticate.stories.tsx | 16 ++ .../pages/WebauthnAuthenticate.tsx | 193 +++++++++++++++ yarn.lock | 223 +++++++++++++++++- 30 files changed, 882 insertions(+), 91 deletions(-) create mode 100644 src/keycloak-theme/pages/LoginUsername.stories.tsx create mode 100644 src/keycloak-theme/pages/LoginUsername.tsx create mode 100644 src/keycloak-theme/pages/LoginVerifyEmail.stories.tsx create mode 100644 src/keycloak-theme/pages/LoginVerifyEmail.tsx create mode 100644 src/keycloak-theme/pages/LogoutConfirm.stories.tsx create mode 100644 src/keycloak-theme/pages/LogoutConfirm.tsx create mode 100644 src/keycloak-theme/pages/UpdateUserProfile.stories.tsx create mode 100644 src/keycloak-theme/pages/UpdateUserProfile.tsx create mode 100644 src/keycloak-theme/pages/WebauthnAuthenticate.stories.tsx create mode 100644 src/keycloak-theme/pages/WebauthnAuthenticate.tsx diff --git a/package.json b/package.json index 11a0e3c..2fe1c2f 100755 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "evt": "^2.4.15", "jwt-decode": "^3.1.2", "keycloak-js": "^21.0.1", - "keycloakify": "^6.12.7", + "keycloakify": "^6.13.1", "powerhooks": "^0.26.2", "react": "18.1.0", "react-dom": "18.1.0", diff --git a/src/keycloak-theme/pages/IdpReviewUserProfile.stories.tsx b/src/keycloak-theme/pages/IdpReviewUserProfile.stories.tsx index e3d6915..660216c 100644 --- a/src/keycloak-theme/pages/IdpReviewUserProfile.stories.tsx +++ b/src/keycloak-theme/pages/IdpReviewUserProfile.stories.tsx @@ -1,6 +1,8 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {template} from '../../../.storybook/util' +import { template } from '../../../.storybook/util' + +const bind = template('idp-review-user-profile.ftl'); export default { kind: 'Page', @@ -11,7 +13,5 @@ export default { }, } as ComponentMeta; -const bind = template('idp-review-user-profile.ftl'); - export const Default = bind({}) diff --git a/src/keycloak-theme/pages/IdpReviewUserProfile.tsx b/src/keycloak-theme/pages/IdpReviewUserProfile.tsx index ec73693..2e4f789 100644 --- a/src/keycloak-theme/pages/IdpReviewUserProfile.tsx +++ b/src/keycloak-theme/pages/IdpReviewUserProfile.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { clsx } from "keycloakify/lib/tools/clsx"; -import { UserProfileFormFields } from "./shared/UserProfileCommons"; +import { UserProfileFormFields } from "keycloakify/lib/pages/shared/UserProfileCommons"; import type { PageProps } from "keycloakify"; import type { KcContext } from "../kcContext"; import type { I18n } from "../i18n"; diff --git a/src/keycloak-theme/pages/Info.stories.tsx b/src/keycloak-theme/pages/Info.stories.tsx index e6bacc5..4fd483f 100644 --- a/src/keycloak-theme/pages/Info.stories.tsx +++ b/src/keycloak-theme/pages/Info.stories.tsx @@ -1,6 +1,8 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {template} from '../../../.storybook/util' +import { template } from '../../../.storybook/util' + +const bind = template('info.ftl'); export default { kind: 'Page', @@ -11,7 +13,6 @@ export default { }, } as ComponentMeta; -const bind = template('info.ftl'); export const Default = bind({ messageHeader: 'Yo, get this:', diff --git a/src/keycloak-theme/pages/Login.stories.tsx b/src/keycloak-theme/pages/Login.stories.tsx index a2e9f8d..9cafd82 100644 --- a/src/keycloak-theme/pages/Login.stories.tsx +++ b/src/keycloak-theme/pages/Login.stories.tsx @@ -1,6 +1,8 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {socialProviders, template} from '../../../.storybook/util' +import { socialProviders, template } from '../../../.storybook/util' + +const bind = template('login.ftl'); export default { kind: 'Page', @@ -11,17 +13,15 @@ export default { }, } as ComponentMeta; -const bind = template('login.ftl'); - export const Default = bind({}) -export const WithoutPasswordField = bind({realm: {password: false}}) -export const WithoutRegistration = bind({realm: {registrationAllowed: false}}) -export const WithoutRememberMe = bind({realm: {rememberMe: false}}) -export const WithoutPasswordReset = bind({realm: {resetPasswordAllowed: false}}) -export const WithEmailAsUsername = bind({realm: {loginWithEmailAllowed: false}}) -export const WithPresetUsername = bind({login: {username: 'max.mustermann@mail.com'}}) +export const WithoutPasswordField = bind({ realm: { password: false } }) +export const WithoutRegistration = bind({ realm: { registrationAllowed: false } }) +export const WithoutRememberMe = bind({ realm: { rememberMe: false } }) +export const WithoutPasswordReset = bind({ realm: { resetPasswordAllowed: false } }) +export const WithEmailAsUsername = bind({ realm: { loginWithEmailAllowed: false } }) +export const WithPresetUsername = bind({ login: { username: 'max.mustermann@mail.com' } }) export const WithImmutablePresetUsername = bind({ - login: {username: 'max.mustermann@mail.com'}, + login: { username: 'max.mustermann@mail.com' }, usernameEditDisabled: true }) -export const WithSocialProviders = bind({social: {displayInfo: true, providers: socialProviders}}) +export const WithSocialProviders = bind({ social: { displayInfo: true, providers: socialProviders } }) diff --git a/src/keycloak-theme/pages/LoginConfigTotp.stories.tsx b/src/keycloak-theme/pages/LoginConfigTotp.stories.tsx index b0a673f..d798dd2 100644 --- a/src/keycloak-theme/pages/LoginConfigTotp.stories.tsx +++ b/src/keycloak-theme/pages/LoginConfigTotp.stories.tsx @@ -1,6 +1,8 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {template} from '../../../.storybook/util' +import { template } from '../../../.storybook/util' + +const bind = template('login-config-totp.ftl'); export default { kind: 'Page', @@ -11,17 +13,15 @@ export default { }, } as ComponentMeta; -const bind = template('login-config-totp.ftl'); - export const Default = bind({}) -export const WithManualSetUp = bind({mode: 'manual'}) +export const WithManualSetUp = bind({ mode: 'manual' }) export const WithError = bind({ messagesPerField: { get: (fieldName: string) => fieldName === 'totp' ? 'Invalid TOTP' : undefined, exists: (fieldName: string) => fieldName === 'totp', existsError: (fieldName: string) => fieldName === 'totp', - printIfExists: (fieldName: string, x: T) => fieldName === 'totp' ? x : undefined + printIfExists: (fieldName: string, x: T) => fieldName === 'totp' ? x : undefined } }) diff --git a/src/keycloak-theme/pages/LoginIdpLinkConfirm.stories.tsx b/src/keycloak-theme/pages/LoginIdpLinkConfirm.stories.tsx index 55ff499..75617bb 100644 --- a/src/keycloak-theme/pages/LoginIdpLinkConfirm.stories.tsx +++ b/src/keycloak-theme/pages/LoginIdpLinkConfirm.stories.tsx @@ -1,6 +1,8 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {template} from '../../../.storybook/util' +import { template } from '../../../.storybook/util' + +const bind = template('login-idp-link-confirm.ftl'); export default { kind: 'Page', @@ -11,7 +13,5 @@ export default { }, } as ComponentMeta; -const bind = template('login-idp-link-confirm.ftl'); - export const Default = bind({}) diff --git a/src/keycloak-theme/pages/LoginIdpLinkEmail.stories.tsx b/src/keycloak-theme/pages/LoginIdpLinkEmail.stories.tsx index 98f280b..1d03385 100644 --- a/src/keycloak-theme/pages/LoginIdpLinkEmail.stories.tsx +++ b/src/keycloak-theme/pages/LoginIdpLinkEmail.stories.tsx @@ -1,6 +1,8 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {template} from '../../../.storybook/util' +import { template } from '../../../.storybook/util' + +const bind = template('login-idp-link-email.ftl'); export default { kind: 'Page', @@ -11,7 +13,5 @@ export default { }, } as ComponentMeta; -const bind = template('login-idp-link-email.ftl'); - export const Default = bind({}) diff --git a/src/keycloak-theme/pages/LoginOtp.stories.tsx b/src/keycloak-theme/pages/LoginOtp.stories.tsx index 21e90bb..f674379 100644 --- a/src/keycloak-theme/pages/LoginOtp.stories.tsx +++ b/src/keycloak-theme/pages/LoginOtp.stories.tsx @@ -1,6 +1,8 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {template} from '../../../.storybook/util' +import { template } from '../../../.storybook/util' + +const bind = template('login-otp.ftl'); export default { kind: 'Page', @@ -11,6 +13,4 @@ export default { }, } as ComponentMeta; -const bind = template('login-otp.ftl'); - export const Default = bind({}) diff --git a/src/keycloak-theme/pages/LoginPageExpired.stories.tsx b/src/keycloak-theme/pages/LoginPageExpired.stories.tsx index c991a2f..f5de885 100644 --- a/src/keycloak-theme/pages/LoginPageExpired.stories.tsx +++ b/src/keycloak-theme/pages/LoginPageExpired.stories.tsx @@ -1,6 +1,8 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {socialProviders, template} from '../../../.storybook/util' +import { template } from '../../../.storybook/util' + +const bind = template('login-page-expired.ftl'); export default { kind: 'Page', @@ -11,6 +13,4 @@ export default { }, } as ComponentMeta; -const bind = template('login-page-expired.ftl'); - export const Default = bind({}) diff --git a/src/keycloak-theme/pages/LoginPassword.stories.tsx b/src/keycloak-theme/pages/LoginPassword.stories.tsx index 6a53efa..5106dfc 100644 --- a/src/keycloak-theme/pages/LoginPassword.stories.tsx +++ b/src/keycloak-theme/pages/LoginPassword.stories.tsx @@ -1,16 +1,16 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {template} from '../../../.storybook/util' +import { template } from '../../../.storybook/util' + +const bind = template('login-password.ftl'); export default { kind: 'Page', - title: 'Theme/Pages/Login/Password Only', + title: 'Theme/Pages/Login/Password', component: KcApp, parameters: { layout: 'fullscreen', }, } as ComponentMeta; -const bind = template('login-password.ftl'); - export const Default = bind({}) diff --git a/src/keycloak-theme/pages/LoginResetPassword.stories.tsx b/src/keycloak-theme/pages/LoginResetPassword.stories.tsx index 9ea3736..c417dd8 100644 --- a/src/keycloak-theme/pages/LoginResetPassword.stories.tsx +++ b/src/keycloak-theme/pages/LoginResetPassword.stories.tsx @@ -1,6 +1,8 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {template} from '../../../.storybook/util' +import { template } from '../../../.storybook/util' + +const bind = template('login-reset-password.ftl'); export default { kind: 'Page', @@ -11,7 +13,5 @@ export default { }, } as ComponentMeta; -const bind = template('login-reset-password.ftl'); - export const Default = bind({}) -export const WithEmailAsUsername = bind({realm: {loginWithEmailAllowed: true, registrationEmailAsUsername: true}}) +export const WithEmailAsUsername = bind({ realm: { loginWithEmailAllowed: true, registrationEmailAsUsername: true } }) diff --git a/src/keycloak-theme/pages/LoginUpdatePassword.stories.tsx b/src/keycloak-theme/pages/LoginUpdatePassword.stories.tsx index cf5177e..91f2d7d 100644 --- a/src/keycloak-theme/pages/LoginUpdatePassword.stories.tsx +++ b/src/keycloak-theme/pages/LoginUpdatePassword.stories.tsx @@ -1,6 +1,8 @@ -import {ComponentMeta} from '@storybook/react'; +import { ComponentMeta } from '@storybook/react'; import KcApp from '../KcApp'; -import {template} from '../../../.storybook/util' +import { template } from '../../../.storybook/util' + +const bind = template('login-update-password.ftl'); export default { kind: 'Page', @@ -11,6 +13,4 @@ export default { }, } as ComponentMeta; -const bind = template('login-update-password.ftl'); - export const Default = bind({}) diff --git a/src/keycloak-theme/pages/LoginUsername.stories.tsx b/src/keycloak-theme/pages/LoginUsername.stories.tsx new file mode 100644 index 0000000..21e63c0 --- /dev/null +++ b/src/keycloak-theme/pages/LoginUsername.stories.tsx @@ -0,0 +1,17 @@ +import { ComponentMeta } from '@storybook/react'; +import KcApp from '../KcApp'; +import { template } from '../../../.storybook/util' + +const bind = template('login-username.ftl'); + +export default { + kind: 'Page', + title: 'Theme/Pages/Login/Username', + component: KcApp, + parameters: { + layout: 'fullscreen', + }, +} as ComponentMeta; + +export const Default = bind({}) +export const WithEmailAsUsername = bind({ realm: { loginWithEmailAllowed: true, registrationEmailAsUsername: true } }) diff --git a/src/keycloak-theme/pages/LoginUsername.tsx b/src/keycloak-theme/pages/LoginUsername.tsx new file mode 100644 index 0000000..7ea5e0a --- /dev/null +++ b/src/keycloak-theme/pages/LoginUsername.tsx @@ -0,0 +1,158 @@ +import React, { useState } from "react"; +import { clsx } from "keycloakify/lib/tools/clsx"; +import { useConstCallback } from "keycloakify/lib/tools/useConstCallback"; +import type { FormEventHandler } from "react"; +import type { PageProps } from "keycloakify"; +import type { KcContext } from "../kcContext"; +import type { I18n } from "../i18n"; + +export default function LoginUsername(props: PageProps, I18n>) { + const { kcContext, i18n, doFetchDefaultThemeResources = true, Template, ...kcProps } = props; + + const { social, realm, url, usernameHidden, login, registrationDisabled } = kcContext; + + const { msg, msgStr } = i18n; + + const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false); + + const onSubmit = useConstCallback>(e => { + e.preventDefault(); + + setIsLoginButtonDisabled(true); + + const formElement = e.target as HTMLFormElement; + + //NOTE: Even if we login with email Keycloak expect username and password in + //the POST request. + formElement.querySelector("input[name='email']")?.setAttribute("name", "username"); + + formElement.submit(); + }); + + return ( +