Setup a very basic storybook
This commit is contained in:
parent
8c8eef22ce
commit
045c20844f
16
.storybook/main.js
Normal file
16
.storybook/main.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module.exports = {
|
||||||
|
"stories": [
|
||||||
|
"../src/**/*.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']
|
||||||
|
}
|
13
.storybook/preview.js
Normal file
13
.storybook/preview.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export const parameters = {
|
||||||
|
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}),
|
||||||
|
},
|
||||||
|
}
|
@ -32,6 +32,9 @@ yarn build-keycloak-theme
|
|||||||
# Read the instruction printed on the console to see how to test
|
# Read the instruction printed on the console to see how to test
|
||||||
# your theme on a real Keycloak instance.
|
# your theme on a real Keycloak instance.
|
||||||
|
|
||||||
|
# For launching the Storybook
|
||||||
|
yarn storybook
|
||||||
|
|
||||||
# For customizing other pages at the component level
|
# For customizing other pages at the component level
|
||||||
npx eject-keycloak-page # Then select the page you want
|
npx eject-keycloak-page # Then select the page you want
|
||||||
|
|
||||||
|
16
package.json
16
package.json
@ -12,7 +12,9 @@
|
|||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"build-keycloak-theme": "yarn build && keycloakify",
|
"build-keycloak-theme": "yarn build && keycloakify",
|
||||||
"eject-keycloak-page": "eject-keycloak-page",
|
"eject-keycloak-page": "eject-keycloak-page",
|
||||||
"download-builtin-keycloak-theme": "download-builtin-keycloak-theme"
|
"download-builtin-keycloak-theme": "download-builtin-keycloak-theme",
|
||||||
|
"storybook": "start-storybook -p 6006",
|
||||||
|
"build-storybook": "build-storybook"
|
||||||
},
|
},
|
||||||
"keycloakify": {
|
"keycloakify": {
|
||||||
"extraThemeProperties": [
|
"extraThemeProperties": [
|
||||||
@ -48,7 +50,17 @@
|
|||||||
"@types/react": "18.0.9",
|
"@types/react": "18.0.9",
|
||||||
"@types/react-dom": "18.0.4",
|
"@types/react-dom": "18.0.4",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"typescript": "~4.7.0"
|
"typescript": "~4.7.0",
|
||||||
|
"@storybook/addon-actions": "^6.5.16",
|
||||||
|
"@storybook/addon-essentials": "^6.5.16",
|
||||||
|
"@storybook/addon-interactions": "^6.5.16",
|
||||||
|
"@storybook/addon-links": "^6.5.16",
|
||||||
|
"@storybook/builder-webpack5": "^6.5.16",
|
||||||
|
"@storybook/manager-webpack5": "^6.5.16",
|
||||||
|
"@storybook/node-logger": "^6.5.16",
|
||||||
|
"@storybook/preset-create-react-app": "^4.1.2",
|
||||||
|
"@storybook/react": "^6.5.16",
|
||||||
|
"@storybook/testing-library": "^0.0.13"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
|
24
src/keycloak-theme/account/createPageStory.tsx
Normal file
24
src/keycloak-theme/account/createPageStory.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { getKcContext, type KcContext } from "./kcContext";
|
||||||
|
import KcApp from "./KcApp";
|
||||||
|
import type { DeepPartial } from "keycloakify/tools/DeepPartial";
|
||||||
|
|
||||||
|
export function createPageStory<PageId extends KcContext["pageId"]>(params: {
|
||||||
|
pageId: PageId;
|
||||||
|
}) {
|
||||||
|
|
||||||
|
const { pageId } = params;
|
||||||
|
|
||||||
|
function PageStory(params: { kcContext?: DeepPartial<Extract<KcContext, { pageId: PageId }>>; }) {
|
||||||
|
|
||||||
|
const { kcContext } = getKcContext({
|
||||||
|
mockPageId: pageId,
|
||||||
|
storyParams: params.kcContext
|
||||||
|
});
|
||||||
|
|
||||||
|
return <KcApp kcContext={kcContext} />;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return { PageStory };
|
||||||
|
|
||||||
|
}
|
@ -1,11 +1,10 @@
|
|||||||
import { getKcContext } from "keycloakify/account";
|
import { createGetKcContext } from "keycloakify/account";
|
||||||
|
|
||||||
export type KcContextExtension =
|
export type KcContextExtension =
|
||||||
| { pageId: "my-extra-page-1.ftl"; }
|
| { pageId: "my-extra-page-1.ftl"; }
|
||||||
| { pageId: "my-extra-page-2.ftl"; someCustomValue: string; };
|
| { pageId: "my-extra-page-2.ftl"; someCustomValue: string; };
|
||||||
|
|
||||||
export const { kcContext } = getKcContext<KcContextExtension>({
|
export const { getKcContext } = createGetKcContext<KcContextExtension>({
|
||||||
//mockPageId: "password.ftl",
|
|
||||||
mockData: [
|
mockData: [
|
||||||
{
|
{
|
||||||
pageId: "my-extra-page-2.ftl",
|
pageId: "my-extra-page-2.ftl",
|
||||||
@ -14,4 +13,8 @@ export const { kcContext } = getKcContext<KcContextExtension>({
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const { kcContext } = getKcContext({
|
||||||
|
//mockPageId: "password.ftl",
|
||||||
|
});
|
||||||
|
|
||||||
export type KcContext = NonNullable<typeof kcContext>;
|
export type KcContext = NonNullable<typeof kcContext>;
|
14
src/keycloak-theme/account/pages/Password.stories.tsx
Normal file
14
src/keycloak-theme/account/pages/Password.stories.tsx
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
import { ComponentStory, ComponentMeta } from "@storybook/react";
|
||||||
|
import { createPageStory } from "../createPageStory";
|
||||||
|
|
||||||
|
const { PageStory } = createPageStory({
|
||||||
|
pageId: "password.ftl"
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "account/Password",
|
||||||
|
component: PageStory,
|
||||||
|
} as ComponentMeta<typeof PageStory>;
|
||||||
|
|
||||||
|
export const Default: ComponentStory<typeof PageStory> = () => <PageStory />;
|
@ -2,13 +2,10 @@
|
|||||||
|
|
||||||
## Presentation / Features
|
## Presentation / Features
|
||||||
|
|
||||||
[EC: continuation of today's meeting: this would deserve to differentiate the SSP Cloud from the Onyxia SSP Cloud instance]
|
|
||||||
|
|
||||||
The SSP Cloud is a service (hereinafter referred to as "the service") implemented by the National Institute for Statistics and Economic Studies (hereinafter referred to as "Insee").
|
The SSP Cloud is a service (hereinafter referred to as "the service") implemented by the National Institute for Statistics and Economic Studies (hereinafter referred to as "Insee").
|
||||||
|
|
||||||
The SSP Cloud is an implementation of free software [Onyxia] (https://github.com/InseeFrLab/onyxia) created and maintained by the innovation and technical instruction division of INSEE (information system management / innovation unit and information system strategy). The SSP Cloud is hosted by INSEE.
|
The SSP Cloud is an implementation of free software [Onyxia](https://github.com/InseeFrLab/onyxia) created and maintained by the innovation and technical instruction division of INSEE (information system management / innovation unit and information system strategy). The SSP Cloud is hosted by INSEE.
|
||||||
|
|
||||||
[EC: I will remove the "on open data", since the SSP Cloud can accommodate secure data under the appropriate conditions]
|
|
||||||
The SSP Cloud is a platform offering a "datalab" intended for _data science_ experiments on open data in which users can orchestrate services dedicated to the practice of _data science_ (development environments, databases, etc.). This service offering thus aims to familiarize users with new collaborative working methods using _open source_ statistical languages (R, python, Julia, etc.), _cloud computing_ type technologies, as well as to allow processing experiments. innovative statistics. The services offered are standard.
|
The SSP Cloud is a platform offering a "datalab" intended for _data science_ experiments on open data in which users can orchestrate services dedicated to the practice of _data science_ (development environments, databases, etc.). This service offering thus aims to familiarize users with new collaborative working methods using _open source_ statistical languages (R, python, Julia, etc.), _cloud computing_ type technologies, as well as to allow processing experiments. innovative statistics. The services offered are standard.
|
||||||
|
|
||||||
The SSP Cloud is aimed at officials of the official statistical system as well as teachers and students of the Group of National Schools of Economics and Statistics, allowing inter-service collaboration and cooperation with their ecosystem. Access can thus be granted on request and after decision of the governance bodies of the Cloud SSP to external collaborators and involved in the realization of experimental projects of the official statistical system. Projects involving non-open data are also subject to the decision of the governing bodies.
|
The SSP Cloud is aimed at officials of the official statistical system as well as teachers and students of the Group of National Schools of Economics and Statistics, allowing inter-service collaboration and cooperation with their ecosystem. Access can thus be granted on request and after decision of the governance bodies of the Cloud SSP to external collaborators and involved in the realization of experimental projects of the official statistical system. Projects involving non-open data are also subject to the decision of the governing bodies.
|
||||||
@ -22,7 +19,7 @@ The SSP Cloud allows:
|
|||||||
- access to a code management service
|
- access to a code management service
|
||||||
- orchestration of data processing flows
|
- orchestration of data processing flows
|
||||||
|
|
||||||
A user account is also used to connect to the service platform of the Inter-ministerial Mutualization Free Software community (<https://groupes.mim-libre.fr/>).
|
A user account is also used to connect to the service platform of [the Inter-ministerial Mutualization Free Software community](https://groupes.mim-libre.fr/).
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
@ -49,8 +46,8 @@ Internet. The use of a computer is recommended. Use of the datalab services is f
|
|||||||
|
|
||||||
The user community is accessible on:
|
The user community is accessible on:
|
||||||
|
|
||||||
- Tchap, salon [SSP Cloud] (https://www.tchap.gouv.fr/#/room/#SSPCloudXDpAw6v:agent.finances.tchap.gouv.fr)
|
- Tchap, salon [SSP Cloud](https://www.tchap.gouv.fr/#/room/#SSPCloudXDpAw6v:agent.finances.tchap.gouv.fr)
|
||||||
- Rocket Chat at MIM Libre, [SSP Cloud] lounge (https://chat.mim-libre.fr/channel/sspcloud)
|
- Rocket Chat at MIM Libre, [SSP Cloud lounge](https://chat.mim-libre.fr/channel/sspcloud)
|
||||||
|
|
||||||
## Limits of use of the Service
|
## Limits of use of the Service
|
||||||
|
|
||||||
@ -177,4 +174,4 @@ functionalities encountered on the platform, it is recommended, first of all
|
|||||||
time to solicit communities of peers in collaborative spaces
|
time to solicit communities of peers in collaborative spaces
|
||||||
provided for this purpose on Tchap and Rocket Chat-MIM Libre.
|
provided for this purpose on Tchap and Rocket Chat-MIM Libre.
|
||||||
|
|
||||||
CNIL right of access for: <innovation@insee.fr>
|
CNIL right of access for: innovation@insee.fr
|
||||||
|
24
src/keycloak-theme/login/createPageStory.tsx
Normal file
24
src/keycloak-theme/login/createPageStory.tsx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { getKcContext, type KcContext } from "./kcContext";
|
||||||
|
import KcApp from "./KcApp";
|
||||||
|
import type { DeepPartial } from "keycloakify/tools/DeepPartial";
|
||||||
|
|
||||||
|
export function createPageStory<PageId extends KcContext["pageId"]>(params: {
|
||||||
|
pageId: PageId;
|
||||||
|
}) {
|
||||||
|
|
||||||
|
const { pageId } = params;
|
||||||
|
|
||||||
|
function PageStory(params: { kcContext?: DeepPartial<Extract<KcContext, { pageId: PageId }>>; }) {
|
||||||
|
|
||||||
|
const { kcContext } = getKcContext({
|
||||||
|
mockPageId: pageId,
|
||||||
|
storyParams: params.kcContext
|
||||||
|
});
|
||||||
|
|
||||||
|
return <KcApp kcContext={kcContext} />;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return { PageStory };
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { getKcContext } from "keycloakify/login";
|
import { createGetKcContext } from "keycloakify/login";
|
||||||
|
|
||||||
export type KcContextExtension =
|
export type KcContextExtension =
|
||||||
// NOTE: A 'keycloakify' field must be added
|
// NOTE: A 'keycloakify' field must be added
|
||||||
@ -12,13 +12,11 @@ export type KcContextExtension =
|
|||||||
| { pageId: "register.ftl"; authorizedMailDomains: string[]; };
|
| { pageId: "register.ftl"; authorizedMailDomains: string[]; };
|
||||||
|
|
||||||
//NOTE: In most of the cases you do not need to overload the KcContext, you can
|
//NOTE: In most of the cases you do not need to overload the KcContext, you can
|
||||||
// just call getKcContext(...) without type arguments.
|
// just call createGetKcContext(...) without type arguments.
|
||||||
// You want to overload the KcContext only if:
|
// You want to overload the KcContext only if:
|
||||||
// - You have custom plugins that add some values to the context (like https://github.com/micedre/keycloak-mail-whitelisting that adds authorizedMailDomains)
|
// - You have custom plugins that add some values to the context (like https://github.com/micedre/keycloak-mail-whitelisting that adds authorizedMailDomains)
|
||||||
// - You want to add support for extra pages that are not yey featured by default, see: https://docs.keycloakify.dev/contributing#adding-support-for-a-new-page
|
// - You want to add support for extra pages that are not yey featured by default, see: https://docs.keycloakify.dev/contributing#adding-support-for-a-new-page
|
||||||
export const { kcContext } = getKcContext<KcContextExtension>({
|
export const { getKcContext } = createGetKcContext<KcContextExtension>({
|
||||||
// Uncomment to test the login page for development.
|
|
||||||
//mockPageId: "login.ftl",
|
|
||||||
mockData: [
|
mockData: [
|
||||||
{
|
{
|
||||||
pageId: "login.ftl",
|
pageId: "login.ftl",
|
||||||
@ -94,4 +92,10 @@ export const { kcContext } = getKcContext<KcContextExtension>({
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const { kcContext } = getKcContext({
|
||||||
|
// Uncomment to test the login page for development.
|
||||||
|
//mockPageId: "login.ftl",
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
export type KcContext = NonNullable<typeof kcContext>;
|
export type KcContext = NonNullable<typeof kcContext>;
|
94
src/keycloak-theme/login/pages/Login.stories.tsx
Normal file
94
src/keycloak-theme/login/pages/Login.stories.tsx
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||||
|
import { createPageStory } from "../createPageStory";
|
||||||
|
|
||||||
|
const { PageStory } = createPageStory({
|
||||||
|
pageId: "login.ftl"
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "login/Login",
|
||||||
|
component: PageStory,
|
||||||
|
} as ComponentMeta<typeof PageStory>;
|
||||||
|
|
||||||
|
export const Default: ComponentStory<typeof PageStory> = () => <PageStory />;
|
||||||
|
|
||||||
|
export const WithoutPasswordField: ComponentStory<typeof PageStory> = () => (
|
||||||
|
<PageStory
|
||||||
|
kcContext={{
|
||||||
|
realm: { password: false }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const WithoutRegistration: ComponentStory<typeof PageStory> = () => (
|
||||||
|
<PageStory
|
||||||
|
kcContext={{
|
||||||
|
realm: { registrationAllowed: false }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const WithoutRememberMe: ComponentStory<typeof PageStory> = () => (
|
||||||
|
<PageStory
|
||||||
|
kcContext={{
|
||||||
|
realm: { rememberMe: false }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const WithoutPasswordReset: ComponentStory<typeof PageStory> = () => (
|
||||||
|
<PageStory
|
||||||
|
kcContext={{
|
||||||
|
realm: { resetPasswordAllowed: false }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const WithEmailAsUsername: ComponentStory<typeof PageStory> = () => (
|
||||||
|
<PageStory
|
||||||
|
kcContext={{
|
||||||
|
realm: { loginWithEmailAllowed: false }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const WithPresetUsername: ComponentStory<typeof PageStory> = () => (
|
||||||
|
<PageStory
|
||||||
|
kcContext={{
|
||||||
|
login: { username: "max.mustermann@mail.com" }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const WithImmutablePresetUsername: ComponentStory<typeof PageStory> = () => (
|
||||||
|
<PageStory
|
||||||
|
kcContext={{
|
||||||
|
login: { username: 'max.mustermann@mail.com' },
|
||||||
|
usernameEditDisabled: true
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const WithSocialProviders: ComponentStory<typeof PageStory> = () => (
|
||||||
|
<PageStory
|
||||||
|
kcContext={{
|
||||||
|
social: {
|
||||||
|
displayInfo: true, providers: [
|
||||||
|
{ 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' },
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
21
src/keycloak-theme/login/pages/MyExtraPage2.stories.tsx
Normal file
21
src/keycloak-theme/login/pages/MyExtraPage2.stories.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||||
|
import { createPageStory } from "../createPageStory";
|
||||||
|
|
||||||
|
const { PageStory } = createPageStory({
|
||||||
|
pageId: "my-extra-page-2.ftl"
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "login/MyExtraPage2",
|
||||||
|
component: PageStory,
|
||||||
|
} as ComponentMeta<typeof PageStory>;
|
||||||
|
|
||||||
|
export const Default: ComponentStory<typeof PageStory> = () => <PageStory />;
|
||||||
|
|
||||||
|
export const WitAbc: ComponentStory<typeof PageStory> = () => (
|
||||||
|
<PageStory
|
||||||
|
kcContext={{
|
||||||
|
someCustomValue: "abc"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
@ -17,6 +17,7 @@ export default function MyExtraPage1(props: PageProps<Extract<KcContext, { pageI
|
|||||||
>
|
>
|
||||||
|
|
||||||
<form>
|
<form>
|
||||||
|
{kcContext.someCustomValue}
|
||||||
{/*...*/}
|
{/*...*/}
|
||||||
</form>
|
</form>
|
||||||
</Template>
|
</Template>
|
||||||
|
13
src/keycloak-theme/login/pages/Terms.stories.tsx
Normal file
13
src/keycloak-theme/login/pages/Terms.stories.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||||
|
import { createPageStory } from "../createPageStory";
|
||||||
|
|
||||||
|
const { PageStory } = createPageStory({
|
||||||
|
pageId: "terms.ftl"
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "login/Terms",
|
||||||
|
component: PageStory,
|
||||||
|
} as ComponentMeta<typeof PageStory>;
|
||||||
|
|
||||||
|
export const Primary: ComponentStory<typeof PageStory> = () => <PageStory />;
|
Loading…
Reference in New Issue
Block a user