Run as theme (#840)
* Build for Keycloak theme * Update based on lastest index.html changes. * Fix realm dropdown when home realm is not master. * Fix readme. * Fix linting errors. * Try to fix tests. * Address Jon's comments.
This commit is contained in:
parent
0930778390
commit
d606dc6bee
13 changed files with 172 additions and 132 deletions
2
.github/workflows/cypress.yml
vendored
2
.github/workflows/cypress.yml
vendored
|
@ -30,7 +30,7 @@ jobs:
|
||||||
run: ./start.js & sleep 40
|
run: ./start.js & sleep 40
|
||||||
|
|
||||||
- name: Run Admin Console
|
- name: Run Admin Console
|
||||||
run: npx http-server ./build -P http://localhost:8180/ & sleep 30
|
run: npx http-server ./build/src/main/resources/admin/resources -P http://localhost:8180/ & sleep 30
|
||||||
|
|
||||||
- name: Admin Console client
|
- name: Admin Console client
|
||||||
run: ./import.js
|
run: ./import.js
|
||||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -128,8 +128,9 @@ sketch
|
||||||
|
|
||||||
# snowpack
|
# snowpack
|
||||||
web_modules/
|
web_modules/
|
||||||
build/
|
build/src
|
||||||
.build/
|
build/target
|
||||||
|
.build/target
|
||||||
public/assets/
|
public/assets/
|
||||||
|
|
||||||
# server-install
|
# server-install
|
||||||
|
|
27
build/README.md
Normal file
27
build/README.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Keycloak Admin Console V2 Maven Build
|
||||||
|
|
||||||
|
The Maven build prepares the admin console to be deployed as a theme on the Keycloak server.
|
||||||
|
|
||||||
|
# Build Instructions
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$> npm run build
|
||||||
|
$> cd build
|
||||||
|
$> mvn install
|
||||||
|
```
|
||||||
|
|
||||||
|
# Deployment
|
||||||
|
|
||||||
|
The jar created with `mvn install` needs to be deployed to a Maven repository. From there, it will become part of the Keycloak server build.
|
||||||
|
|
||||||
|
For development, you can also just copy the contents of `build/target/classes` to `<keycloak server>/themes/keycloak.v2`. Then restart the server.
|
||||||
|
|
||||||
|
# To Run
|
||||||
|
|
||||||
|
Until New Admin Console becomes the default, you will need to start Keycloak server like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$> bin/standalone.sh -Dprofile.feature.newadmin=enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
Then go to `Realm Settings --> Themes` and set Admin Console Theme to `keycloak.v2`.
|
92
build/pom.xml
Normal file
92
build/pom.xml
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
JBoss, Home of Professional Open Source
|
||||||
|
Copyright 2016, Red Hat, Inc. and/or its affiliates, and individual
|
||||||
|
contributors by the @authors tag. See the copyright.txt in the
|
||||||
|
distribution for a full listing of individual contributors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-admin-ui</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>Keycloak Administration UI</name>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>Apache License, Version 2.0.0</name>
|
||||||
|
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jboss</id>
|
||||||
|
<url>https://repository.jboss.org/nexus/content/groups/public/</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||||
|
<artifactId>maven-replacer-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>replace</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<file>target/classes/admin/resources/index.html</file>
|
||||||
|
<outputFile>target/classes/admin/index.ftl</outputFile>
|
||||||
|
<regex>false</regex>
|
||||||
|
<replacements>
|
||||||
|
<replacement>
|
||||||
|
<token>src="/_dist_</token>
|
||||||
|
<value>src="${resourceUrl}/_dist_</value>
|
||||||
|
</replacement>
|
||||||
|
<replacement>
|
||||||
|
<token>href="./</token>
|
||||||
|
<value>href="${resourceUrl}/</value>
|
||||||
|
</replacement>
|
||||||
|
<replacement>
|
||||||
|
<token><head></token>
|
||||||
|
<value>
|
||||||
|
<head>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var loginRealm = "${loginRealm}";
|
||||||
|
var authServerUrl = "${authServerUrl}";
|
||||||
|
var authUrl = "${authUrl}";
|
||||||
|
var consoleBaseUrl = "${consoleBaseUrl}";
|
||||||
|
var resourceUrl = "${resourceUrl}";
|
||||||
|
var masterRealm = "${masterRealm}";
|
||||||
|
var resourceVersion = "${resourceVersion}";
|
||||||
|
</script>
|
||||||
|
</value>
|
||||||
|
</replacement>
|
||||||
|
</replacements>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -1,67 +0,0 @@
|
||||||
{
|
|
||||||
"clientId": "security-admin-console-v2",
|
|
||||||
"rootUrl": "",
|
|
||||||
"adminUrl": "",
|
|
||||||
"baseUrl": "",
|
|
||||||
"surrogateAuthRequired": false,
|
|
||||||
"enabled": true,
|
|
||||||
"alwaysDisplayInConsole": false,
|
|
||||||
"clientAuthenticatorType": "client-secret",
|
|
||||||
"redirectUris": [
|
|
||||||
"/adminv2/*",
|
|
||||||
"http://localhost:8080/*",
|
|
||||||
"http://localhost/*"
|
|
||||||
],
|
|
||||||
"webOrigins": [
|
|
||||||
"*"
|
|
||||||
],
|
|
||||||
"notBefore": 0,
|
|
||||||
"bearerOnly": false,
|
|
||||||
"consentRequired": false,
|
|
||||||
"standardFlowEnabled": true,
|
|
||||||
"implicitFlowEnabled": false,
|
|
||||||
"directAccessGrantsEnabled": true,
|
|
||||||
"serviceAccountsEnabled": false,
|
|
||||||
"publicClient": true,
|
|
||||||
"frontchannelLogout": false,
|
|
||||||
"protocol": "openid-connect",
|
|
||||||
"attributes": {
|
|
||||||
"saml.assertion.signature": "false",
|
|
||||||
"saml.force.post.binding": "false",
|
|
||||||
"saml.multivalued.roles": "false",
|
|
||||||
"saml.encrypt": "false",
|
|
||||||
"backchannel.logout.revoke.offline.tokens": "false",
|
|
||||||
"saml.server.signature": "false",
|
|
||||||
"saml.server.signature.keyinfo.ext": "false",
|
|
||||||
"exclude.session.state.from.auth.response": "false",
|
|
||||||
"backchannel.logout.session.required": "true",
|
|
||||||
"client_credentials.use_refresh_token": "false",
|
|
||||||
"saml_force_name_id_format": "false",
|
|
||||||
"saml.client.signature": "false",
|
|
||||||
"tls.client.certificate.bound.access.tokens": "false",
|
|
||||||
"saml.authnstatement": "false",
|
|
||||||
"display.on.consent.screen": "false",
|
|
||||||
"saml.onetimeuse.condition": "false"
|
|
||||||
},
|
|
||||||
"authenticationFlowBindingOverrides": {},
|
|
||||||
"fullScopeAllowed": true,
|
|
||||||
"nodeReRegistrationTimeout": -1,
|
|
||||||
"defaultClientScopes": [
|
|
||||||
"web-origins",
|
|
||||||
"role_list",
|
|
||||||
"roles",
|
|
||||||
"profile",
|
|
||||||
"email"
|
|
||||||
],
|
|
||||||
"optionalClientScopes": [
|
|
||||||
"address",
|
|
||||||
"phone",
|
|
||||||
"offline_access",
|
|
||||||
"microprofile-jwt"
|
|
||||||
],
|
|
||||||
"access": {
|
|
||||||
"view": true,
|
|
||||||
"configure": true,
|
|
||||||
"manage": true
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,7 +9,10 @@ module.exports = {
|
||||||
"@snowpack/plugin-typescript",
|
"@snowpack/plugin-typescript",
|
||||||
],
|
],
|
||||||
buildOptions: {
|
buildOptions: {
|
||||||
baseUrl: "/adminv2",
|
baseUrl: "./",
|
||||||
clean: true,
|
clean: true,
|
||||||
},
|
},
|
||||||
|
devOptions: {
|
||||||
|
out: "build/src/main/resources/admin/resources", // For snowpack 3, "out" goes under buildOptions.
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { WhoAmIContext } from "./context/whoami/WhoAmI";
|
||||||
import { HelpContext, HelpHeader } from "./components/help-enabler/HelpHeader";
|
import { HelpContext, HelpHeader } from "./components/help-enabler/HelpHeader";
|
||||||
import { Link, useHistory } from "react-router-dom";
|
import { Link, useHistory } from "react-router-dom";
|
||||||
import { useAdminClient } from "./context/auth/AdminClient";
|
import { useAdminClient } from "./context/auth/AdminClient";
|
||||||
|
import { resourceUri } from "./util";
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
const adminClient = useAdminClient();
|
const adminClient = useAdminClient();
|
||||||
|
@ -126,7 +127,7 @@ export const Header = () => {
|
||||||
<UserDropdown />
|
<UserDropdown />
|
||||||
</PageHeaderToolsItem>
|
</PageHeaderToolsItem>
|
||||||
</PageHeaderToolsGroup>
|
</PageHeaderToolsGroup>
|
||||||
<Avatar src="./img_avatar.svg" alt="Avatar image" />
|
<Avatar src={resourceUri + "/img_avatar.svg"} alt="Avatar image" />
|
||||||
</PageHeaderTools>
|
</PageHeaderTools>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -180,7 +181,7 @@ export const Header = () => {
|
||||||
logo={
|
logo={
|
||||||
<Link to="/">
|
<Link to="/">
|
||||||
<Brand
|
<Brand
|
||||||
src="./logo.svg"
|
src={resourceUri + "/logo.svg"}
|
||||||
id="masthead-logo"
|
id="masthead-logo"
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
className="keycloak__pageheader_brand"
|
className="keycloak__pageheader_brand"
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe("FormAccess", () => {
|
||||||
<WhoAmIContext.Provider
|
<WhoAmIContext.Provider
|
||||||
value={{
|
value={{
|
||||||
refresh: () => {},
|
refresh: () => {},
|
||||||
whoAmI: new WhoAmI("master", whoami as WhoAmIRepresentation),
|
whoAmI: new WhoAmI(whoami as WhoAmIRepresentation),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RealmContext.Provider
|
<RealmContext.Provider
|
||||||
|
|
|
@ -1,51 +1,25 @@
|
||||||
import KcAdminClient from "keycloak-admin";
|
import KcAdminClient from "keycloak-admin";
|
||||||
|
import { homeRealm, isDevMode, authUri } from "../../util";
|
||||||
|
|
||||||
export default async function (): Promise<KcAdminClient> {
|
export default async function (): Promise<KcAdminClient> {
|
||||||
const realm =
|
|
||||||
new URLSearchParams(window.location.search).get("realm") || "master";
|
|
||||||
|
|
||||||
const kcAdminClient = new KcAdminClient();
|
const kcAdminClient = new KcAdminClient();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await kcAdminClient.init(
|
await kcAdminClient.init(
|
||||||
{ onLoad: "check-sso", pkceMethod: "S256" },
|
{ onLoad: "check-sso", pkceMethod: "S256" },
|
||||||
{
|
{
|
||||||
url: keycloakAuthUrl(),
|
url: authUri(),
|
||||||
realm: realm,
|
realm: homeRealm(),
|
||||||
clientId: "security-admin-console-v2",
|
clientId: isDevMode
|
||||||
|
? "security-admin-console-v2"
|
||||||
|
: "security-admin-console",
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
kcAdminClient.setConfig({ realmName: realm });
|
kcAdminClient.setConfig({ realmName: homeRealm() });
|
||||||
|
|
||||||
// we can get rid of devMode once developers upgrade to Keycloak 13
|
kcAdminClient.baseUrl = authUri();
|
||||||
const devMode = !window.location.pathname.startsWith("/adminv2");
|
|
||||||
kcAdminClient.baseUrl = devMode ? "/auth" : keycloakAuthUrl();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert("failed to initialize keycloak");
|
alert("failed to initialize keycloak");
|
||||||
}
|
}
|
||||||
|
|
||||||
return kcAdminClient;
|
return kcAdminClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keycloakAuthUrl = () => {
|
|
||||||
// Eventually, authContext should not be hard-coded.
|
|
||||||
// You are allowed to change this context on your keycloak server,
|
|
||||||
// but it is rarely done.
|
|
||||||
const authContext = "/auth";
|
|
||||||
|
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
|
||||||
|
|
||||||
// passed in as query param
|
|
||||||
const authUrlFromParam = searchParams.get("keycloak-server");
|
|
||||||
if (authUrlFromParam) return authUrlFromParam + authContext;
|
|
||||||
|
|
||||||
// dev mode
|
|
||||||
if (!window.location.pathname.startsWith("/adminv2"))
|
|
||||||
return "http://localhost:8180" + authContext;
|
|
||||||
|
|
||||||
// demo mode
|
|
||||||
if (searchParams.get("demo")) return "http://localhost:8080" + authContext;
|
|
||||||
|
|
||||||
// admin console served from keycloak server
|
|
||||||
return window.location.origin + authContext;
|
|
||||||
};
|
|
||||||
|
|
|
@ -4,12 +4,10 @@ import i18n from "../../i18n";
|
||||||
import type WhoAmIRepresentation from "keycloak-admin/lib/defs/whoAmIRepresentation";
|
import type WhoAmIRepresentation from "keycloak-admin/lib/defs/whoAmIRepresentation";
|
||||||
import type { AccessType } from "keycloak-admin/lib/defs/whoAmIRepresentation";
|
import type { AccessType } from "keycloak-admin/lib/defs/whoAmIRepresentation";
|
||||||
import { useAdminClient, useFetch } from "../auth/AdminClient";
|
import { useAdminClient, useFetch } from "../auth/AdminClient";
|
||||||
|
import { homeRealm } from "../../util";
|
||||||
|
|
||||||
export class WhoAmI {
|
export class WhoAmI {
|
||||||
constructor(
|
constructor(private me?: WhoAmIRepresentation) {
|
||||||
private homeRealm?: string | undefined,
|
|
||||||
private me?: WhoAmIRepresentation | undefined
|
|
||||||
) {
|
|
||||||
if (this.me !== undefined && this.me.locale) {
|
if (this.me !== undefined && this.me.locale) {
|
||||||
i18n.changeLanguage(this.me.locale, (error) => {
|
i18n.changeLanguage(this.me.locale, (error) => {
|
||||||
if (error) console.error("Unable to set locale to", this.me?.locale);
|
if (error) console.error("Unable to set locale to", this.me?.locale);
|
||||||
|
@ -33,11 +31,7 @@ export class WhoAmI {
|
||||||
* Return the realm I am signed in to.
|
* Return the realm I am signed in to.
|
||||||
*/
|
*/
|
||||||
public getHomeRealm(): string {
|
public getHomeRealm(): string {
|
||||||
let realm: string | undefined = this.homeRealm;
|
return homeRealm();
|
||||||
if (realm === undefined) realm = this.me?.realm;
|
|
||||||
if (realm === undefined) realm = "master"; // this really can't happen in the real world
|
|
||||||
|
|
||||||
return realm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public canCreateRealm(): boolean {
|
public canCreateRealm(): boolean {
|
||||||
|
@ -72,7 +66,7 @@ export const WhoAmIContextProvider = ({ children }: WhoAmIProviderProps) => {
|
||||||
useFetch(
|
useFetch(
|
||||||
() => adminClient.whoAmI.find(),
|
() => adminClient.whoAmI.find(),
|
||||||
(me) => {
|
(me) => {
|
||||||
const whoAmI = new WhoAmI(adminClient.keycloak?.realm, me);
|
const whoAmI = new WhoAmI(me);
|
||||||
setWhoAmI(whoAmI);
|
setWhoAmI(whoAmI);
|
||||||
},
|
},
|
||||||
[key]
|
[key]
|
||||||
|
|
|
@ -3,24 +3,22 @@ import { WhoAmI } from "../WhoAmI";
|
||||||
import type WhoAmIRepresentation from "keycloak-admin/lib/defs/whoAmIRepresentation";
|
import type WhoAmIRepresentation from "keycloak-admin/lib/defs/whoAmIRepresentation";
|
||||||
|
|
||||||
test("returns display name", () => {
|
test("returns display name", () => {
|
||||||
const whoami = new WhoAmI("master", whoamiMock as WhoAmIRepresentation);
|
const whoami = new WhoAmI(whoamiMock as WhoAmIRepresentation);
|
||||||
expect(whoami.getDisplayName()).toEqual("Stan Silvert");
|
expect(whoami.getDisplayName()).toEqual("Stan Silvert");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("returns correct home realm", () => {
|
test("returns correct home realm in dev mode", () => {
|
||||||
let whoami = new WhoAmI("myrealm", whoamiMock as WhoAmIRepresentation);
|
const whoami = new WhoAmI(whoamiMock as WhoAmIRepresentation);
|
||||||
expect(whoami.getHomeRealm()).toEqual("myrealm");
|
|
||||||
whoami = new WhoAmI(undefined, whoamiMock as WhoAmIRepresentation);
|
|
||||||
expect(whoami.getHomeRealm()).toEqual("master");
|
expect(whoami.getHomeRealm()).toEqual("master");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("can not create realm", () => {
|
test("can not create realm", () => {
|
||||||
const whoami = new WhoAmI("master", whoamiMock as WhoAmIRepresentation);
|
const whoami = new WhoAmI(whoamiMock as WhoAmIRepresentation);
|
||||||
expect(whoami.canCreateRealm()).toEqual(false);
|
expect(whoami.canCreateRealm()).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("getRealmAccess", () => {
|
test("getRealmAccess", () => {
|
||||||
const whoami = new WhoAmI("master", whoamiMock as WhoAmIRepresentation);
|
const whoami = new WhoAmI(whoamiMock as WhoAmIRepresentation);
|
||||||
expect(Object.keys(whoami.getRealmAccess()).length).toEqual(3);
|
expect(Object.keys(whoami.getRealmAccess()).length).toEqual(3);
|
||||||
expect(whoami.getRealmAccess()["master"].length).toEqual(18);
|
expect(whoami.getRealmAccess()["master"].length).toEqual(18);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import {
|
import {
|
||||||
Brand,
|
Brand,
|
||||||
Button,
|
|
||||||
Card,
|
Card,
|
||||||
CardBody,
|
CardBody,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
|
@ -29,17 +28,17 @@ import { useRealm } from "../context/realm-context/RealmContext";
|
||||||
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
|
||||||
|
|
||||||
import "./dashboard.css";
|
import "./dashboard.css";
|
||||||
import { toUpperCase } from "../util";
|
import { toUpperCase, resourceUri } from "../util";
|
||||||
import { HelpItem } from "../components/help-enabler/HelpItem";
|
import { HelpItem } from "../components/help-enabler/HelpItem";
|
||||||
|
|
||||||
const EmptyDashboard = () => {
|
const EmptyDashboard = () => {
|
||||||
const { t } = useTranslation("dashboard");
|
const { t } = useTranslation("dashboard");
|
||||||
const { realm, setRealm } = useRealm();
|
const { realm } = useRealm();
|
||||||
return (
|
return (
|
||||||
<PageSection variant="light">
|
<PageSection variant="light">
|
||||||
<EmptyState variant="large">
|
<EmptyState variant="large">
|
||||||
<Brand
|
<Brand
|
||||||
src="./icon.svg"
|
src={resourceUri + "/icon.svg"}
|
||||||
alt="Keycloak icon"
|
alt="Keycloak icon"
|
||||||
className="keycloak__dashboard_icon"
|
className="keycloak__dashboard_icon"
|
||||||
/>
|
/>
|
||||||
|
@ -50,9 +49,6 @@ const EmptyDashboard = () => {
|
||||||
{realm}
|
{realm}
|
||||||
</Title>
|
</Title>
|
||||||
<EmptyStateBody>{t("introduction")}</EmptyStateBody>
|
<EmptyStateBody>{t("introduction")}</EmptyStateBody>
|
||||||
<Button variant="link" onClick={() => setRealm("master")}>
|
|
||||||
{t("common:realmInfo")}
|
|
||||||
</Button>
|
|
||||||
</EmptyState>
|
</EmptyState>
|
||||||
</PageSection>
|
</PageSection>
|
||||||
);
|
);
|
||||||
|
|
21
src/util.ts
21
src/util.ts
|
@ -5,6 +5,27 @@ import type ClientRepresentation from "keycloak-admin/lib/defs/clientRepresentat
|
||||||
import type { ProviderRepresentation } from "keycloak-admin/lib/defs/serverInfoRepesentation";
|
import type { ProviderRepresentation } from "keycloak-admin/lib/defs/serverInfoRepesentation";
|
||||||
import type KeycloakAdminClient from "keycloak-admin";
|
import type KeycloakAdminClient from "keycloak-admin";
|
||||||
|
|
||||||
|
// if we are running on Keycloak server, resourceUrl will be passed from index.ftl
|
||||||
|
declare const resourceUrl: string;
|
||||||
|
export const isDevMode = typeof resourceUrl === "undefined";
|
||||||
|
export const resourceUri = isDevMode ? "." : resourceUrl;
|
||||||
|
|
||||||
|
// if we are running on Keycloak server, loginRealm will be passed from index.ftl
|
||||||
|
declare const loginRealm: string;
|
||||||
|
export const homeRealm = () => {
|
||||||
|
if (typeof loginRealm !== "undefined") return loginRealm;
|
||||||
|
|
||||||
|
return new URLSearchParams(window.location.search).get("realm") || "master";
|
||||||
|
};
|
||||||
|
|
||||||
|
// if we are running on Keycloak server, authUrl will be passed from index.ftl
|
||||||
|
declare const authUrl: string;
|
||||||
|
export const authUri = () => {
|
||||||
|
if (typeof authUrl !== "undefined") return authUrl;
|
||||||
|
|
||||||
|
return "http://localhost:8180/auth";
|
||||||
|
};
|
||||||
|
|
||||||
export const sortProviders = (providers: {
|
export const sortProviders = (providers: {
|
||||||
[index: string]: ProviderRepresentation;
|
[index: string]: ProviderRepresentation;
|
||||||
}) => {
|
}) => {
|
||||||
|
|
Loading…
Reference in a new issue