From d1decfbedba38015e6bb30364dc751b83ae7a41f Mon Sep 17 00:00:00 2001 From: Brion Date: Sat, 13 Jul 2024 13:49:13 +0530 Subject: [PATCH] [docs] init docs --- docs/.gitignore | 134 ++++ docs/.vitepress/config.ts | 27 + docs/.vitepress/theme/index.ts | 17 + docs/.vitepress/theme/style.css | 139 ++++ docs/api-examples.md | 49 ++ docs/content/ADVANCED.md | 7 + docs/content/ARCHITECTURE.md | 43 + docs/content/BUILD_AND_RUN.md | 49 ++ docs/content/CONFIGURATION.md | 734 ++++++++++++++++++ docs/content/CONNECTORS.md | 52 ++ docs/content/DEPLOYMENT.md | 86 ++ docs/content/DEVELOPER.md | 33 + docs/content/FORMS.md | 127 +++ docs/content/MAINTENANCE.md | 23 + docs/content/SET_UP_DEV_ENVIRONMENT.md | 92 +++ docs/content/STYLE-GUIDE.md | 40 + docs/content/TROUBLESHOOTING.md | 138 ++++ docs/content/hotfix/README.md | 66 ++ docs/content/release/README.md | 58 ++ docs/content/testing/README.md | 11 + docs/content/testing/STATIC_CODE_ANALYSIS.md | 103 +++ docs/content/testing/UNIT_TESTING.md | 226 ++++++ docs/content/write-code/CODE_QUALITY.md | 27 + docs/content/write-code/DATA_FETCHING.md | 171 ++++ .../write-code/DEVELOPING_REACT_CODE.md | 97 +++ docs/content/write-code/ENSURING_GOOD_UX.md | 32 + docs/content/write-code/FORMATTING.md | 31 + docs/content/write-code/PERFORMANCE.md | 173 +++++ docs/content/write-code/README.md | 11 + docs/content/write-code/STYLING.md | 37 + ...DD_TEXT_CUSTOMIZATION_TO_NEW_INTERFACES.md | 80 ++ docs/index.md | 25 + docs/markdown-examples.md | 85 ++ docs/package.json | 40 + 34 files changed, 3063 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/.vitepress/config.ts create mode 100644 docs/.vitepress/theme/index.ts create mode 100644 docs/.vitepress/theme/style.css create mode 100644 docs/api-examples.md create mode 100644 docs/content/ADVANCED.md create mode 100644 docs/content/ARCHITECTURE.md create mode 100644 docs/content/BUILD_AND_RUN.md create mode 100644 docs/content/CONFIGURATION.md create mode 100644 docs/content/CONNECTORS.md create mode 100644 docs/content/DEPLOYMENT.md create mode 100644 docs/content/DEVELOPER.md create mode 100644 docs/content/FORMS.md create mode 100644 docs/content/MAINTENANCE.md create mode 100644 docs/content/SET_UP_DEV_ENVIRONMENT.md create mode 100644 docs/content/STYLE-GUIDE.md create mode 100644 docs/content/TROUBLESHOOTING.md create mode 100644 docs/content/hotfix/README.md create mode 100644 docs/content/release/README.md create mode 100644 docs/content/testing/README.md create mode 100644 docs/content/testing/STATIC_CODE_ANALYSIS.md create mode 100644 docs/content/testing/UNIT_TESTING.md create mode 100644 docs/content/write-code/CODE_QUALITY.md create mode 100644 docs/content/write-code/DATA_FETCHING.md create mode 100644 docs/content/write-code/DEVELOPING_REACT_CODE.md create mode 100644 docs/content/write-code/ENSURING_GOOD_UX.md create mode 100644 docs/content/write-code/FORMATTING.md create mode 100644 docs/content/write-code/PERFORMANCE.md create mode 100644 docs/content/write-code/README.md create mode 100644 docs/content/write-code/STYLING.md create mode 100644 docs/content/write-code/branding/ADD_TEXT_CUSTOMIZATION_TO_NEW_INTERFACES.md create mode 100644 docs/index.md create mode 100644 docs/markdown-examples.md create mode 100644 docs/package.json diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000000..f4ca5745f05 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,134 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# vitepress build output +.vitepress/dist +.vitepress/cache diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 00000000000..b7f156b0f8c --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,27 @@ +import { defineConfig } from 'vitepress' + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: "Developer Guide", + description: "Developer documentation for the WSO2 Identity Server Apps codebase", + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + nav: [ + { text: 'Home', link: '/' }, + { text: 'Guides', link: '/content/DEVELOPER' } + ], + + sidebar: [ + { + text: 'Overview', + items: [ + { text: 'Developer Guide', link: '/content/DEVELOPER' }, + ] + } + ], + + socialLinks: [ + { icon: 'github', link: 'https://github.com/wso2/identity-apps' } + ] + } +}) diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts new file mode 100644 index 00000000000..def4cfc87ef --- /dev/null +++ b/docs/.vitepress/theme/index.ts @@ -0,0 +1,17 @@ +// https://vitepress.dev/guide/custom-theme +import { h } from 'vue' +import type { Theme } from 'vitepress' +import DefaultTheme from 'vitepress/theme' +import './style.css' + +export default { + extends: DefaultTheme, + Layout: () => { + return h(DefaultTheme.Layout, null, { + // https://vitepress.dev/guide/extending-default-theme#layout-slots + }) + }, + enhanceApp({ app, router, siteData }) { + // ... + } +} satisfies Theme diff --git a/docs/.vitepress/theme/style.css b/docs/.vitepress/theme/style.css new file mode 100644 index 00000000000..d63aee82dc9 --- /dev/null +++ b/docs/.vitepress/theme/style.css @@ -0,0 +1,139 @@ +/** + * Customize default theme styling by overriding CSS variables: + * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css + */ + +/** + * Colors + * + * Each colors have exact same color scale system with 3 levels of solid + * colors with different brightness, and 1 soft color. + * + * - `XXX-1`: The most solid color used mainly for colored text. It must + * satisfy the contrast ratio against when used on top of `XXX-soft`. + * + * - `XXX-2`: The color used mainly for hover state of the button. + * + * - `XXX-3`: The color for solid background, such as bg color of the button. + * It must satisfy the contrast ratio with pure white (#ffffff) text on + * top of it. + * + * - `XXX-soft`: The color used for subtle background such as custom container + * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors + * on top of it. + * + * The soft color must be semi transparent alpha channel. This is crucial + * because it allows adding multiple "soft" colors on top of each other + * to create a accent, such as when having inline code block inside + * custom containers. + * + * - `default`: The color used purely for subtle indication without any + * special meanings attched to it such as bg color for menu hover state. + * + * - `brand`: Used for primary brand colors, such as link text, button with + * brand theme, etc. + * + * - `tip`: Used to indicate useful information. The default theme uses the + * brand color for this by default. + * + * - `warning`: Used to indicate warning to the users. Used in custom + * container, badges, etc. + * + * - `danger`: Used to show error, or dangerous message to the users. Used + * in custom container, badges, etc. + * -------------------------------------------------------------------------- */ + + :root { + --vp-c-default-1: var(--vp-c-gray-1); + --vp-c-default-2: var(--vp-c-gray-2); + --vp-c-default-3: var(--vp-c-gray-3); + --vp-c-default-soft: var(--vp-c-gray-soft); + + --vp-c-brand-1: var(--vp-c-indigo-1); + --vp-c-brand-2: var(--vp-c-indigo-2); + --vp-c-brand-3: var(--vp-c-indigo-3); + --vp-c-brand-soft: var(--vp-c-indigo-soft); + + --vp-c-tip-1: var(--vp-c-brand-1); + --vp-c-tip-2: var(--vp-c-brand-2); + --vp-c-tip-3: var(--vp-c-brand-3); + --vp-c-tip-soft: var(--vp-c-brand-soft); + + --vp-c-warning-1: var(--vp-c-yellow-1); + --vp-c-warning-2: var(--vp-c-yellow-2); + --vp-c-warning-3: var(--vp-c-yellow-3); + --vp-c-warning-soft: var(--vp-c-yellow-soft); + + --vp-c-danger-1: var(--vp-c-red-1); + --vp-c-danger-2: var(--vp-c-red-2); + --vp-c-danger-3: var(--vp-c-red-3); + --vp-c-danger-soft: var(--vp-c-red-soft); +} + +/** + * Component: Button + * -------------------------------------------------------------------------- */ + +:root { + --vp-button-brand-border: transparent; + --vp-button-brand-text: var(--vp-c-white); + --vp-button-brand-bg: var(--vp-c-brand-3); + --vp-button-brand-hover-border: transparent; + --vp-button-brand-hover-text: var(--vp-c-white); + --vp-button-brand-hover-bg: var(--vp-c-brand-2); + --vp-button-brand-active-border: transparent; + --vp-button-brand-active-text: var(--vp-c-white); + --vp-button-brand-active-bg: var(--vp-c-brand-1); +} + +/** + * Component: Home + * -------------------------------------------------------------------------- */ + +:root { + --vp-home-hero-name-color: transparent; + --vp-home-hero-name-background: -webkit-linear-gradient( + 120deg, + #bd34fe 30%, + #41d1ff + ); + + --vp-home-hero-image-background-image: linear-gradient( + -45deg, + #bd34fe 50%, + #47caff 50% + ); + --vp-home-hero-image-filter: blur(44px); +} + +@media (min-width: 640px) { + :root { + --vp-home-hero-image-filter: blur(56px); + } +} + +@media (min-width: 960px) { + :root { + --vp-home-hero-image-filter: blur(68px); + } +} + +/** + * Component: Custom Block + * -------------------------------------------------------------------------- */ + +:root { + --vp-custom-block-tip-border: transparent; + --vp-custom-block-tip-text: var(--vp-c-text-1); + --vp-custom-block-tip-bg: var(--vp-c-brand-soft); + --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft); +} + +/** + * Component: Algolia + * -------------------------------------------------------------------------- */ + +.DocSearch { + --docsearch-primary-color: var(--vp-c-brand-1) !important; +} + diff --git a/docs/api-examples.md b/docs/api-examples.md new file mode 100644 index 00000000000..6bd8bb5c170 --- /dev/null +++ b/docs/api-examples.md @@ -0,0 +1,49 @@ +--- +outline: deep +--- + +# Runtime API Examples + +This page demonstrates usage of some of the runtime APIs provided by VitePress. + +The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files: + +```md + + +## Results + +### Theme Data +
{{ theme }}
+ +### Page Data +
{{ page }}
+ +### Page Frontmatter +
{{ frontmatter }}
+``` + + + +## Results + +### Theme Data +
{{ theme }}
+ +### Page Data +
{{ page }}
+ +### Page Frontmatter +
{{ frontmatter }}
+ +## More + +Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata). diff --git a/docs/content/ADVANCED.md b/docs/content/ADVANCED.md new file mode 100644 index 00000000000..64b7bb76e85 --- /dev/null +++ b/docs/content/ADVANCED.md @@ -0,0 +1,7 @@ +# Advanced + +Here are the topics for the Identity Apps adavanced concepts. + +1. [Architecture](./ARCHITECTURE.md) + + > Follow this guide to learn how the project architecture is set-up. diff --git a/docs/content/ARCHITECTURE.md b/docs/content/ARCHITECTURE.md new file mode 100644 index 00000000000..837bf1b4726 --- /dev/null +++ b/docs/content/ARCHITECTURE.md @@ -0,0 +1,43 @@ +# Architecture + +Follow this guide to learn how the project architecture is set-up. + +## Repo Structure + +We follow a monolithic structure when it comes to the structure of the repository. + +The repository is setup as a **mono-repo** with the help of [NX](https://nx.dev/) mono repo management tool. And it has all the front end applications along with the shared modules. + +> πŸ’‘ A Monorepo, as the name suggests mono (single) and repo (repository of the codebase) is a single source of truth for the entire project code base. + +Following is a high level diagram depicting the different components in our structure. + +> ⚠️ Keep [this diagram](./assets/repo-monolithic-structure.excalidraw) up-to date when ever a component change occurs. + +![Repo Monolithic Structure](./assets/repo-monolithic-structure.png) + +## Dependency Graph + +Following is the [dependency graph](https://nx.dev/nx/dep-graph) generated with NX. + +This shows how the different components interact with each other inside the repository. + +> ⚠️ Keep this diagram up-to date when ever a component change occurs by executing `pnpx nx graph` command. + +![Repo Dependency Graph](./assets/nx-dependency-graph.png) + +## Computational Caching + +This repository leverages the [Computation Caching](https://nx.dev/using-nx/caching) provided by NX. + +Following gif shows how quickly NX rebuilds from cache. + +![NX Caching No Affected](./assets/nx-caching.gif) + +> πŸ’‘ When a certain module is changed, for an example `core`, NX will only build the specific module and the other components that depend on the `core` module. All the unrelated components will be built from cache. + +## Remote Data Fetching Architecture + + + + diff --git a/docs/content/BUILD_AND_RUN.md b/docs/content/BUILD_AND_RUN.md new file mode 100644 index 00000000000..6542b4f2325 --- /dev/null +++ b/docs/content/BUILD_AND_RUN.md @@ -0,0 +1,49 @@ +# Build & Run + +Follow this guide to install the dependencies and build the modules needed to run the apps in the local environment. + +* [Install Dependencies](#install-dependencies) +* [Build](#build) + * [Building using Maven](#building-using-maven) + * [Building using pnpm](#building-using-pnpm) +* [Run](#run) + +## Install Dependencies + +The following script installs the local modules(react-components, theme, etc.) using pnpm workspaces and also installs the other dependencies. + +```shell +pnpm install +``` + +## Build + +We support the following set of build strategies. + +### Building using Maven + +Run the following command from the root of the project (where the root `pom.xml` is located). + +```shell +# Installs the dependencies & builds the entire project including the JSP portals. +mvn clean install +``` + +### Building using pnpm + +Run the relevant command from the root of the project (where the root `package.json` is located). + +```shell +# Builds the node projects. +pnpm build +``` + +## Run + +To run the apps, navigate to the specific folder and execute `npm start`. + +```shell +# To run My Account +cd apps/myaccount +pnpm start +``` diff --git a/docs/content/CONFIGURATION.md b/docs/content/CONFIGURATION.md new file mode 100644 index 00000000000..4227d60acc5 --- /dev/null +++ b/docs/content/CONFIGURATION.md @@ -0,0 +1,734 @@ +# Configurations + +* [Overview](#overview) +* [Common Configs](#common-configs) +* [Console Specific Configs](#console-specific-configs) + +## Overview + +The portals i.e. Console & My Account are configurable using the `deployment.toml` when they are hosted inside the Identity Server. +The Jinja 2 template files which can be found in `features/org.wso2.identity.apps.{$appName}.server.feature/resources/deployment.config.json.j2` are used to template the configuration file i.e. `deploymemnt.config.json` which can be found at the root of the webapp. + +**Note**: If the portals are to be hosted outside, the aforementioned `deployment.config.json` file has to be modified accordingly. + +To learn more abut the new configuration model, click [here](https://is.docs.wso2.com/en/latest/references/new-configuration-model/). + +## Common Configs + +The following sections contain the common configs that are needed to configure/override the existing behaviour of the `Console` or `My Account` application. + +### `app_base_name` + +> :white_check_mark: Default JSON value - `"console"` | `"myaccount"` + +This configuration is needed if you want to change app base name from `console` or `myaccount` to something else. + +**Note**: Changing just the bellow config will not be enough to achieve the desired results. You will have to manually rename the application in `/repository/deployment/server/webapps`. +And also you will have to refactor the paths(links to the theme, rpIframe etc.) in `index.jsp` at the root of the `console` webapp. + +**Supported Values -** Any string value + +```toml +[console] +app_base_name = "custom-console" +``` + +**Note for Developers**: If you want to build the application with a different basename, change this config in `/apps/console/src/public/deployment.config.json`. +[Webapack](https://webpack.js.org/) will use this value during build time to put all the build files. + +### `app_base_name_for_history_api` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"/"` + +Base name used by the browser history API. For the default SaaS behaviour `/` has been used due to limitations in history API. See https://github.com/ReactTraining/history/issues/644. +This config was added to enable support for none SaaS apps so that they can easily history push. + +**Supported Values -** Any path with a leading forward slash. + +```toml +[console] +app_base_name_for_history_api = "/console" +``` + +### `client_id` + +> :white_check_mark: Default JSON value - `"CONSOLE"` | `"MY_ACCOUNT"` + +Client ID of the application. + +**Supported Values -** Any string value. Check the [OIDC configurations section](https://is.docs.wso2.com/en/latest/learn/configuring-oauth2-openid-connect-single-sign-on/) of the application to retrieve the correct value. + +```toml +[console] +client_id = "CONSOLE" +``` + +### `debug` + +> :white_check_mark: Default JSON value - `false` + +Enable debug logs for certain features such as `i18n` etc. + +**Supported Values -** `true` | `false` + +```toml +[console] +debug.enable = true +``` + +### `idp_configs` + +Configs for the [authentication SDK](https://github.com/asgardio/asgardio-js-oidc-sdk). + +#### `enablePKCE` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `true` + +The Proof Key for Code Exchange (PKCE) is a specification supported by WSO2 Identity Server to mitigate code interception attacks. +[See Mitigating Authorization Code Interception Attacks](https://is.docs.wso2.com/en/latest/administer/mitigating-authorization-code-interception-attacks) to configure PKCE for an OAuth application. + +**Supported Values -** true | false + +```toml +[console] +idp_configs.enablePKCE = true +``` + +#### `clockTolerance` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - 60 Seconds (Declared in SDK) + +Allowed leeway when validating the id_token. Required to address possible time mismatches between the client and the server. +[Check the Specification](https://tools.ietf.org/html/rfc7519#page-10) + +**Supported Values -** Any number (in Seconds) + +```toml +[console] +idp_configs.clockTolerance = 120 +``` + +#### `responseMode` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"form_post"` + +How the result of the authorization request is formatted. + +**Supported Values -** `"form_post"` | `"query"` + +```toml +[console] +idp_configs.responseMode = "form_post" +``` + +#### `scope` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `[ "SYSTEM" ]` + +Scopes requested when the token request is made. + +**Supported Values -** String array + +```toml +[console] +idp_configs.scope = [ "internal_login", "internal_identity_mgt_view" ] +``` + +#### `serverOrigin` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"https://localhost:9443"` + +The origin of the Identity Provider. eg: https://localhost:9443 + +**Supported Values -** Any URL. + +```toml +[console] +idp_configs.serverOrigin = "https://localhost:9443" +``` + +#### `storage` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"webWorker"` + +The storage medium where the session information such as the access token should be stored. + +**Supported Values -** `"sessionStorage"` | `"webWorker"` | `"localStorage"` + +```toml +[console] +idp_configs.storage = "webWorker" +``` + +#### `authorizeEndpointURL` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"/oauth2/authorize"` + +The endpoint to send the authorization request to. + +**Supported Values -** Any relative URL. + +```toml +[console] +idp_configs.authorizeEndpointURL = "/oauth2/authorize" +``` + +#### `jwksEndpointURL` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"/oauth2/jwks"` + +The endpoint from which the JSON Web Keyset can be obtained. + +**Supported Values -** Any relative URL. + +```toml +[console] +idp_configs.jwksEndpointURL = "/oauth2/jwks" +``` + +#### `logoutEndpointURL` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"/oidc/logout"` + +The endpoint to send the logout request to. + +**Supported Values -** Any relative URL. + +```toml +[console] +idp_configs.logoutEndpointURL = "/oidc/checksession" +``` + +#### `oidcSessionIFrameEndpointURL` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"/oidc/checksession"` + +The URL of the OIDC session iframe. + +**Supported Values -** Any relative URL. + +```toml +[console] +idp_configs.oidcSessionIFrameEndpointURL = "/oidc/checksession" +``` + +#### `tokenRevocationEndpointURL` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"/oauth2/revoke"` + +The endpoint to send the revoke-access-token request to.. + +**Supported Values -** Any relative URL. + +```toml +[console] +idp_configs.tokenRevocationEndpointURL = "/oauth2/revoke" +``` + +#### `tokenEndpointURL` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"/oauth2/token"` + +The endpoint to send the token request to. + +**Supported Values -** Any relative URL. + +```toml +[console] +idp_configs.tokenEndpointURL = "/oauth2/token" +``` + +#### `tokenEndpointURL` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"/oauth2/oidcdiscovery/.well-known/openid-configuration"` + +The endpoint to receive the OIDC endpoints from. + +**Supported Values -** Any relative URL. + +```toml +[console] +idp_configs.wellKnownEndpointURL = "/oauth2/oidcdiscovery/.well-known/openid-configuration" +``` + +### `session` + +OIDC Session management configs. + +#### `userIdleTimeOut` + +> :white_check_mark: Default JSON value - `600` + +Idle session timeout interval. + +**Supported Values -** Any numerical value. (in seconds) + +```toml +[console] +session.params.userIdleTimeOut = 600 +``` + +#### `userIdleWarningTimeOut` + +> :white_check_mark: Default JSON value - `580` + +When will the warning modal appear to warn about idle timeout. + +**Supported Values -** Any numerical value. (in seconds and should be less than `userIdleTimeOut`) + +```toml +[console] +session.params.userIdleWarningTimeOut = 580 +``` + +#### `sessionRefreshTimeOut` + +> :white_check_mark: Default JSON value - `300` + +When to send the session extension request. + +**Supported Values -** Any numerical value. (in seconds) + +```toml +[console] +session.params.sessionRefreshTimeOut = 300 +``` + +#### `checkSessionInterval` + +> :white_check_mark: Default JSON value - `3` + +At what interval should the app poll for session state. + +**Supported Values -** Any numerical value. (in seconds) + +```toml +[console] +session.params.checkSessionInterval = 3 +``` + +### `tenantResolutionStrategy` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"id_token"` + +How is the tenant resolved after the user is logged in. +In SaaS mode, the tenant will be extracted from the logged in users ID token. Otherwise, the tenant can be obtained by reading the URL. + +**Supported Values -** `"location"` | `"id_token"` + +```toml +[console] +tenantResolutionStrategy = "id_token" +``` + +### `server_origin` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - URL will be taken from IdentityUtil.getServerURL() + +Server Origin URL to be used for API requests etc. +URL will be taken from [getServerURL()](https://github.com/wso2-attic/carbon-identity/blob/master/components/identity-core/org.wso2.carbon.identity.core/src/main/java/org/wso2/carbon/identity/core/util/IdentityUtil.java#L298) method in IdentityUtil when the app is deployed inside IS. + +**Supported Values -** Any URL. + +```toml +[console] +server_origin = "https://localhost:9443" +``` + +### `route_paths` + +App route paths. + +#### `home` + +> :white_check_mark: Default JSON value - `"/develop/applications"` (for Console) | `"/overview"` (for My Account) + +Where to route the users when the app is loaded. + +**Supported Values -** Any path defined in the app. + +```toml +[console] +route_paths.home = "/manage/users" +``` + +#### `login` + +> :white_check_mark: Default JSON value - `"/login"` (for Console) | `"/login"` (for My Account) + +Where to route the users on login. + +**Supported Values -** Any path defined in the app. + +```toml +[console] +route_paths.login = "/login" +``` + +#### `logout` + +> :white_check_mark: Default JSON value - `"/logout"` (for Console) | `"/logout"` (for My Account) + +Where to route the users on logout. + +**Supported Values -** Any path defined in the app. + +```toml +[console] +route_paths.logout = "/logout" +``` + +### `ui` + +UI configurations. + +#### `announcements` + +Announcements to be displayed on the banner. Configured as an array. + +##### `color` + +> :bulb: No value defined in Default JSON + +Color of the Announcements banner. + +**Supported Values -** [`SemanticCOLORS`](https://semantic-ui.com/usage/theming.html#sitewide-defaults) | `"primary"` | `"secondary"` + +```toml +[[console.ui.announcements]] +color = "primary" +``` + +##### `order` + +> :bulb: No value defined in Default JSON + +Order of the Announcement. + +**Supported Values -** number + +```toml +[[console.ui.announcements]] +order = 1.0 +``` + +##### `expire` + +> :bulb: No value defined in Default JSON + +Announcement expiry time. + +**Supported Values -** Time stamp. + +```toml +[[console.ui.announcements]] +expire = "1593475200" +``` + +##### `id` + +> :bulb: No value defined in Default JSON + +Unique ID for the Announcement. + +**Supported Values -** Any string. Preferably a GUID. + +```toml +[[console.ui.announcements]] +id = "d47a8201-3d58-43ae-b1a9-1ac653814f4e" +``` + +##### `message` + +> :bulb: No value defined in Default JSON + +Main message for the Announcement. + +**Supported Values -** Any string. + +```toml +[[console.ui.announcements]] +message = "Regular maintenance work will be carried out and the service will be unavailable for few hours." +``` + +#### `app_copyright` + +> :white_check_mark: Default JSON value - `"WSO2 Identity Server"` + +App copyright to be displayed on footer. + +**Supported Values -** Any string. + +```toml +[console] +ui.app_copyright = "WSO2 Identity Server" +``` + +#### `app_title` + +> :white_check_mark: Default JSON value - `"Console | WSO2 Identity Server"` (for Console) | `"My Account | WSO2 Identity Server"` (for My Account) + +Browser tab title. + +**Supported Values -** Any string. + +```toml +[console] +ui.app_title = "Console | WSO2 Identity Server" +``` + +#### `app_name` + +> :white_check_mark: Default JSON value - `"Console"` (for Console) | `"My Account"` (for My Account) + +Display name of the app. + +**Supported Values -** Any string. + +```toml +[console] +ui.app_name = "Console" +``` + +#### `app_logo_path` + +> :white_check_mark: Default JSON value - `"/assets/images/logo.svg"` + +Path of the app logo. + +**Supported Values -** Relative paths (will be resolved from the resource bundle) | Hosted Images | Data URLs + +```toml +[console] +ui.app_logo_path = "https://cdn.wso2.is.com/assets/images/logo.svg" +``` + +#### `gravatar.configs` + +Gravatar configs. + +##### `fallback` + +> :white_check_mark: Default JSON value - `"404"` + +Fallback types for gravatar images. + +**Supported Values -** `"404"` | `"default"` | `"mp"` | `"identicon"` | `"monsterid"` | `"wavatar"` | `"retro"` | `"robohash"` | `"blank"` + +```toml +[console] +ui.gravatar.configs.fallback = "404" +``` + +##### `defaultImage` + +> :bulb: No value defined in Default JSON + +Custom fallback image URL if Gravatar is not found. + +**Supported Values -** Any image URL. + +```toml +[console] +ui.gravatar.configs.defaultImage = "https://cdn.wso2.is.com/assets/images/gravatar-fallback.png" +``` + +##### `size` + +> :bulb: No value defined in Default JSON + +Gravatar image size. + +**Supported Values -** Any number. See http://en.gravatar.com/site/implement/images/#size. + +```toml +[console] +ui.gravatar.configs.size = 200 +``` + +#### `product_name` + +> :white_check_mark: Default JSON value - `"Identity Server"` + +Product name. + +**Supported Values -** Any string. + +```toml +[console] +ui.product_name = "Identity Server" +``` + +### `product_version.configs` + +Configurations for customizing the product version label. + +#### `allowSnapshot` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `false` + +Shows the snapshot label if present in product version. + +**Supported Values -** `true` | `false` + +```toml +[console] +product_version.configs.allowSnapshot = false +``` + +#### `productVersion` + +> :bulb: No value defined in Default JSON + +Overrides the version number. Use "" if version should be hidden. Drop the attribute if no change to version number is required. + +**Supported Values -** Any string or "" + +```toml +[console] +product_version.configs.productVersion = "ALPHA" +``` + +#### `textCase` + +> :bulb: No value defined in Default JSON + +Text case for the version. + +**Supported Values -** `"lowercase"` | `"uppercase"` + +```toml +[console] +product_version.configs.textCase = "uppercase" +``` + +#### `labelColor` + +> :bulb: No value defined in Default JSON + +> :checkered_flag: Fallback Value - `"primary"` + +Color of the label. + +**Supported Values -** `"auto"` | `"primary"` | `"secondary"` | [`SemanticCOLORS`](https://semantic-ui.com/usage/theming.html#sitewide-defaults) + +```toml +[console] +product_version.configs.labelColor = "primary" +``` + +### `theme` + +Theme configurations. + +#### `name` + +> :white_check_mark: Default JSON value - `"default"` + +Name of the app theme. + +**Supported Values -** Any string. + +```toml +[console] +theme = "default" +``` + +## Console Specific Configs + +The following sections contain `Console` specific configs that cann be used to configure/override the existing behaviour of the `Console` application. + +### `applications` + +Different configurations for applications that are used inside the `Console`. + +#### `account_app` + +My Account app configurations. + +```toml +[console] +applications.account_app.configs.origin = "" # Defaults to the server URL (ex: https://localhost:9443). +applications.account_app.configs.path = "" # Relative path(without tenant) to navigate when the My Account link is clicked on the user dropdown. Defaults to `/myaccount/overview`. +``` + +#### `admin_app` + +Console app's **Manage** section configs. + +```toml +[console] +applications.admin_app.configs.basePath = "" # Defaults to the `/manage`. +applications.admin_app.configs.displayName = "" # Name to displayed in the tab. Defaults to the `Manage`. +applications.admin_app.configs.path = "" # Path to navigate the users when the manage tab is clicked. Defaults to the `/manage/users`. +``` + +#### `developer_app` + +Console app's **Develop** section configs. + +```toml +[console] +applications.developer_app.configs.basePath = "" # Defaults to the `/develop`. +applications.developer_app.configs.displayName = "" # Name to displayed in the tab. Defaults to the `Develop`. +applications.developer_app.configs.path = "" # Path to navigate the users when the manage tab is clicked. Defaults to the `/develop/applications`. +``` + +### `extensions` + +> :negative_squared_cross_mark: No value defined in Default JSON + +App extensions configuration. + +#### `connectors` + +> :bulb: No value defined in Default JSON + +Add UI metadata for the connectors you add to the Identity Server instance. + +> πŸ“– For more information, read through [Connectors guide](./CONNECTORS.md). + + +The following configuration adds UI metadata for the LinkedIn connector. + +```toml +[[console.extensions.connectors]] +authenticatorId="TGlua2VkSW4" +description="Login users with existing LinkedIn accounts" +displayName="LinkedIn" +icon="https://brand.linkedin.com/content/dam/me/business/en-us/amp/brand-site/v2/bg/LI-Bug.svg.original.svg" +``` diff --git a/docs/content/CONNECTORS.md b/docs/content/CONNECTORS.md new file mode 100644 index 00000000000..4560e05bf07 --- /dev/null +++ b/docs/content/CONNECTORS.md @@ -0,0 +1,52 @@ +# Connectors + +## Authenticators + +An authenticator allows you to authenticate the user using third party authentication systems such as LinkedIn, Duo security and Foursquare. + +By default Identity Server packs several of these Authenticators and they are available to be configured via the Console. + +But WSO2 has a wide range of authenticators in the [connector store](https://store.wso2.com/store/assets/isconnector/list) that you can plugin in to your Identity Server instance. + +Let's see how we can configure LinkedIn connector in Console. + +### Steps + +1. Download the [LinkedIn connector](https://store.wso2.com/store/assets/isconnector/details/3a4f9dd9-be56-4e79-a925-8d8a4ace5a8f) from WSO2 connector store.(`org.wso2.carbon.extension.identity.authenticator.linkedin.connector-x.x.x`). + +2. Place the authenticator.jar file into the +`/repository/components/dropins` directory. + +3. Re-start the WSO2 Identity Server. + +> πŸ’‘ For more in formation, read through the [connector documentation](https://github.com/wso2-extensions/identity-outbound-auth-linkedIn/blob/master/docs/README.md). + +4. Login to Console (https://localhost:9443/console) + +5. Navigate to `Connections > Create Connection` and create a Connection with the `Custom Connector` Connection template. + + ![Create Connection with Custom Connector](./assets/create-idp-with-expert-mode.png) + +6. Once the Connection is created, navigate to the `Settings` tab and click on `New Authenticator` button. + +7. Select `LinkedIn` from the authenticator selection and proceed with configuration. + + ![Configure LinkedIn connector](./assets/configure-linkedin-connector.png) + +### (πŸ¦„ Optional) Add connector metadata to supplement the UI + +Optionally, you can add a `display name`, `icon` and a description to the newly added connector to make the UI nicer πŸ˜‰. + +Add something like the following in the `/repository/conf/deployment.toml`. + +> πŸ’‘ UI maps the meta data with the `authenticatorId`. This can be found by checking the `Browser Network` tab when the authenticators are loaded in the `Settings` tab. + +```toml +[[console.extensions.connectors]] +authenticatorId="TGlua2VkSW4" +description="Login users with existing LinkedIn accounts" +displayName="LinkedIn" +icon="https://brand.linkedin.com/content/dam/me/business/en-us/amp/brand-site/v2/bg/LI-Bug.svg.original.svg" +``` + +![Configure LinkedIn connector](./assets/configure-linkedin-connector-with-meta.png) diff --git a/docs/content/DEPLOYMENT.md b/docs/content/DEPLOYMENT.md new file mode 100644 index 00000000000..27ab1b58a84 --- /dev/null +++ b/docs/content/DEPLOYMENT.md @@ -0,0 +1,86 @@ +# Deployment + +## Deploying the apps on an external server + +It is possible to deploy the Console and My Account applications on an external server. To do so, the following steps has to be followed in order to build the applications. + +### Build + +#### Prepare the source + +Execute the following commands from the project root in order to build the repo. + +```bash +pnpm install +pnpm build +``` + +#### Build Console + +##### Deploy on a Java EE server (ex: Tomcat) + +Go inside `apps/console` and change the `.env.local` file as follows. + +```env +SERVER_TYPE="tomcat" +``` + +And then build the application. + + +```bash +pnpm build +``` + +##### Deploy on a static server. + +Go inside `apps/console` and change the `.env.local` file as follows. + +```env +SERVER_TYPE="static" +``` + +And then build the application. + + +```bash +pnpm build +``` + +> **Note** +> Once the build is completed, you can find the build artifacts inside the build folder i.e `apps/console/build`. + +#### Build My Account + +##### Deploy on a Java EE server (ex: Tomcat) + +Go inside `apps/myaccount` and change the `.env.local` file as follows. + +```env +SERVER_TYPE="tomcat" +``` + +And then build the application. + + +```bash +pnpm build +``` + +##### Deploy on a static server. + +Go inside `apps/myaccount` and change the `.env.local` file as follows. + +```env +SERVER_TYPE="static" +``` + +And then build the application. + + +```bash +pnpm build +``` + +> **Note** +> Once the build is completed, you can find the build artifacts inside the build folder i.e `apps/myaccount/build`. diff --git a/docs/content/DEVELOPER.md b/docs/content/DEVELOPER.md new file mode 100644 index 00000000000..33802be80ab --- /dev/null +++ b/docs/content/DEVELOPER.md @@ -0,0 +1,33 @@ +# Developer Guide + +Welcome to the WSO2 Identity Apps developer guide. If you would like to contribute to the code, see the information on this guide. + +## Get started + +1. [Setting Up Development Environment](./SET_UP_DEV_ENVIRONMENT.md) + + > Follow this guide to set up the source code, development tools & other software. + +2. [Build & Run](./BUILD_AND_RUN.md) + + > Follow this guide to install the dependencies and build the modules needed to run the apps in the local environment. + +3. [Write Code](./write-code/README.md) + + > Follow this guide to learn about our coding style and tips on writing maintainable code. + +4. [Testing](./testing/README.md) + + > Follow this guide to learn about our testing strategies. + +5. [Maintenance](./MAINTENANCE.md) + + > Follow this guide to learn about the maintainance tasks of the repository, such as, what to do with dependacy updatest, etc. + +6. [Advanced](./ADVANCED.md) + + > Follow this section to learn the advance concepts of the Identity Apps repository including Architecture, etc. + +6. [Troubleshooting](./TROUBLESHOOTING.md) + + > Look through here if you come across any issue. diff --git a/docs/content/FORMS.md b/docs/content/FORMS.md new file mode 100644 index 00000000000..f372e033e85 --- /dev/null +++ b/docs/content/FORMS.md @@ -0,0 +1,127 @@ +# Forms + +The @wso2is/form-fields library can cater to all the requirements that are identified when it comes to its use-cases. The fields of +this module is compatible with the semantic UI elements that are customised in the `react-components` module and +support their native behaviors. + +All form elements should use the WSO2 styled to be aligned with the default WSO2 `theme` for consistent design, good +user experience, and accessibility. + +## Fields + +This is the basic form field, it is a wrapper for any single input or select elements. It sets a few layout options by +default margins and styles any optional UI elements within. + +- [Text Inputs]() +- Buttons +- Checkboxes +- Radio Buttons + +### Text Inputs + +Text inputs are the basic building blocks of forms. They allow users to enter various types of data into web-based +forms. + +#### Best Practises + +- All form inputs must have a corresponding label. +- Provide a hint whenever the details collected from the input field is not self-explanatory. +- The label should be visible without relying on placeholders as not every browser can see them, nor can all + screenreaders. A visible permanent label provides continuous context. +- Whenever a input field is mandatory make sure to mark it as `required`. +- For text inputs that are optional, add "(optional)" to the input label. + +### Text Input Samples + +1. Basic Input Field + +![basic](assets/forms-field-basic.png) + +Sample Field Component +```html + +``` + +2. Input Field with Hint + +![with-hint](assets/forms-field-with-hint.png) + +Sample Field Component +```html + +``` + +2. Input Field with a Message + +![with-message](assets/forms-field-with-info-message.png) + +Sample Field Component +```html + + } +/> +``` + +### Text Input Validations + +The developer provided validation, or the default validations will be triggered by the `on-blur` event of the field. +The developers can overwrite the default validation criteria by providing custom validations by passing them to the +`validation` prop of the `FormField` component. + +#### Default Validations + +The default validations of the text input will rely on the `fieldType` you specify for the `FormField` component. The +type of the input can be picked out of the following, and the default validations will be +applied to the field accordingly. + +- `name` +- `email` +- `phoneNumber` +- `url` + +If the input violates the validation criteria and error message will be displayed through +a `semantic-ui` label pointing to the relevant input field. Also, if the field is marked as `required` an error will be +shown whenever the input field looses `focus`. + +![with-message](assets/froms-field-validation-email.png) + +Sample Field Component +```html + +``` diff --git a/docs/content/MAINTENANCE.md b/docs/content/MAINTENANCE.md new file mode 100644 index 00000000000..bec664fa27b --- /dev/null +++ b/docs/content/MAINTENANCE.md @@ -0,0 +1,23 @@ +# Maintenance + +Follow this guide to learn about the maintainance tasks of the repository. + +* [Dependabot Updates](#dependabot-updates) + +## Dependabot Updates + +PRs sent by `dependabot` can be found here - https://github.com/wso2/identity-apps/pulls/app%2Fdependabot + +Before merging `dependabot` PRs, they need to be tested and verified that they don't introduce any bugs or breaking changes locally. + +1. Fetch the latest codebase from upstream. + +2. **Locally** merge the dependabot branch. + +3. Test the changes and verify that everything is working in the product. + +4. If the changes are non-breaking, add a comment to verify the testing of the dependabot PR. Since `dependabot` bumps the `package.lock.json` versions, if the dependency in question is a **direct dependency**, we can bump the version in `package.json` and send another PR closing the dependabot PR. + +5. If it's a **transitive dependency**, we can check whether we can bump the parent dependency. In case if the parent dependency doesn't have the fixed version of the transitive dependency, we can create an issue in the respective project and merge the `package.lock.json` as a temporary fix. + +6. If there are breaking changes, send a PR to fix those breaking changes introduced from the newer dependency version. If it is not possible to fix the breaking changes or requires a significant effort, create a git issue and link it to the Dependabot PR to track these changes. diff --git a/docs/content/SET_UP_DEV_ENVIRONMENT.md b/docs/content/SET_UP_DEV_ENVIRONMENT.md new file mode 100644 index 00000000000..f3f1a7431b6 --- /dev/null +++ b/docs/content/SET_UP_DEV_ENVIRONMENT.md @@ -0,0 +1,92 @@ +# Setting Up Development Environment + +Follow this guide to set up the source code, development tools & other software. + +* [Prerequisite Software](#prerequisite-software) +* [Setting up Development Tools](#setting-up-development-tools) + * [NX Console](#nx-console) + * [React Developer Tools](#react-developer-tools) + * [Redux DevTools](#redux-devtools) + * [ESLint IDE Plugin](#eslint-ide-plugin) + * [Code Spell Checker Plugin](#code-spell-checker-plugin) +* [Setting up the Source Code](#setting-up-the-source-code) + +## Prerequisite Software + +To build and write code, make sure you have the following set of tools on your local environment: + +* [Git](https://git-scm.com/downloads) - Open source distributed version control system. For install instructions, refer [this](https://www.atlassian.com/git/tutorials/install-git). +* [Node.js](https://nodejs.org/en/download/) - JavaScript runtime with node package manager ([npm](https://www.npmjs.com/)). +* [pnpm](https://pnpm.io/) - Alternate npm client for faster package installs. +* [Maven](https://maven.apache.org/download.cgi) - Build automation tool for Java projects. +* [Java Development Kit 1.8](https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html) - Development environment for building applications using the Java programming language. + +## Setting up Development Tools + +### NX Console + +Editor plugin which wraps NX commands so you don't have to memorize. + +- [Install for VS Code](https://marketplace.visualstudio.com/items?itemName=nrwl.angular-console) +- [Install for VS Web Storm](https://plugins.jetbrains.com/plugin/15000-nx-webstorm) + +### React Developer Tools + +Browser extension to debug React code. + +- [Download for Chrome](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) +- [Download for Firefox](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/) + +### Redux DevTools + +Redux DevTools for debugging application's Redux store operations. + +- [Download for Chrome](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en) +- [Download for Firefox](https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/) + +### ESLint IDE Plugin + +ESLint is a static code analysis tool for identifying problematic patterns found in JavaScript/Typescript code. + +Make sure you setup the supplementary plugins in your IDE of choice. + +#### Webstorm + +WebStorm shows warnings and errors reported by ESLint right in the editor, as you type. + +- [Install the plugin](https://www.jetbrains.com/help/webstorm/eslint.html) + +#### VS Code + +Integrates ESLint into VS Code. The extension uses the ESLint library installed in the opened workspace folder. + +- [Install the plugin](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) + +### Code Spell Checker + +A basic spell checker that works well with code and documents. + +- [Install the plugin](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) + +### JSON Sort Order + +Sorts JSON objects in alphabetical order. + +- [Install the plugin](https://marketplace.visualstudio.com/items?itemName=msyesyan.json-sorter) + +## Setting up the Source Code + +1. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the repository. +2. Clone your fork to the local machine. + +Replace `` with your own username. + +```shell +git clone https://github.com//identity-apps.git +``` + +3. Set the original repo as the upstream remote. + +```shell +git remote add upstream https://github.com/wso2/identity-apps.git +``` diff --git a/docs/content/STYLE-GUIDE.md b/docs/content/STYLE-GUIDE.md new file mode 100644 index 00000000000..fff120865ef --- /dev/null +++ b/docs/content/STYLE-GUIDE.md @@ -0,0 +1,40 @@ +# WSO2 Identity Apps Style Guide + +The WSO2 Identity Apps Style Guide introduces a set of conventions to be followed when a developer contributes to WSO2 +Identity App portals. It is much easier to understand a complex product, or a codebase when a set of guidelines are in +place ensuring consistency. Therefore, through this style guide a set of guidelines, that comprises file naming +conventions, code formatting styles, UI design guidelines, etc., are provided. + +## Table of Content + +- [Introduction](#Introduction) +- Source files fundamentals +- Basic file structure +- Code formatting +- [Form library](#Form-Library) +- Accessibility support +- Using custom components +- Performance +- [Developer guidelines](https://github.com/wso2/identity-apps/blob/master/docs/DEVELOPER.md) +- UI design guidelines - TODO + + +## Introduction + +This document serves as the complete definition of WSO2’s coding standards for source code and UI design conventions +for the portals that are implemented. The main objective of introducing this is to maintain the consistency of products +from the code base to the visual representation. + +However, this document focuses primarily on the hard-and-fast rules that we follow universally, and avoids giving +advice that isn't clearly enforceable. Especially when it comes to the code formatting, file naming conventions, and +accessibility support criteria. The UI design guidelines will be helpful for the developers who will introduce new +UI components or enhance the existing UI elements in the products. The guide discusses various UI/UX aspects including +the element styles (colors, paddings, borders, etc.), element placements, usage of the custom UI components, etc. + +## Form Library + +The @wso2is/form library that we use in the WSO2 Identity App portals cater to all the requirements that are +identified when it comes to its use-cases. This helps to govern the styles of the form elements, and the behavioral +patterns of the forms used in WSO2 Identity Apps. Follow [these guidelines](https://github.com/wso2/identity-apps/blob/master/docs/FORMS.md) +to implement a form in the Identity App portals more efficiently, maintaining consistency of the UI aspects as well as the +code base. diff --git a/docs/content/TROUBLESHOOTING.md b/docs/content/TROUBLESHOOTING.md new file mode 100644 index 00000000000..efafcbbbe65 --- /dev/null +++ b/docs/content/TROUBLESHOOTING.md @@ -0,0 +1,138 @@ +# Troubleshooting + +Look through here if you come across any issue. + +✨ If your issues isn't here and you were able to figure a solution, please consider contribute to the guide. + +* [Changesets](#changesets) +* [Node](#node) + * [Dev Server Failures](#dev-server-failures) + * [File watchers exceed error](#file-watchers-exceed-error) + * [Package Install Failures](#package-install-failures) + * [Global npm package install errors on Mac System](#global-npm-package-install-errors-on-mac-system) +* [Maven](#maven) + * [Build Failures](#build-failures) + +## Changesets + +### Failed to find where HEAD diverged from master + +You may sometimes see the following error when trying to generate changeset on your feature branch. + +``` +❯ pnpm changeset +πŸ¦‹ error Error: Failed to find where HEAD diverged from master. Does master exist? +``` + +**How to fix:** + +1. First you need to checkout to master branch. +`git checkout master` + +2. Then get the latest changes from upstream. +`git pull upstream master` + +3. Rebase the feature branch on master branch, and try generating changesets again. +`git checkout ` +`git rebase master` + +## Node + +### Dev Server Failures + +#### File watchers exceed error + +- Error: ENOSPC: System limit for number of file watchers reached +- Steps to resolve: + - Need to increase the amount of max_user_watches in system file. + - Use 'sudo nano /etc/sysctl.conf' to access the file. + - Then add 'fs.inotify.max_user_watches = 5242881' at the end of the file. + - Next save the file and exit. + - Finally use 'sudo sysctl -p' to apply changes. + +### Package Install Failures + +#### Global npm package install errors on Mac System + +```bash +npm i -g pnpm +``` + +A global npm package install such above via `npm` could result in the following stacktrace in Mac systems. + +```bash +npm ERR! code EACCES +npm ERR! syscall mkdir +npm ERR! path /usr/local/lib/node_modules/pnpm +npm ERR! errno -13 +npm ERR! Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/pnpm' +npm ERR! [Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/pnpm'] { +npm ERR! errno: -13, +npm ERR! code: 'EACCES', +npm ERR! syscall: 'mkdir', +npm ERR! path: '/usr/local/lib/node_modules/pnpm' +npm ERR! } +npm ERR! +npm ERR! The operation was rejected by your operating system. +npm ERR! It is likely you do not have the permissions to access this file as the current user +npm ERR! +npm ERR! If you believe this might be a permissions issue, please double-check the +npm ERR! permissions of the file and its containing directories, or try running +npm ERR! the command again as root/Administrator. +``` + +The reason for this is that your user does not have permissions to write to `/usr/local/lib/node_modules`. + +##### Possible Fixes + +1. Check who owns the errored path. + + ```bash + ls -la /usr/local/lib/node_modules + ``` + + If the above command shows the owner as `root` then you need to change it so that your user can modify the path. + +2. Checking your username if you do not know already. + + ```bash + whoami + ``` + +3. Change the owner of the path. Replace `ownerName` with the username you received after executing the above command. + + ```bash + sudo chown -R ownerName: /usr/local/lib/node_modules + ``` + +## Maven + +### Build Failures + +- If you face any out of memory build failures, make sure that you have set maven options to `set MAVEN_OPTS=-Xmx384M` +- For Maven v3.8 up, add below configuration to the `~/.m2/settings.xml` (Create a new file if the file exist) + +```xml + + + + wso2-nexus-public + external:http:* + http://maven.wso2.org/nexus/content/groups/wso2-public/ + false + + + wso2-nexus-release + external:http:* + http://maven.wso2.org/nexus/content/repositories/releases/ + false + + + wso2-nexus-snapshots + external:http:* + http://maven.wso2.org/nexus/content/repositories/snapshots/ + false + + + +``` diff --git a/docs/content/hotfix/README.md b/docs/content/hotfix/README.md new file mode 100644 index 00000000000..7951f6efb90 --- /dev/null +++ b/docs/content/hotfix/README.md @@ -0,0 +1,66 @@ +# Hotfixing Identity Apps + +This guide will walk you through preparing hotfixes for a specific Console, My Account or JSP applications (Authentication Portal, Recovery Portal and X509 Authentication Portal) version. + +## Preparing hotfixes through Github Action + +> # ⚠️ Temporarily disabled +> +> **Please note that the hotfix branch creation Github action is temporarily disabled due to several issues. We are proactively working on fixing them. Meanwhile, refer to the [guide for preparing hotfixes manually](#preparing-hotfixes-manually) for step by step instructions on manually creating hotfix releases yourself.** + +1. Create a hotfix branch for the application version to be hotfixed, using the [*πŸ”₯ Hotfix Branch Creation*](https://github.com/wso2/identity-apps/actions/workflows/hotfix-branch-creation.yml) Github Action. + +> ℹ️ **Note** +> +> If you don't have enough permission to trigger the workflow yet, feel free to ask someone with permission to trigger the workflow for you. + +2. Fetch the created hotfix branch to your local repo, and apply your changes. + +```bash +# if upstream repository is not set already +git remote add upstream https://github.com/wso2/identity-apps.git +git fetch upstream +``` + +3. Send a PR from your branch, targeting the created hotfix branch in upstream repository. + +> ℹ️ Note +> +> It's not needed to add changesets to a hotfix PR. + +4. Upon merging the PR, a hotfix release will be automatically triggered. You can find the created hotfix release in the [releases](https://github.com/wso2/identity-apps/releases). + +## Preparing hotfixes manually + +1. Create the hotfix branch for the specific application version in wso2/identity-apps repo, from the branch dropdown in Github UI. Make sure to follow the `hotfix-@` format, when creating the hotfix branch. If there is already a branch with the same name, you may use that existing branch for your hotfix. + +For example, if you are planning to send a hotfix for `@wso2is/console` v2.19.9 version, below is how you get to create the hotfix branch. + +![create-hotfix-branch](https://i.imgur.com/NhRRXax.png) + +2. Fetch the upstream repo branches to your local workspace, and create a new branch from the hotfix branch. This new branch is referred to as `hotfix_feature` throughout this document. + +```bash +git fetch upstream hotfix-@ +git checkout -b hotfix_feature hotfix-@ +``` + +3. Implement your changes in the created feature branch (`hotfix_feature`) and send a PR from your hotfix_feature_branch targeting the created hotfix branch. Get the PR approved and merged. + +4. Go to [releases](https://github.com/wso2/identity-apps/releases) and click on `Draft a new release`. + +![draft-a-new-release](https://i.imgur.com/LiACkDj.png) + +5. You will see the form to create a new release. Follow the steps below. + +- For the tag name, type in the new release tag of the hotfix to be released. Please follow the format `@-hotfix-` when specifying the new release tag. Click `Create new on publish`. + +![enter-tag-name](https://i.imgur.com/2hEUI5s.png) + +- Select the hotfix branch from the `target branch` dropdown + +- Click `Generate release notes` button to get a release description automatically generated. + +- Type in the same hotfix release tag you specified in the `Choose a tag` dropdown, in the `Release title` field as well. + +- Untick `Set as latest release` checkbox and click `Publish release`. diff --git a/docs/content/release/README.md b/docs/content/release/README.md new file mode 100644 index 00000000000..4e93f8a528c --- /dev/null +++ b/docs/content/release/README.md @@ -0,0 +1,58 @@ +# Release + +This repository uses [πŸ¦‹ Changesets](https://github.com/changesets/changesets) to manage releases. + +## Creating a release + +1. To create a release from your PR, switch to your feature branch, and execute the following command from the identity-apps root. + +> πŸ—’οΈ Note: +> +> Changeset identifies the changed packages by comparing your feature branch with the `master` branch. If these branches are not properly synced with remote, you'll some irrelevant packages listed under changed packages. Therefore, it is recommended to **rebase your feature branch on the up-to-date `master` branch before executing `pnpm changeset`**. + +```bash +# from the root of the project +pnpm changeset +``` + +2. This will open a prompt to select the packages that have changed. Select **the changed packages**, and press Enter. + +![changesets-001](../assets/images/develop/release/changesets-changed-packages-001.png) + +3. Then, it will open a prompt to select the type of change. Select the type of change and press `Enter`. + + - MAJOR version when you make incompatible API changes + - MINOR version when you add functionality in a backward compatible manner + - PATCH version when you make backward compatible bug fixes + +![changesets-002](../assets/images/develop/release/changesets-changed-packages-002.png) + +4. Lastly, it will open a prompt to enter a summary of the changes. Enter a summary and press `Enter`. (Additionally, if you want to have an editor view to enter a long summary with line breaks, press `Enter` without typing anything.) + +> πŸ—’οΈ Note +> +> Please enter a meaningful summary of the changes. This will be used in the changelog. + +![changesets-summary-001](../assets/images/develop/release/changesets-summary-001.png) + +5. Then commit the generated changeset file with the following commit message. + +```bash +Add changeset πŸ¦‹ +``` + +## Merging the autogenerated version bump PR. + +1. After your PR is merged, Changesets Github Action will version the packages that have changed and create a PR with the version bump. You can find the PR in the [pull requests](https://github.com/wso2/identity-apps/pulls?q=is%3Apr+is%3Aopen+%22%5BRelease%5D+%5BGitHub+Action%5D+Update+package+versions%22) tab. + +πŸ’‘ Sample PR title: `[Release] [GitHub Action] Update package versions.` + +2. Approve and merge the PR. + + > ⚠️ **Warning** + > + > Do not choose `squash and merge` option to merge the version bump PR. + +![changesets-autogen-pr-1](../assets/images/develop/release/changesets-autogen-pr-001.png) + +3. That's it! A release build will be automatically triggered after the version bump PR is merged. The changed apps and package artifacts will be released to GitHub and Nexus. diff --git a/docs/content/testing/README.md b/docs/content/testing/README.md new file mode 100644 index 00000000000..12df4a8dfa9 --- /dev/null +++ b/docs/content/testing/README.md @@ -0,0 +1,11 @@ +# Testing + +Follow this guide to learn about our testing strategies. + +## Static Tests + +Follow through [this guide](./STATIC_CODE_ANALYSIS.md) to set-up and understand the different static code analysis tools that are being used in the project. + +## Unit Tests + +Read the unit testing guide [here](UNIT_TESTING.md) diff --git a/docs/content/testing/STATIC_CODE_ANALYSIS.md b/docs/content/testing/STATIC_CODE_ANALYSIS.md new file mode 100644 index 00000000000..dae41cf21c1 --- /dev/null +++ b/docs/content/testing/STATIC_CODE_ANALYSIS.md @@ -0,0 +1,103 @@ +# Static Code Analysis + +## Linting + +We use [ESLint](https://eslint.org/) as the primary linting tool, and it's important that you adhere to the +defined ruleset in the configuration. + +Set up the ESLint plugin corresponding to the IDE/Code editor you are using. For more +information, follow the instructions [here](./DEVELOPER.md#setting-up-development-tools). + +Always keep an eye out for the inline warnings and errors given out by the plugin. + +### Running the linter + +Execute the following commands based on the requirement to analyze the code with ESLint. + +#### For the Entire Mono-repo + +```bash +# Run this from the root. +pnpm lint +``` + +#### For a specific module/app. + +##### Example: To run linter on Console + +```bash +cd apps/console +pnpm lint +``` + +or + +```bash +# From anywhere in the project. +pnpm nx run console:lint +``` + +##### Example: To run linter on React Components + +```bash +cd modules/react-components +pnpm lint +``` + +or + +```bash +# From anywhere in the project. +pnpm nx run react-components:lint +``` + +#### For a specific folder or a file. + +The script `lint:targeted` is meant to be used if you need to run the linter on a specific folder or file inside an app or a module. + +##### Example: To run linter on `features/applications` inside the Console + +```bash +cd apps/console +pnpm lint:targeted -- src/features/applications +``` + +### Auto-fixing Issues + +ESLint has the ability to [auto-fix](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) certain warnings and errors. + +This can be done using the **CLI** as well as via the IDE/Code Editor using the integrated ESLint Plugin. + +Execute the following commands to auto-fix possible issues using the **CLI**. + +#### Auto-fix issues in the entire Mono-repo + +```bash +# Run this from the root. +pnpm lint:autofix +``` + +#### Auto-fix issues in a specific module/app. + +##### Example: To fix issues in Core module + +```bash +cd modules/core +pnpm lint:autofix +``` + +#### Auto-fix issues in a specific folder or a file. + +##### Example: To fix issues in `api` directory inside the My Account + +```bash +cd apps/myaccount +pnpm lint:targeted -- src/api --fix +``` + +##### Example: To fix issues in `url-utils.ts` file inside the Core module. + +```bash +cd modules/core +pnpm lint:targeted -- src/utils/url-utils.ts --fix +``` diff --git a/docs/content/testing/UNIT_TESTING.md b/docs/content/testing/UNIT_TESTING.md new file mode 100644 index 00000000000..eee098a9d67 --- /dev/null +++ b/docs/content/testing/UNIT_TESTING.md @@ -0,0 +1,226 @@ +# Unit Tests + +Product Unit tests have been implemented using [Jest](https://jestjs.io/) along with [React Testing Library](https://testing-library.com/docs/react-testing-library/intro). +Make sure to write unit tests when you are working on new or existing features. + +## Structuring Tests + +Tests should be properly structured. Checkout the following examples. + +### Example + +Let's say that you have a component called `applications-list.tsx` at the root of `features/admin.applications.v1/components` that needs to be tested. + +#### Steps + +1. Create a `__tests__` under `features/admin.applications.v1/components`. +2. Create a file with the pattern `.test.` inside the `__tests__` folder. (In this case `applications-list.test.tsx`). + +#### Folder Structure + +```bash +features +└── admin.applications.v1 + β”œβ”€β”€ __tests__ + β”œβ”€β”€ components + | └── __tests__ + | | └── applications-list.test.tsx + | └── applications-list.tsx + └── applications-page.tsx +``` + +## Writing Tests + +Writing unit tests for every component that you develop is mandatory. +Take a look at the following example test case where we test if the component that we are writing mounts and renders as expected. + +⚠️ There are several ESLint plugins ([eslint-plugin-jest-dom][eslint-plugin-jest-dom], [eslint-plugin-testing-library][eslint-plugin-testing-library]) configured to make sure that developers follow the best practices. +Please configure ESLint in your coding environment if you haven't already done so by [following this guide][eslint-ide-plugin-setup-guide]. + +```tsx +import { render, screen } from "@unit-testing"; +import React from "react"; +import "@testing-library/jest-dom"; +import { ApplicationList } from "../../../components/applications"; + +describe("Test if the Application List is working as expected", () => { + it(" renders without exploding", () => { + render(); + expect(screen.getByTestId("application-list")).toBeInTheDocument(); + }); +}); +``` + +:bulb: Note that we use a custom `render` function here rather than from the `@testing-library/react` module. The reason for +this is that we need to wrap our components with providers like `Redux` etc. And doing this in every test case is a +tedious task. So we have written a custom renderer following the guide in +[official documentation][react-testing-library-custom-renderer]. `@unit-testing` is a webpack alias added to avoid importing this function using relative paths. + +### Identifying Elements in DOM + +As a practice we use `data-componentid` inorder to make our tests resilient to change. +Use the [getByTestId](https://testing-library.com/docs/queries/bytestid/) method to access with the component id. + +#### Example: Assert on components with `getByTestId`. + +```typescript jsx +expect(component.getByTestId("getting-started-page-layout")).toBeInTheDocument(); +``` + +:no_entry: Never use any other selectors such as `id`, `classes`, etc. to identify the elements. + +If there are no `data-componentid` present in the element, extend the [IdentifiableComponentInterface](../../modules/core/src/models/core.ts) from `@wso2is/core/models` to inherit the attribute. + +#### Example: Inheriting `data-componentid` + +```typescript jsx + +export interface SampleComponentInterface extends IdentifiableComponentInterface { + + // Other attributes +} + +export const SampleComponent: FunctionComponent = ( + props: SampleComponentInterface +): ReactElement => { + + const { + ["data-componentid"]: componentId, + // Other props + } = props; +} + +``` + +:warning: Some components might have the `data-testid` already implemented using the [TestableComponentInterface](../../modules/core/src/models/core.ts). +This interface and the data attribute since has been **deprecated**. Hence, :boom: **DO NOT USE IT** in new components. Refactor the usage where ever possible. + +### Testing API Calls + +We have used [msw][msw] to mock the APIs. The mock implementation root for the core can be found at `/test-configs/__mocks__/server`. +If you need to add further endpoint mocks, add them in the `handlers.ts`. + +#### Extended Features + +The mock implementation root for the extensions can be found at `/src/extensions/test-configs/__mocks__/server`. +Add any extended API endpoint mocks in the `handlers.ts`. + +πŸ’‘Checkout these references if you want to learn more about API mocking. + +### Snapshot Testing + +Snapshot tests are a very useful tool whenever you want to make sure your UI does not change unexpectedly. + +A typical snapshot test case renders a UI component, takes a snapshot, then compares it to a reference snapshot file stored alongside the test. The test will fail if the two snapshots do not match: either the change is unexpected, or the reference snapshot needs to be updated to the new version of the UI component. + +```tsx +import { render } from "@unit-testing"; +import React from "react"; +import "@testing-library/jest-dom"; +import { ApplicationList } from "../../../components/applications"; + +it(" matches snapshot", () => { + const { container } = render(); + + expect(container).toMatchSnapshot(); +}); +``` + +For further reference, checkout the official documentation of [React Testing Library][react-testing-library]. + +## Running the test suite + +Following are few of the useful commands that you can use to run the existing unit tests for modules. + +### Run the full test suite + +```bash +# From project root. +pnpm test +``` + +#### Run the full test suite in watch mode + +```bash +# From project root. +pnpm test:watch +``` + +### Run Tests for a specific test file + +```bash +# From features root +npx jest features/admin.applications.v1/__tests__/applications-page.test.tsx +``` + +### Run Tests for a specific test file in watch mode + +```bash +# From features root +npx jest --watch features/admin.applications.v1/__tests__/applications-page.test.tsx +``` + +### Run Tests for an individual module + +#### Using Lerna + +```bash +# From anywhere inside the project. +pnpm nx run forms:test +``` + +#### From the project root. + +```bash +# Run tests for modules. +pnpm test:unit:modules +``` + +```bash +# Run tests for apps. +pnpm test:unit:apps +``` + +```bash +# Run tests for specific module. (Replace with something like `@wso2is/core` or `@wso2is/myaccount`) +pnpm test:unit: +``` + +#### From inside respective module. + +```bash +# From inside component ex: apps/console. Use `pnpm test:watch for watch mode. +pnpm test +``` + +## Code Coverage + +### Generate coverage report + +```bash +# From the root of the project. +pnpm test:unit:coverage +``` + +## References + +- Common + - [Common mistakes with React Testing Library][common-mistakes-with-react-testing-library] Blog by Kent C. Dodds + - [Fix the "not wrapped in act(...)" warning][fix-the-not-wrapped-in-act-warning] Blog by Kent C. Dodds +- API Mocking + - [Stop mocking fetch][stop-mocking-fetch] Blog by Kent C. Dodds + - [Use Mock Service Worker and Test Like a User][use-mock-Service-worker] Video Tutorial by Leigh Halliday + + +[eslint-ide-plugin-setup-guide]: ../SET_UP_DEV_ENVIRONMENT.md#eslint-ide-plugin + + +[react-testing-library]: https://testing-library.com/docs/ +[react-testing-library-custom-renderer]: https://testing-library.com/docs/react-testing-library/setup#custom-render +[common-mistakes-with-react-testing-library]: https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#using-wrapper-as-the-variable-name-for-the-return-value-from-render +[stop-mocking-fetch]: https://kentcdodds.com/blog/stop-mocking-fetch +[fix-the-not-wrapped-in-act-warning]: https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning +[eslint-plugin-jest-dom]: https://github.com/testing-library/eslint-plugin-jest-dom +[eslint-plugin-testing-library]: https://github.com/testing-library/eslint-plugin-testing-library +[msw]: https://mswjs.io/ +[use-mock-Service-worker]: https://www.youtube.com/watch?v=v77fjkKQTH0 diff --git a/docs/content/write-code/CODE_QUALITY.md b/docs/content/write-code/CODE_QUALITY.md new file mode 100644 index 00000000000..3e44795eb79 --- /dev/null +++ b/docs/content/write-code/CODE_QUALITY.md @@ -0,0 +1,27 @@ +# Ensuring Code Quality + +Make sure that you set up the required developer tools as mentioned [here](../SET_UP_DEV_ENVIRONMENT.md#setting-up-development-tools) before starting off with the coding. + +## Typescript Doc Comments + +We follow [TSDoc](https://tsdoc.org/) comments when writing doc comments. Also we use [eslint-plugin-tsdoc](https://tsdoc.org/pages/packages/eslint-plugin-tsdoc/) ESLint plugin to ensure the validity of the TS doc comments. Please make sure that you adhere to the specified rules. + +### Examples +TSDoc comment for a function that accepts two numbers and returns the average of those numbers. +>Note: The type of the parameters is not specified in TSDoc, because it is already expressed by the TypeScript language. +```ts +/** + * Returns the average of two numbers. + * + * @param x - The first input number + * @param y - The second input number + * @returns The arithmetic mean of `x` and `y` + * + */ +const getAverage = (x: number, y: number): number => { + return (x + y) / 2.0; +} + +``` + +Refer [TSDoc](https://tsdoc.org/) for more information. \ No newline at end of file diff --git a/docs/content/write-code/DATA_FETCHING.md b/docs/content/write-code/DATA_FETCHING.md new file mode 100644 index 00000000000..5613f20fa3a --- /dev/null +++ b/docs/content/write-code/DATA_FETCHING.md @@ -0,0 +1,171 @@ +# Data Fetching + +## Overview + +Recently we migrated to [SWR](https://swr.vercel.app/) which is based on the [HTTP RFC 5861](https://datatracker.ietf.org/doc/html/rfc5861) spec. + +With SWR, components will get a stream of data updates constantly and automatically. +And the UI will be always fast and reactive. + +> πŸ’‘ IMPORTANT: Any new features or major refactorings should adopt the SWR strategy when invoking external data sources. + +## API + +### useRequest + +`useRequest` is a custom hook which wraps the [`useSWR`](https://swr.vercel.app/docs/options) hook provided by the library. + +> πŸ’‘ The main reason for writing a wrapper is to move the `fetcher` to a common place for easy maintainance. And also, we are using an `Axios Instance` provided by the [@asgardeo/auth-react](https://github.com/asgardeo/asgardeo-auth-react-sdk#httprequest) which uses request objects to invoke APIs though Axios, hence additional boilerplate code should be written to plug this as the fetcher. By writing a custom hook, we can abstract out that additional complexity from the usage. + +```ts +const requestConfig = { + headers: { + "Accept": "application/json", + "Content-Type": "application/json" + }, + method: HttpMethods.GET, + params: { + filter, + limit, + offset + }, + url: store.getState().config.endpoints.applications +}; + +const { data, error } = useRequest(requestConfig); +``` + +## Examples + +### Before + +### API Function + +```ts +const getApplications = () => { + const requestConfig = { + headers: { + "Accept": "application/json", + "Access-Control-Allow-Origin": store.getState().config.deployment.clientHost, + "Content-Type": "application/json" + }, + method: HttpMethods.GET, + params: { + filter, + limit, + offset + }, + url: store.getState().config.endpoints.applications + }; + + return httpClient(requestConfig) + .then((response) => { + if (response.status !== 200) { + return Promise.reject(new Error("Failed to get application list from: ")); + } + + return Promise.resolve(response.data as ApplicationListInterface); + }).catch((error) => { + return Promise.reject(error); + }); +}; +``` + +### Component + +```tsx + +const ApplicationsList = () => { + + const [ applicationsList, setApplicationsList ] = useState([]); + const [ isLoading, setIsLoading ] = useState(false); + const [ error, setError ] = useState(null); + + useEffect(() => { + setIsLoading(true); + + getApplications() + .then((response) => { + setApplicationsList(response); + }) + .catch((error) => { + setError(error); + }) + .finally(() => { + setIsLoading(false); + }); + }, []); + + if (isLoading) { + return
Loading...
; + } + + return ( +
+ { + data.map((item) => { + // render items + }) + } +
+ ) +}; + +``` + +### After + +### Custom Hook + +```ts +export function useApplicationList(): { + error: AxiosError; + isLoading: boolean; + applicationsList: ApplicationListInterface; +} { + const requestConfig = { + headers: { + "Accept": "application/json", + "Content-Type": "application/json" + }, + method: HttpMethods.GET, + url: store.getState().config.endpoints.applications + }; + + const { data, error } = useRequest(requestConfig); + + return { + data, + error, + isLoading: !error && !data + }; +} +``` + +### Component + +```tsx +const ApplicationsList = () => { + + const { + data, + isLoading, + error + } = useApplicationList(); + + if (isLoading) { + return
Loading...
; + } + + return ( +
+ { + data.map((item) => { + // render items + }) + } +
+ ) +}; + +``` diff --git a/docs/content/write-code/DEVELOPING_REACT_CODE.md b/docs/content/write-code/DEVELOPING_REACT_CODE.md new file mode 100644 index 00000000000..b4fe4f9ff5e --- /dev/null +++ b/docs/content/write-code/DEVELOPING_REACT_CODE.md @@ -0,0 +1,97 @@ +# Developing React Code + +## Writing Components + +### Ordering + +When writing React components, follow the below ordering pattern for better readability. + +```jsx + +export const Component: FunctionComponent = ( + props: ComponentPropsInterface +): ReactElement => { + + // 1. Prop restructuring + const { + children, + "data-componentid": componentId + } = props; + + // 2. Refs + const ref: MutableRefObject = useRef(null); + + // 3. Other custom & third party hooks. + const { t } = useTranslation(); + const dispatch = useDispatch(); + const { getLink } = useDocumentation(); + const { isGreaterThanComputerViewport } = useMediaContext(); + + // 4. Redux selectors + const theme: string = useSelector((state: AppState) => state.config.ui.theme?.name); + + // 5. State declarations. + const [ isAvailable, setIsAvailable ] = useState(false); + + // 6. Memo hooks + const isReadOnly = useMemo(() => { + // do something + } , []); + + // 7. useEffect Hooks with empty dependency array. + useEffect(() => { + // do something + }, []); + + // 8. useEffect Hooks with non-empty dependency array. + useEffect(() => { + // do something + }, [ isReadOnly ]); + + // 9. Functions. + const noop = (): string | null => { + return null; + }; + + // 10. Return of the function. + return ( +
My Awesome Component.
+ ) +}; +``` + +### Conditional Rendering + +The return from an component should always be a `ReactElement` or `null`. Always be careful when doing +[conditional rendering][react-conditional-rendering] with `&&` operator. If the component returns undefined, React +will break the rendering as of now. + +:white_check_mark: Do + +```typescript +export const SignOnMethods: FunctionComponent = ( + props: SignOnMethodsPropsInterface +): ReactElement => { + + ... + + return ( + someCondition + ? + : null + ); +} +``` + +:x: Don't + +```typescript +export const SignOnMethods: FunctionComponent = ( + props: SignOnMethodsPropsInterface +): ReactElement => { + + ... + + return someCondition && ; +} +``` diff --git a/docs/content/write-code/ENSURING_GOOD_UX.md b/docs/content/write-code/ENSURING_GOOD_UX.md new file mode 100644 index 00000000000..1538f7be1c2 --- /dev/null +++ b/docs/content/write-code/ENSURING_GOOD_UX.md @@ -0,0 +1,32 @@ +# Ensuring a good UX + +We follow certain development practices to ensure the applications provide a good user experience. Please make sure you adhere to the following guidelines. + +## Disable submit buttons until the submission is complete + +When the submit button in a form is clicked, usually an API call is sent to persist the changes. However, during the API call, if the submit button remains enabled, then the users will be able to click on it as many times as they want, which will result in multiple API calls. + +To avoid this, disable the submit button until the API call is complete. While disabling the button, to provide a better UX, it is also advisable top show a loading indicator in the button. + +```TypeScript +const SampleComponent = () => { + const [isSubmitting, setIsSubmitting] = useState(false); + + const apiCall = (): void { + setIsSubmitting(true); + + callAPI().then((response) => { + // handle response + }).error((error)=>{ + // handle error + }).finally(()=>{ + setIsSubmitting(false); + }); + } + + return ( +
+ Submit +
+ ) +``` diff --git a/docs/content/write-code/FORMATTING.md b/docs/content/write-code/FORMATTING.md new file mode 100644 index 00000000000..232645afa80 --- /dev/null +++ b/docs/content/write-code/FORMATTING.md @@ -0,0 +1,31 @@ +# Formatting + +We have already added few [ESLint rules](../../.eslintrc.js) to ensure consistent formatting across the entire codebase. +Please make sure you adhere to the specified rules and also follow the following set of common formatting practices while developing components. + +## Ternary Expressions + +Typescript allows operands of ternary expressions to be separated by newlines, which can improve the readability of your program. + +:white_check_mark: Do + +**Single Line** + +```typescript +foo > bar ? value1 : value1 +``` + +**Multiline** + +```typescript +foo > bar + ? value1 + : value1 +``` + +:x: Don't + +```typescript +foo > bar ? value1 + : value1 +``` diff --git a/docs/content/write-code/PERFORMANCE.md b/docs/content/write-code/PERFORMANCE.md new file mode 100644 index 00000000000..02347281a41 --- /dev/null +++ b/docs/content/write-code/PERFORMANCE.md @@ -0,0 +1,173 @@ +# Ensuring performance + +We care a lot about maintaining the performance of our applications. Hence, it is your duty to make sure that the code you +write follows the standards and does not diminish the existing performance levels. + +In-order to ensure this, please follow the following steps while making your contributions. + +## Use code splitting + +Webpack and React supports code splitting out of the box. Try to always leverage these features to reduce bundle size and performance. + +- Read more about Webpack Code Splitting [here](https://webpack.js.org/guides/code-splitting/). +- Read more about React Code Splitting [here](https://reactjs.org/docs/code-splitting.html). + +## Take advantage of tree shaking + +Webpack's treeshaking is a really awesome feature to get rid of dead code. Always try to take advantage of that. + +:white_check_mark: Do + +```typescript +import get from "lodash-es"; +``` + +:x: Don't + +```typescript +import * as _ from "lodash-es"; +``` + +## Don't write redundant code + +Unnecessary code will bulk up the bundle without you even realizing. Always try to avoid scenarios like the following. + +#### Redundant optional chain + +:x: Don't + +```typescript +if (user?.email && user?.email?.home) { + ... +} +``` + +When the above block is transpiled, it is converted to the following. + +```javascript +if ((user === null || user === void 0 ? void 0 : user.email) && ((_a = user === null || user === void 0 ? void 0 : user.email) === null || _a === void 0 ? void 0 : _a.home)) { +} +``` + +Notice that the first null check is redundant. It can be re-written as follows. + +:white_check_mark: Do + +```typescript +if (user?.email?.home) { + ... +} +``` + +Following is the transpiled version of the above code block. The footprint is significantly less. + +```javascript +if ((_a = user === null || user === void 0 ? void 0 : user.email) === null || _a === void 0 ? void 0 : _a.home) { +} +``` + +:bulb: Always remember, more characters means more bytes. + +### Carefully adding new dependencies + +Dependencies carry a heavy wait and contribute in a significant amount for the overall bundle size. So, when adding a new +library to the project try to answer the following questions. + +Q1. Is the library absolutely required? + +In some cases, you will be able to manually write the code rather than using a library. But keep in mind not to re-invent the wheel as well. + +Q2. Is the library actively maintained? + +Go to the NPM registry and GitHub repository of the prospective library and check for stats like downloads, stars, last published dates, +issues etc. This will give you an understanding on the state of the library. + +:bulb: Never add a dependency that is not actively maintained. + +Q3. Have you considered other libraries? + +Do a benchmark and test other related libraries. + +Q4. What is the size of the library? + +You can easily check the size of the library by using an online tool like [Bundlephobia](https://bundlephobia.com/). + +![bundlephobia-sample](../assets/bundlephobia-sample.jpg) + +Q5. What are the dependencies used inside the library? + +Some library developers include relatively large dependencies like [`lodash`](https://lodash.com/), [`moment`](https://momentjs.com/) etc. in their libraries as dependencies. +Adding these will result in increase bundle sizes. Check in the `package.json` for the dependencies used inside the library. + +Q6. What is the footprint introduced by the newly added library? + +We have added a script to analyze the bundle sizes of our react applications using [Webpack Bundle Analyzer Plugin](https://www.npmjs.com/package/webpack-bundle-analyzer). + +Use the following command to examine the footprint introduced by the prospective library. + +#### Analyze for Console + +:bulb: The analyzer will open in http://localhost:8889 + +1. Navigate to `console` application directory: + +```shell +cd apps/console +``` + +2. Edit the `.env.local` file to enable the analyzer: + +``` +ENABLE_ANALYZER=true +``` + +3. Build Application: + +```shell +pnpm build +``` + +#### Analyze for My Account + +:bulb: The analyzer will open in http://localhost:8888 + +1. Navigate to `myaccount` application directory: + +```shell +cd apps/myaccount +``` + +2. Edit the `.env.local` file to enable the analyzer: + +``` +ENABLE_ANALYZER=true +``` + +3. Build Application: + +```shell +pnpm build +``` + +Following these steps will enable the analyzer and result in a view that would look like the following. + +![webpack-analyzer-sample](../assets/webpack-analyzer-sample.jpg) + +### Optimize static assets + +When adding new assets, always check the existing once in the theme and only proceed if the desired asset is not available. + +#### Adding Images + +When adding images, always try to add SVGs which are optimized for web. + +#### Prepend unused arguments with `_` + +There might be times when you have to leave an argument unused in a function, especially when writing extension configs. This will prompt the linter to throw a warning. +To avoid this, always prepend the unused argument with `_`. + +```TypeScript +const printAge(_name: string, age: number){ + console.log(age); +} +``` diff --git a/docs/content/write-code/README.md b/docs/content/write-code/README.md new file mode 100644 index 00000000000..a19167126aa --- /dev/null +++ b/docs/content/write-code/README.md @@ -0,0 +1,11 @@ +# Write Code + +Go though the following guides to learn about our coding style and tips on writing maintainable code. + +- [Ensuring Code Quality](./CODE_QUALITY.md) +- [Developing React Code](./DEVELOPING_REACT_CODE.md) +- [Data Fetching](./DATA_FETCHING.md) +- [Formatting](./FORMATTING.md) +- [Ensuring performance](./ENSURING_PERFORMANCE.md) +- [Ensuring a good UX](./ENSURING_GOOD_UX.md) +- [Styling](./STYLING.md) diff --git a/docs/content/write-code/STYLING.md b/docs/content/write-code/STYLING.md new file mode 100644 index 00000000000..8150322699d --- /dev/null +++ b/docs/content/write-code/STYLING.md @@ -0,0 +1,37 @@ +# Styling + +## Forms +Always use the new [@wso2is/form](../../modules/form) module when developing forms. + +Read the documentation [here](../FORMS.md). + +### Sectioned Form + +When styling the forms, avoid using any ad-hoc Headings, Dividers etc. +If you wish to write a form with sub-sections, use the [FormSection](../../modules/react-components/src/components/forms/form-section.tsx) component. +It will add a divider and a Heading with a constant emphasis level. + +#### Usage + +```tsx + + + + +``` + +#### Output + +![form-section](../assets/forms-section.png) + +[react-conditional-rendering]: https://reactjs.org/docs/conditional-rendering.html diff --git a/docs/content/write-code/branding/ADD_TEXT_CUSTOMIZATION_TO_NEW_INTERFACES.md b/docs/content/write-code/branding/ADD_TEXT_CUSTOMIZATION_TO_NEW_INTERFACES.md new file mode 100644 index 00000000000..3a14c9287c9 --- /dev/null +++ b/docs/content/write-code/branding/ADD_TEXT_CUSTOMIZATION_TO_NEW_INTERFACES.md @@ -0,0 +1,80 @@ +# How to add text customization to new interfaces + +Here are the steps to add text customization in the interfaces: + +1. **List Interfaces and Corresponding JSP Files:** + +2. **Access and List Relevant i18n Tags:** + - For each string that you plan to change, identify the corresponding i18n tag in the `Resources.properties` file. + - Authentication Portal: + - Language File: `identity-apps-core/apps/authentication-portal/src/main/resources/org/wso2/carbon/identity/application/authentication/endpoint/i18n/Resources.properties` + - Recovery Portal: + - Language File: `identity-apps-core/apps/recovery-portal/src/main/resources/org/wso2/carbon/identity/mgt/recovery/endpoint/i18n/Resources.properties` + + +3. **Move Strings to Top of File and Add Metadata:** + - Move the identified strings to the top of the file. + - Add metadata to each string: + ``` + # + # EDITABLE=true, SCREEN="sign-up", MULTI_LINE=true + sign.up.heading=Sign Up + # EDITABLE=true, SCREEN="sign-up", MULTI_LINE=true + sign.up.button=Sign Up + # + ``` + - The `EDITABLE` metadata is used to identify the strings that can be customized. + - The `SCREEN` metadata is used to identify the screen where the string is used. + - The `MULTI_LINE` metadata is used to identify the strings that support multi-line text. + - Change the key to the following format: `screen-name.field-name` (e.g., `password.reset.heading`). + +4. **Update Resource Language Files:** + - Add the updated strings to other resource language files as well. + +5. **Update i18n in Namespaces File:** + - Update the `modules/i18n/src/models/namespaces/branding-ns.ts` file with the relevant i18n keys for the screens and form fields. + - It should be in the following format: + ``` + export const consoleNS = { + // ... + brandingCustomText: { + // ... + form: { + // ... + fields: { + // ... + passwordReset.heading: { + hint: String; + }, + // ... + }, + // ... + }, + // ... + }, + // ... + }; + ``` + +6. **Create Fragment Component:** + - Create a fragment component in `apps/console/src/features/branding/components/preview/sign-in-box/fragments`. + - Name the fragment component based on the screen (e.g., `password-reset-fragment.tsx`). + +7. **Add Fragment Component to SignInBox:** + - Add the created fragment component to the `apps/console/src/features/branding/components/preview/sign-in-box/sign-in-box.tsx` file. + +8. **Update Preview Fragment Component:** + - Update the preview fragment component with the necessary i18n keys. + +9. **Add New File to Branding Preferences JSP:** + - Add the new file required for text customization to the `includes/branding-preferences.jsp` file in both the recovery portal and authentication portal. + +10. **Add Localization in JSP Files:** + - Add localization in JSP files using `<%=i18n(recoveryResourceBundle, customText, "password.reset.heading")%>`. + - Ensure to add multi-line support if necessary by setting the `MULTI_LINE` metadata to `true` and adding the `new-line-support` helper class to the component. + +11. **A sample PR:** + - https://github.com/wso2/identity-apps/pull/5394 + +By following these steps, you can effectively add text customization to the new interfaces. + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000000..9837fe44a3b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,25 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: "Docs | WSO2 Identity Server Apps" + text: "Developer documentation for the WSO2 Identity Server Apps codebase" + tagline: My great project tagline + actions: + - theme: brand + text: Markdown Examples + link: /markdown-examples + - theme: alt + text: API Examples + link: /api-examples + +features: + - title: Feature A + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit + - title: Feature B + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit + - title: Feature C + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit +--- + diff --git a/docs/markdown-examples.md b/docs/markdown-examples.md new file mode 100644 index 00000000000..f9258a55036 --- /dev/null +++ b/docs/markdown-examples.md @@ -0,0 +1,85 @@ +# Markdown Extension Examples + +This page demonstrates some of the built-in markdown extensions provided by VitePress. + +## Syntax Highlighting + +VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting: + +**Input** + +````md +```js{4} +export default { + data () { + return { + msg: 'Highlighted!' + } + } +} +``` +```` + +**Output** + +```js{4} +export default { + data () { + return { + msg: 'Highlighted!' + } + } +} +``` + +## Custom Containers + +**Input** + +```md +::: info +This is an info box. +::: + +::: tip +This is a tip. +::: + +::: warning +This is a warning. +::: + +::: danger +This is a dangerous warning. +::: + +::: details +This is a details block. +::: +``` + +**Output** + +::: info +This is an info box. +::: + +::: tip +This is a tip. +::: + +::: warning +This is a warning. +::: + +::: danger +This is a dangerous warning. +::: + +::: details +This is a details block. +::: + +## More + +Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown). diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 00000000000..486a36517db --- /dev/null +++ b/docs/package.json @@ -0,0 +1,40 @@ +{ + "private": true, + "name": "@wso2is/identity-apps-docs", + "version": "0.0.0", + "description": "Developer documentation for the WSO2 Identity Server Apps codebase", + "type": "module", + "author": "WSO2", + "license": "Apache-2.0", + "files": [ + ".vitepress/dist" + ], + "homepage": "https://github.com/wso2/identity-apps/tree/main/docs#readme", + "bugs": { + "url": "https://github.com/wso2/identity-apps/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/wso2/identity-apps", + "directory": "docs" + }, + "keywords": [ + "wso2", + "identity-server", + "identity-apps", + "developer-docs", + "docs" + ], + "scripts": { + "docs:dev": "vitepress dev", + "docs:build": "vitepress build", + "docs:preview": "vitepress preview" + }, + "devDependencies": { + "vitepress": "^1.3.0", + "vue": "^3.4.31" + }, + "publishConfig": { + "access": "restricted" + } +} \ No newline at end of file