Upgrade to Snowpack 3 (#839)
1
.github/pull_request_template.md
vendored
|
@ -25,7 +25,6 @@ new functionality can follow them, such as QE or documentation.
|
|||
- [ ] Help has been implemented
|
||||
- [ ] axe report has been run and resulting a11y issues have been resolved
|
||||
- [ ] Unit tests have been created/updated
|
||||
- [ ] Formatting has been performed via prettier/eslint
|
||||
|
||||
## Additional Notes
|
||||
<!--
|
||||
|
|
8
.gitignore
vendored
|
@ -30,9 +30,6 @@ coverage
|
|||
# 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
|
||||
|
||||
|
@ -127,9 +124,8 @@ sketch
|
|||
# End of https://www.gitignore.io/api/node,react
|
||||
|
||||
# snowpack
|
||||
web_modules/
|
||||
.snowpack
|
||||
build/
|
||||
public/assets/
|
||||
|
||||
# server-install
|
||||
server/
|
||||
|
@ -140,6 +136,6 @@ server/
|
|||
|
||||
# Cypress #
|
||||
###########
|
||||
**/assets
|
||||
/assets
|
||||
**/cypress.env.json
|
||||
cypress/downloads/
|
||||
|
|
29
Gruntfile.js
|
@ -1,29 +0,0 @@
|
|||
const path = require("path");
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.loadNpmTasks("grunt-contrib-copy");
|
||||
|
||||
grunt.initConfig({
|
||||
// …
|
||||
copy: {
|
||||
main: {
|
||||
cwd: "./node_modules/@patternfly/patternfly/assets/",
|
||||
src: ["**/*", '!**/fontawesome/**'],
|
||||
dest: "public/assets/",
|
||||
expand: true,
|
||||
},
|
||||
sso: {
|
||||
expand: true,
|
||||
cwd: "./public/",
|
||||
src: "rh-sso-*",
|
||||
dest: "public",
|
||||
rename: function (dest, matchedSrcPath) {
|
||||
return path.join(dest, matchedSrcPath.substring("rh-sso-".length));
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
grunt.registerTask("default", ["copy:main"]);
|
||||
grunt.registerTask("switch-rh-sso", ["copy:sso"]);
|
||||
};
|
60
README.md
|
@ -1,7 +1,7 @@
|
|||
# Keycloak Admin Console V2
|
||||
This project is the next generation of the Keycloak Administration Console. It is written with React and [PatternFly 4][1].
|
||||
|
||||
### Development Instructions
|
||||
## Development Instructions
|
||||
|
||||
For development on this project you will need a running Keycloak server listening on port 8180.
|
||||
|
||||
|
@ -27,7 +27,7 @@ For development on this project you will need a running Keycloak server listenin
|
|||
$> npm run start
|
||||
```
|
||||
|
||||
### Build and run through Docker
|
||||
## Build and run through Docker
|
||||
git checkout git@github.com:keycloak/keycloak-admin-ui.git
|
||||
cd keycloak-admin-ui
|
||||
docker-compose build
|
||||
|
@ -39,29 +39,51 @@ If your Keycloak instance is not on `localhost:8180`, create a file `.env` with
|
|||
|
||||
KEYCLOAK_ENDPOINT=https:\/\/remoteinstance.keycloak.com
|
||||
|
||||
### Additionally there are some nice scripts to format and lint
|
||||
|
||||
```bash
|
||||
$> npm run lint
|
||||
```
|
||||
|
||||
To switch to a RH-SSO themed version of this console you can run:
|
||||
|
||||
```bash
|
||||
$> npx grunt switch-rh-sso
|
||||
```
|
||||
|
||||
To switch back just do a `git checkout public`
|
||||
|
||||
## Building as a Keycloak theme
|
||||
|
||||
If you want to build the application using Maven and produce a JAR that can be installed directly into Keycloak, check out the [Keycloak theme documentation](./keycloak-theme/README.md).
|
||||
|
||||
# Keycloak UI Test Suite in Cypress
|
||||
## Linting
|
||||
|
||||
Every time you create a commit it should be automatically linted and formatted for you. It is also possible to trigger the linting manually:
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
```
|
||||
|
||||
## Theming
|
||||
|
||||
It's possible to theme the Admin UI interface, this is useful if you want to apply your own branding so that the product looks familiar to your users. The Admin UI comes with two built-in themes called `keycloak` and `rh-sso`, by default the `keycloak` theme will be used when building the application.
|
||||
|
||||
This behavior can be changed by passing in a `THEME_NAME` environment variable, for example if wanted to build the application using the `rh-sso` theme we can do the following:
|
||||
|
||||
```bash
|
||||
THEME_NAME=rh-sso npm run build
|
||||
```
|
||||
|
||||
And likewise if we wanted to start a development server with this theme:
|
||||
|
||||
```
|
||||
THEME_NAME=rh-sso npm run start
|
||||
```
|
||||
|
||||
To make it simpler to build the `rh-sso` theme there are some shorthand NPM scripts available that you can run instead:
|
||||
|
||||
```bash
|
||||
# Run a production build with the 'rh-sso' theme
|
||||
npm run build:rh-sso
|
||||
|
||||
# Or for development
|
||||
npm run start:rh-sso
|
||||
```
|
||||
|
||||
### Creating your own theme
|
||||
|
||||
All themes are located in the `themes/` directory of the project, if you want to create a new theme you can create a new directory here and name it the same as your theme. Copy the files from the default theme here and customize them to your liking.
|
||||
|
||||
## Keycloak UI Test Suite in Cypress
|
||||
|
||||
This repository contains the UI tests for Keycloak developed with Cypress framework
|
||||
|
||||
## Run the test suite
|
||||
### Prerequisites
|
||||
* `Keycloak distribution` has to be [downloaded](https://www.keycloak.org/downloads) and started on 8081 port.
|
||||
**note**: the port in at the test suite side in [cypress.json](cypress.json) or at the Keycloak side, see [Keycloak Getting Started Guide](https://www.keycloak.org/docs/latest/getting_started/#starting-the-keycloak-server),
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"extends": "@snowpack/app-scripts-react/babel.config.json",
|
||||
"plugins": ["@babel/plugin-proposal-class-properties"]
|
||||
}
|
|
@ -124,11 +124,11 @@
|
|||
<regex>false</regex>
|
||||
<replacements>
|
||||
<replacement>
|
||||
<token>src="/_dist_</token>
|
||||
<value>src="${resourceUrl}/_dist_</value>
|
||||
<token>src="/</token>
|
||||
<value>src="${resourceUrl}/</value>
|
||||
</replacement>
|
||||
<replacement>
|
||||
<token>href="./</token>
|
||||
<token>href="/</token>
|
||||
<value>href="${resourceUrl}/</value>
|
||||
</replacement>
|
||||
<replacement>
|
||||
|
|
11597
package-lock.json
generated
16
package.json
|
@ -14,9 +14,10 @@
|
|||
},
|
||||
"scripts": {
|
||||
"build": "snowpack build",
|
||||
"build:rh-sso": "THEME_NAME=rh-sso snowpack build",
|
||||
"lint": "eslint \"./src/**/*.{js,jsx,mjs,ts,tsx}\"",
|
||||
"postinstall": "grunt",
|
||||
"start": "snowpack dev",
|
||||
"start:rh-sso": "THEME_NAME=rh-sso snowpack dev",
|
||||
"test": "jest",
|
||||
"start:cypress": "cypress open",
|
||||
"start:cypress-tests": "cypress run",
|
||||
|
@ -43,14 +44,11 @@
|
|||
"use-react-router-breadcrumbs": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.11.5",
|
||||
"@babel/preset-typescript": "^7.14.5",
|
||||
"@jest/types": "^27.0.6",
|
||||
"@snowpack/app-scripts-react": "^1.12.6",
|
||||
"@snowpack/plugin-postcss": "1.4.3",
|
||||
"@snowpack/plugin-postcss": "^1.4.3",
|
||||
"@snowpack/plugin-react-refresh": "^2.5.0",
|
||||
"@snowpack/plugin-typescript": "^1.2.1",
|
||||
"@snowpack/plugin-webpack": "3.0.0",
|
||||
"@storybook/addon-actions": "^6.3.4",
|
||||
"@storybook/addon-essentials": "^6.3.4",
|
||||
"@storybook/addon-links": "^6.3.4",
|
||||
|
@ -60,7 +58,6 @@
|
|||
"@storybook/react": "^6.3.4",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"@types/dot": "^1.1.4",
|
||||
"@types/file-saver": "^2.0.3",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/lodash": "^4.14.171",
|
||||
|
@ -70,7 +67,6 @@
|
|||
"@types/snowpack-env": "^2.3.4",
|
||||
"@typescript-eslint/eslint-plugin": "^4.28.1",
|
||||
"@typescript-eslint/parser": "^4.28.2",
|
||||
"babel-loader": "^8.1.0",
|
||||
"cypress": "7.7.0",
|
||||
"decompress": "^4.2.1",
|
||||
"decompress-targz": "^4.1.1",
|
||||
|
@ -78,17 +74,15 @@
|
|||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-react": "^7.24.0",
|
||||
"grunt": "^1.4.1",
|
||||
"grunt-contrib-copy": "^1.0.0",
|
||||
"http2-proxy": "^5.0.53",
|
||||
"husky": "^7.0.1",
|
||||
"jest": "^26.6.3",
|
||||
"lint-staged": "^11.0.1",
|
||||
"mutationobserver-shim": "^0.3.7",
|
||||
"postcss": "^8.3.5",
|
||||
"postcss-cli": "^8.3.1",
|
||||
"postcss-import": "^14.0.2",
|
||||
"prettier": "^2.3.2",
|
||||
"snowpack": "2.18.5",
|
||||
"snowpack": "^3.7.1",
|
||||
"ts-node": "^10.1.0",
|
||||
"typescript": "4.2.4"
|
||||
},
|
||||
|
|
Before Width: | Height: | Size: 464 B After Width: | Height: | Size: 464 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 369 B After Width: | Height: | Size: 369 B |
Before Width: | Height: | Size: 785 B After Width: | Height: | Size: 785 B |
|
@ -1,10 +0,0 @@
|
|||
@import "@patternfly/patternfly/patternfly.min.css";
|
||||
|
||||
.keycloak__pageheader_brand {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
body {
|
||||
--pf-global--primary-color--100: red;
|
||||
--pf-global--active-color--400: darkred;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
module.exports = {
|
||||
extends: "@snowpack/app-scripts-react",
|
||||
proxy: {
|
||||
"/auth/admin": "http://localhost:8180/auth/admin/",
|
||||
},
|
||||
plugins: [
|
||||
"@snowpack/plugin-postcss",
|
||||
"@snowpack/plugin-react-refresh",
|
||||
"@snowpack/plugin-typescript",
|
||||
],
|
||||
buildOptions: {
|
||||
baseUrl: "./",
|
||||
clean: true,
|
||||
},
|
||||
devOptions: {
|
||||
hmrErrorOverlay: false,
|
||||
},
|
||||
};
|
47
snowpack.config.mjs
Normal file
|
@ -0,0 +1,47 @@
|
|||
import proxy from "http2-proxy";
|
||||
import path from "node:path";
|
||||
|
||||
const themeName = process.env.THEME_NAME ?? "keycloak";
|
||||
const themePath = path.join("themes", themeName);
|
||||
|
||||
/** @type {import("snowpack").SnowpackUserConfig } */
|
||||
export default {
|
||||
mount: {
|
||||
[themePath]: { url: "/", static: true },
|
||||
public: { url: "/", static: true },
|
||||
src: { url: "/" },
|
||||
"node_modules/@patternfly/patternfly/assets/fonts": {
|
||||
url: "/assets/fonts",
|
||||
static: true,
|
||||
},
|
||||
"node_modules/@patternfly/patternfly/assets/pficon": {
|
||||
url: "/assets/pficon",
|
||||
static: true,
|
||||
},
|
||||
"node_modules/@patternfly/patternfly/assets/images": {
|
||||
url: "/assets/images",
|
||||
static: true,
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
"@snowpack/plugin-postcss",
|
||||
"@snowpack/plugin-react-refresh",
|
||||
"@snowpack/plugin-typescript",
|
||||
],
|
||||
routes: [
|
||||
{
|
||||
src: "/auth/admin/.*",
|
||||
dest: (req, res) =>
|
||||
proxy.web(req, res, {
|
||||
hostname: "localhost",
|
||||
port: 8180,
|
||||
}),
|
||||
},
|
||||
],
|
||||
optimize: {
|
||||
bundle: true,
|
||||
},
|
||||
devOptions: {
|
||||
hmrErrorOverlay: false,
|
||||
},
|
||||
};
|
|
@ -1,29 +1,45 @@
|
|||
import React from "react";
|
||||
import bitbucketIcon from "./bitbucket-brands.svg";
|
||||
import microsoftIcon from "./microsoft-brands.svg";
|
||||
import instagramIcon from "./instagram-brands.svg";
|
||||
import paypalIcon from "./paypal-brands.svg";
|
||||
import environment from "../../environment";
|
||||
|
||||
type FontAwesomeIconProps = {
|
||||
icon: "bitbucket" | "microsoft" | "instagram" | "paypal";
|
||||
};
|
||||
|
||||
export const FontAwesomeIcon = ({ icon }: FontAwesomeIconProps) => {
|
||||
const styles = { style: { height: "2em", width: "2em" } };
|
||||
switch (icon) {
|
||||
case "bitbucket":
|
||||
return (
|
||||
<img src={bitbucketIcon} {...styles} aria-label="bitbucket icon" />
|
||||
<img
|
||||
src={environment.resourceUrl + "./bitbucket-brands.svg"}
|
||||
{...styles}
|
||||
aria-label="bitbucket icon"
|
||||
/>
|
||||
);
|
||||
case "microsoft":
|
||||
return (
|
||||
<img src={microsoftIcon} {...styles} aria-label="microsoft icon" />
|
||||
<img
|
||||
src={environment.resourceUrl + "./microsoft-brands.svg"}
|
||||
{...styles}
|
||||
aria-label="microsoft icon"
|
||||
/>
|
||||
);
|
||||
case "instagram":
|
||||
return (
|
||||
<img src={instagramIcon} {...styles} aria-label="instagram icon" />
|
||||
<img
|
||||
src={environment.resourceUrl + "./instagram-brands.svg"}
|
||||
{...styles}
|
||||
aria-label="instagram icon"
|
||||
/>
|
||||
);
|
||||
case "paypal":
|
||||
return <img src={paypalIcon} {...styles} aria-label="paypal icon" />;
|
||||
return (
|
||||
<img
|
||||
src={environment.resourceUrl + "./paypal-brands.svg"}
|
||||
{...styles}
|
||||
aria-label="paypal icon"
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return <></>;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import "./index.css";
|
||||
import React, { StrictMode } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import i18n from "./i18n";
|
||||
|
|
Before Width: | Height: | Size: 627 B After Width: | Height: | Size: 627 B |
|
@ -3,8 +3,7 @@
|
|||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link id="favicon" rel="icon" href="./favicon.ico" />
|
||||
<link rel="stylesheet" href="./index.css" />
|
||||
<link id="favicon" rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="Web site to manage keycloak" />
|
||||
<title>Keycloak Administration Console</title>
|
||||
|
@ -60,17 +59,17 @@
|
|||
</div>
|
||||
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<script type="module" src="/_dist_/index.js"></script>
|
||||
<script type="module" src="/index.js"></script>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start`.
|
||||
To create a production bundle, use `npm run build`.
|
||||
-->
|
||||
To begin the development, run `npm start`.
|
||||
To create a production bundle, use `npm run build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
85
themes/rh-sso/index.html
Normal file
|
@ -0,0 +1,85 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link id="favicon" rel="icon" href="./favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="Web site to manage Red Hat Single Sign-On" />
|
||||
<title>Red Hat Single Sign-On Administration Console</title>
|
||||
|
||||
<style>
|
||||
.container,
|
||||
.container-fluid,
|
||||
#load-container {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.container,
|
||||
.container-fluid,
|
||||
#load-container {
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
.keycloak__loading-container {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
background-color: #f0f0f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#loading-text {
|
||||
z-index: 1000;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
padding-top: 32px;
|
||||
}
|
||||
|
||||
/* Theme specific styling */
|
||||
.keycloak__pageheader_brand {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
body {
|
||||
--pf-global--primary-color--100: red;
|
||||
--pf-global--active-color--400: darkred;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="height: 100%;">
|
||||
<div id="app" style="height: 100%">
|
||||
<div class="container container-fluid" id="load-container">
|
||||
<div class="keycloak__loading-container">
|
||||
<span class="pf-c-spinner pf-m-xl" role="progressbar" aria-valuetext="Loading...">
|
||||
<span class="pf-c-spinner__clipper"></span>
|
||||
<span class="pf-c-spinner__lead-ball"></span>
|
||||
<span class="pf-c-spinner__tail-ball"></span>
|
||||
</span>
|
||||
<div>
|
||||
<p id="loading-text">Loading the admin console</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<script type="module" src="index.js"></script>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start`.
|
||||
To create a production bundle, use `npm run build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |