diff --git a/.storybook/data.ts b/.storybook/data.ts deleted file mode 100644 index 337e207..0000000 --- a/.storybook/data.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { KcContextBase, getKcContext } from "keycloakify/lib/getKcContext"; -import type { DeepPartial } from "keycloakify/lib/tools/DeepPartial"; -import type { ExtendsKcContextBase } from "keycloakify/lib/getKcContext/getKcContextFromWindow"; -import type { KcContextExtension } from "keycloak-theme/kcContext"; - - -export const useKcStoryData = (mockData: ( - { pageId: KcContextBase['pageId'] | KcContextExtension['pageId'] } & DeepPartial> -)) => { - const { kcContext } = getKcContext({ mockPageId: mockData.pageId, mockData: [mockData] }) - return { kcContext: kcContext as NonNullable } -} - -export const socialProviders = [ - { loginUrl: 'google', alias: 'google', providerId: 'google', displayName: 'Google' }, - { loginUrl: 'microsoft', alias: 'microsoft', providerId: 'microsoft', displayName: 'Microsoft' }, - { loginUrl: 'facebook', alias: 'facebook', providerId: 'facebook', displayName: 'Facebook' }, - { loginUrl: 'instagram', alias: 'instagram', providerId: 'instagram', displayName: 'Instagram' }, - { loginUrl: 'twitter', alias: 'twitter', providerId: 'twitter', displayName: 'Twitter' }, - { loginUrl: 'linkedin', alias: 'linkedin', providerId: 'linkedin', displayName: 'LinkedIn' }, - { loginUrl: 'stackoverflow', alias: 'stackoverflow', providerId: 'stackoverflow', displayName: 'Stackoverflow' }, - { loginUrl: 'github', alias: 'github', providerId: 'github', displayName: 'Github' }, - { loginUrl: 'gitlab', alias: 'gitlab', providerId: 'gitlab', displayName: 'Gitlab' }, - { loginUrl: 'bitbucket', alias: 'bitbucket', providerId: 'bitbucket', displayName: 'Bitbucket' }, - { loginUrl: 'paypal', alias: 'paypal', providerId: 'paypal', displayName: 'PayPal' }, - { loginUrl: 'openshift', alias: 'openshift', providerId: 'openshift', displayName: 'OpenShift' }, -] \ No newline at end of file diff --git a/.storybook/main.js b/.storybook/main.js index ae1673f..bf619ea 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -1,18 +1,16 @@ module.exports = { - "stories": [ - "../src/keycloak-theme/pages/Login.stories.tsx", - "../src/keycloak-theme/pages/Register.stories.tsx", - "../src/keycloak-theme/pages/MyExtraPage1.stories.tsx", - "../src/keycloak-theme/pages/MyExtraPage2.stories.tsx", - ], - "addons": [ - "@storybook/addon-links", - "@storybook/addon-essentials", - "@storybook/addon-interactions", - "@storybook/preset-create-react-app" - ], - "framework": "@storybook/react", - "core": { - "builder": "@storybook/builder-webpack5" - } + "stories": [ + "../src/keycloak-theme/**/*.stories.tsx", + ], + "addons": [ + "@storybook/addon-links", + "@storybook/addon-essentials", + "@storybook/addon-interactions", + "@storybook/preset-create-react-app" + ], + "framework": "@storybook/react", + "core": { + "builder": "@storybook/builder-webpack5" + }, + "staticDirs": ['../public'] } \ No newline at end of file diff --git a/.storybook/preview.js b/.storybook/preview.js index 48afd56..b6de5f6 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,9 +1,13 @@ export const parameters = { - actions: { argTypesRegex: "^on[A-Z].*" }, - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/, + actions: {argTypesRegex: "^on[A-Z].*"}, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, + options: { + storySort: (a, b) => + a[1].kind === b[1].kind ? 0 : a[1].id.localeCompare(b[1].id, undefined, {numeric: true}), }, - }, } \ No newline at end of file diff --git a/.storybook/util.tsx b/.storybook/util.tsx new file mode 100644 index 0000000..4180dee --- /dev/null +++ b/.storybook/util.tsx @@ -0,0 +1,41 @@ +import type {KcContextExtension} from "keycloak-theme/kcContext"; +import KcApp from "../src/keycloak-theme/KcApp"; +import {KcContextBase} from "keycloakify"; +import {getKcContext} from "keycloakify/lib/getKcContext"; +import {ExtendsKcContextBase} from "keycloakify/src/lib/getKcContext/getKcContextFromWindow"; +import {DeepPartial} from "keycloakify/src/lib/tools/DeepPartial"; + + +export const socialProviders = [ + {loginUrl: 'google', alias: 'google', providerId: 'google', displayName: 'Google'}, + {loginUrl: 'microsoft', alias: 'microsoft', providerId: 'microsoft', displayName: 'Microsoft'}, + {loginUrl: 'facebook', alias: 'facebook', providerId: 'facebook', displayName: 'Facebook'}, + {loginUrl: 'instagram', alias: 'instagram', providerId: 'instagram', displayName: 'Instagram'}, + {loginUrl: 'twitter', alias: 'twitter', providerId: 'twitter', displayName: 'Twitter'}, + {loginUrl: 'linkedin', alias: 'linkedin', providerId: 'linkedin', displayName: 'LinkedIn'}, + {loginUrl: 'stackoverflow', alias: 'stackoverflow', providerId: 'stackoverflow', displayName: 'Stackoverflow'}, + {loginUrl: 'github', alias: 'github', providerId: 'github', displayName: 'Github'}, + {loginUrl: 'gitlab', alias: 'gitlab', providerId: 'gitlab', displayName: 'Gitlab'}, + {loginUrl: 'bitbucket', alias: 'bitbucket', providerId: 'bitbucket', displayName: 'Bitbucket'}, + {loginUrl: 'paypal', alias: 'paypal', providerId: 'paypal', displayName: 'PayPal'}, + {loginUrl: 'openshift', alias: 'openshift', providerId: 'openshift', displayName: 'OpenShift'}, +] + +type PageId = (KcContextExtension | KcContextBase)['pageId'] +export const template = (pageId: PageId) => { + type MockData = DeepPartial>; + + const Template = (mockData: MockData) => { + const finalMockData = { + message: undefined, + pageId, + ...mockData + } as MockData + if (!("message" in mockData)) mockData["message"] = undefined + const {kcContext} = getKcContext({mockPageId: pageId, mockData: [finalMockData]}) + return }/> + } + + return (args: MockData) => Object.assign(Template.bind({}), {args}) +} + diff --git a/package.json b/package.json index eb6772b..11a0e3c 100755 --- a/package.json +++ b/package.json @@ -12,8 +12,8 @@ "build": "react-scripts build", "build-keycloak-theme": "yarn build && keycloakify", "download-builtin-keycloak-theme": "download-builtin-keycloak-theme 15.0.2", - "storybook": "start-storybook -p 6006 -s public", - "build-storybook": "build-storybook -s public" + "storybook": "start-storybook -p 6006", + "build-storybook": "build-storybook" }, "keycloakify": { "extraPages": [ diff --git a/src/keycloak-theme/Template.stories.tsx b/src/keycloak-theme/Template.stories.tsx new file mode 100644 index 0000000..d8660ed --- /dev/null +++ b/src/keycloak-theme/Template.stories.tsx @@ -0,0 +1,32 @@ +import type {ComponentMeta} from '@storybook/react'; +import KcApp from './KcApp'; +import {template} from '../../.storybook/util' + +const bind = template('my-extra-page-1.ftl'); + +export default { + title: 'Theme/Template', + component: KcApp, + parameters: { + layout: 'fullscreen', + }, +} as ComponentMeta; + + +export const Default = bind({}) +export const InFrench = bind({locale: {currentLanguageTag: 'fr'}}) +export const RealmDisplayNameIsHtml = bind({ + realm: { + displayNameHtml: 'my realm' + } +}) + +export const NoInternationalization = bind({ + realm: { + internationalizationEnabled: false, + } +}) + +export const WithGlobalError = bind({ + message: {type: "error", summary: "This is an error"} +}) diff --git a/src/keycloak-theme/pages/Error.stories.tsx b/src/keycloak-theme/pages/Error.stories.tsx new file mode 100644 index 0000000..ec176d8 --- /dev/null +++ b/src/keycloak-theme/pages/Error.stories.tsx @@ -0,0 +1,16 @@ +import {ComponentMeta} from '@storybook/react'; +import KcApp from '../KcApp'; +import {template} from '../../../.storybook/util' + +const bind = template('error.ftl'); + +export default { + kind: 'Page', + title: 'Theme/Pages/Error', + component: KcApp, + parameters: { + layout: 'fullscreen', + }, +} as ComponentMeta; + +export const Default = bind({message: {type: 'error', summary: 'Something went wrong'}}) diff --git a/src/keycloak-theme/pages/Error.tsx b/src/keycloak-theme/pages/Error.tsx new file mode 100644 index 0000000..b28ff06 --- /dev/null +++ b/src/keycloak-theme/pages/Error.tsx @@ -0,0 +1,34 @@ +// copied and adapted from https://github.com/InseeFrLab/keycloakify/blob/main/src/lib/pages/Error.tsx +import React from "react"; +import type { PageProps } from "keycloakify" +import type { KcContext } from "../kcContext"; +import type { I18n } from "../i18n"; + + +export default function Error(props: PageProps, I18n>) { + const { kcContext, i18n, doFetchDefaultThemeResources = true, Template, ...kcProps } = props; + + const { message, client } = kcContext; + + const { msg } = i18n; + + return ( +