Fix various linting issues for Account Console
Signed-off-by: Jon Koops <jonkoops@gmail.com>
This commit is contained in:
parent
813b9f2f41
commit
aa86a0b94c
10 changed files with 195 additions and 154 deletions
|
@ -12,7 +12,11 @@ import {
|
||||||
} from "@patternfly/react-core";
|
} from "@patternfly/react-core";
|
||||||
import { LinkIcon, UnlinkIcon } from "@patternfly/react-icons";
|
import { LinkIcon, UnlinkIcon } from "@patternfly/react-icons";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { IconMapper, useAlerts, useEnvironment } from "@keycloak/keycloak-ui-shared";
|
import {
|
||||||
|
IconMapper,
|
||||||
|
useAlerts,
|
||||||
|
useEnvironment,
|
||||||
|
} from "@keycloak/keycloak-ui-shared";
|
||||||
import { linkAccount, unLinkAccount } from "../api/methods";
|
import { linkAccount, unLinkAccount } from "../api/methods";
|
||||||
import { LinkedAccountRepresentation } from "../api/representations";
|
import { LinkedAccountRepresentation } from "../api/representations";
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,11 @@ import {
|
||||||
} from "@patternfly/react-icons";
|
} from "@patternfly/react-icons";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ContinueCancelModal, useAlerts, useEnvironment } from "@keycloak/keycloak-ui-shared";
|
import {
|
||||||
|
ContinueCancelModal,
|
||||||
|
useAlerts,
|
||||||
|
useEnvironment,
|
||||||
|
} from "@keycloak/keycloak-ui-shared";
|
||||||
import { deleteSession, getDevices } from "../api/methods";
|
import { deleteSession, getDevices } from "../api/methods";
|
||||||
import {
|
import {
|
||||||
ClientRepresentation,
|
ClientRepresentation,
|
||||||
|
|
|
@ -3,7 +3,13 @@ import { BaseEnvironment } from "@keycloak/keycloak-ui-shared/dist/context/envir
|
||||||
import { CallOptions } from "./api/methods";
|
import { CallOptions } from "./api/methods";
|
||||||
import { Links, parseLinks } from "./api/parse-links";
|
import { Links, parseLinks } from "./api/parse-links";
|
||||||
import { parseResponse } from "./api/parse-response";
|
import { parseResponse } from "./api/parse-response";
|
||||||
import { Permission, Resource, Scope, CredentialsIssuer, SupportedCredentialConfiguration } from "./api/representations";
|
import {
|
||||||
|
Permission,
|
||||||
|
Resource,
|
||||||
|
Scope,
|
||||||
|
CredentialsIssuer,
|
||||||
|
SupportedCredentialConfiguration,
|
||||||
|
} from "./api/representations";
|
||||||
import { request } from "./api/request";
|
import { request } from "./api/request";
|
||||||
import { joinPath } from "./utils/joinPath";
|
import { joinPath } from "./utils/joinPath";
|
||||||
|
|
||||||
|
@ -70,16 +76,20 @@ function checkResponse<T>(response: T) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getIssuer(context: KeycloakContext<BaseEnvironment>) {
|
||||||
export async function getIssuer(
|
|
||||||
context: KeycloakContext<BaseEnvironment>
|
|
||||||
) {
|
|
||||||
const response = await request(
|
const response = await request(
|
||||||
"/realms/" + context.environment.realm + "/.well-known/openid-credential-issuer",
|
"/realms/" +
|
||||||
|
context.environment.realm +
|
||||||
|
"/.well-known/openid-credential-issuer",
|
||||||
context,
|
context,
|
||||||
{},
|
{},
|
||||||
new URL(
|
new URL(
|
||||||
joinPath(context.environment.authUrl + "/realms/" + context.environment.realm + "/.well-known/openid-credential-issuer"),
|
joinPath(
|
||||||
|
context.environment.authUrl +
|
||||||
|
"/realms/" +
|
||||||
|
context.environment.realm +
|
||||||
|
"/.well-known/openid-credential-issuer",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return parseResponse<CredentialsIssuer>(response);
|
return parseResponse<CredentialsIssuer>(response);
|
||||||
|
@ -87,16 +97,26 @@ export async function getIssuer(
|
||||||
|
|
||||||
export async function requestVCOffer(
|
export async function requestVCOffer(
|
||||||
context: KeycloakContext<BaseEnvironment>,
|
context: KeycloakContext<BaseEnvironment>,
|
||||||
supportedCredentialConfiguration:SupportedCredentialConfiguration,
|
supportedCredentialConfiguration: SupportedCredentialConfiguration,
|
||||||
credentialsIssuer:CredentialsIssuer
|
credentialsIssuer: CredentialsIssuer,
|
||||||
) {
|
) {
|
||||||
const response = await request(
|
const response = await request(
|
||||||
"/protocol/oid4vc/credential-offer-uri",
|
"/protocol/oid4vc/credential-offer-uri",
|
||||||
context,
|
context,
|
||||||
{ searchParams: {"credential_configuration_id": supportedCredentialConfiguration.id, "type": "qr-code", "width": "500", "height": "500"} },
|
{
|
||||||
|
searchParams: {
|
||||||
|
credential_configuration_id: supportedCredentialConfiguration.id,
|
||||||
|
type: "qr-code",
|
||||||
|
width: "500",
|
||||||
|
height: "500",
|
||||||
|
},
|
||||||
|
},
|
||||||
new URL(
|
new URL(
|
||||||
joinPath(credentialsIssuer.credential_issuer + "/protocol/oid4vc/credential-offer-uri"),
|
joinPath(
|
||||||
|
credentialsIssuer.credential_issuer +
|
||||||
|
"/protocol/oid4vc/credential-offer-uri",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return response.blob()
|
return response.blob();
|
||||||
}
|
}
|
|
@ -212,5 +212,8 @@ export interface CredentialsIssuer {
|
||||||
credential_issuer: string;
|
credential_issuer: string;
|
||||||
credential_endpoint: string;
|
credential_endpoint: string;
|
||||||
authorization_servers: string[];
|
authorization_servers: string[];
|
||||||
credential_configurations_supported: Record<string, SupportedCredentialConfiguration>
|
credential_configurations_supported: Record<
|
||||||
|
string,
|
||||||
|
SupportedCredentialConfiguration
|
||||||
|
>;
|
||||||
}
|
}
|
|
@ -37,10 +37,10 @@ export async function request(
|
||||||
path: string,
|
path: string,
|
||||||
{ environment, keycloak }: KeycloakContext<BaseEnvironment>,
|
{ environment, keycloak }: KeycloakContext<BaseEnvironment>,
|
||||||
opts: RequestOptions = {},
|
opts: RequestOptions = {},
|
||||||
fullUrl?: URL
|
fullUrl?: URL,
|
||||||
) {
|
) {
|
||||||
if (typeof fullUrl === 'undefined') {
|
if (typeof fullUrl === "undefined") {
|
||||||
fullUrl = url(environment, path)
|
fullUrl = url(environment, path);
|
||||||
}
|
}
|
||||||
return _request(fullUrl, {
|
return _request(fullUrl, {
|
||||||
...opts,
|
...opts,
|
||||||
|
|
|
@ -22,7 +22,11 @@ import {
|
||||||
} from "@patternfly/react-icons";
|
} from "@patternfly/react-icons";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ContinueCancelModal, useAlerts, useEnvironment } from "@keycloak/keycloak-ui-shared";
|
import {
|
||||||
|
ContinueCancelModal,
|
||||||
|
useAlerts,
|
||||||
|
useEnvironment,
|
||||||
|
} from "@keycloak/keycloak-ui-shared";
|
||||||
import { deleteConsent, getApplications } from "../api/methods";
|
import { deleteConsent, getApplications } from "../api/methods";
|
||||||
import { ClientRepresentation } from "../api/representations";
|
import { ClientRepresentation } from "../api/representations";
|
||||||
import { Page } from "../components/page/Page";
|
import { Page } from "../components/page/Page";
|
||||||
|
|
|
@ -1,74 +1,70 @@
|
||||||
|
import { useEnvironment } from "@keycloak/keycloak-ui-shared";
|
||||||
import {
|
import {
|
||||||
Select,
|
|
||||||
SelectList,
|
|
||||||
SelectOption,
|
|
||||||
PageSectionVariants,
|
|
||||||
PageSection,
|
|
||||||
ActionList,
|
ActionList,
|
||||||
ActionListItem,
|
ActionListItem,
|
||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
|
MenuToggle,
|
||||||
MenuToggleElement,
|
MenuToggleElement,
|
||||||
MenuToggle
|
PageSection,
|
||||||
} from '@patternfly/react-core';
|
PageSectionVariants,
|
||||||
import { useEffect, useState, useMemo } from "react";
|
Select,
|
||||||
|
SelectList,
|
||||||
|
SelectOption,
|
||||||
|
} from "@patternfly/react-core";
|
||||||
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useAlerts, useEnvironment } from "@keycloak/keycloak-ui-shared";
|
|
||||||
import { usePromise } from "../utils/usePromise";
|
|
||||||
import { Page } from "../components/page/Page";
|
|
||||||
import { CredentialsIssuer } from "../api/representations";
|
|
||||||
import { getIssuer, requestVCOffer } from "../api";
|
import { getIssuer, requestVCOffer } from "../api";
|
||||||
|
import { CredentialsIssuer } from "../api/representations";
|
||||||
|
import { Page } from "../components/page/Page";
|
||||||
|
import { usePromise } from "../utils/usePromise";
|
||||||
|
|
||||||
export const Oid4Vci = () => {
|
export const Oid4Vci = () => {
|
||||||
const context = useEnvironment();
|
const context = useEnvironment();
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const initialSelected = t('verifiableCredentialsSelectionDefault')
|
const initialSelected = t("verifiableCredentialsSelectionDefault");
|
||||||
|
|
||||||
const [selected, setSelected] = useState<string>(initialSelected);
|
const [selected, setSelected] = useState<string>(initialSelected);
|
||||||
const [qrCode, setQrCode] = useState<string>("")
|
const [qrCode, setQrCode] = useState<string>("");
|
||||||
const [isOpen, setIsOpen] = useState<boolean>(false)
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||||
const [offerQRVisible, setOfferQRVisible] = useState<boolean>(false)
|
const [offerQRVisible, setOfferQRVisible] = useState<boolean>(false);
|
||||||
const [credentialsIssuer, setCredentialsIssuer] = useState<CredentialsIssuer>()
|
const [credentialsIssuer, setCredentialsIssuer] =
|
||||||
|
useState<CredentialsIssuer>();
|
||||||
|
|
||||||
usePromise(() => getIssuer(context), setCredentialsIssuer);
|
usePromise(() => getIssuer(context), setCredentialsIssuer);
|
||||||
|
|
||||||
const selectOptions = useMemo(
|
const selectOptions = useMemo(() => {
|
||||||
() => {
|
if (typeof credentialsIssuer !== "undefined") {
|
||||||
if(typeof credentialsIssuer !== 'undefined') {
|
return credentialsIssuer.credential_configurations_supported;
|
||||||
return credentialsIssuer.credential_configurations_supported
|
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
},
|
}, [credentialsIssuer]);
|
||||||
[credentialsIssuer],
|
|
||||||
)
|
|
||||||
|
|
||||||
const dropdownItems = useMemo(
|
const dropdownItems = useMemo(() => {
|
||||||
() => {
|
if (typeof selectOptions !== "undefined") {
|
||||||
if (typeof selectOptions !== 'undefined') {
|
return Array.from(Object.keys(selectOptions));
|
||||||
return Array.from(Object.keys(selectOptions))
|
|
||||||
}
|
}
|
||||||
return []
|
return [];
|
||||||
},
|
}, [selectOptions]);
|
||||||
[selectOptions],
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(initialSelected !== selected && credentialsIssuer !== undefined){
|
if (initialSelected !== selected && credentialsIssuer !== undefined) {
|
||||||
requestVCOffer(context, selectOptions[selected], credentialsIssuer)
|
requestVCOffer(context, selectOptions[selected], credentialsIssuer).then(
|
||||||
.then((blob) => {
|
(blob) => {
|
||||||
var reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsDataURL(blob)
|
reader.readAsDataURL(blob);
|
||||||
reader.onloadend = function() {
|
reader.onloadend = function () {
|
||||||
let result = reader.result
|
const result = reader.result;
|
||||||
if (typeof result === "string") {
|
if (typeof result === "string") {
|
||||||
setQrCode(result);
|
setQrCode(result);
|
||||||
setOfferQRVisible(true);
|
setOfferQRVisible(true);
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
})
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [selected]);
|
}, [selected]);
|
||||||
|
|
||||||
|
@ -88,7 +84,10 @@ export const Oid4Vci = () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title={t('verifiableCredentialsTitle')} description={t('verifiableCredentialsDescription')}>
|
<Page
|
||||||
|
title={t("verifiableCredentialsTitle")}
|
||||||
|
description={t("verifiableCredentialsDescription")}
|
||||||
|
>
|
||||||
<PageSection isFilled variant={PageSectionVariants.light}>
|
<PageSection isFilled variant={PageSectionVariants.light}>
|
||||||
<List isPlain>
|
<List isPlain>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
|
@ -102,10 +101,11 @@ export const Oid4Vci = () => {
|
||||||
shouldFocusToggleOnSelect={true}
|
shouldFocusToggleOnSelect={true}
|
||||||
>
|
>
|
||||||
<SelectList>
|
<SelectList>
|
||||||
{dropdownItems.map((option, index) => (
|
{dropdownItems.map((option) => (
|
||||||
<SelectOption
|
<SelectOption
|
||||||
|
key={option}
|
||||||
value={option}
|
value={option}
|
||||||
data-testid='select-${option}'
|
data-testid="select-${option}"
|
||||||
>
|
>
|
||||||
{option}
|
{option}
|
||||||
</SelectOption>
|
</SelectOption>
|
||||||
|
@ -115,11 +115,16 @@ export const Oid4Vci = () => {
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ActionList>
|
<ActionList>
|
||||||
{ offerQRVisible &&
|
{offerQRVisible && (
|
||||||
<ActionListItem>
|
<ActionListItem>
|
||||||
<img width='500' height='500' src={`${qrCode}`} data-testid="qr-code"/>
|
<img
|
||||||
|
width="500"
|
||||||
|
height="500"
|
||||||
|
src={`${qrCode}`}
|
||||||
|
data-testid="qr-code"
|
||||||
|
/>
|
||||||
</ActionListItem>
|
</ActionListItem>
|
||||||
}
|
)}
|
||||||
</ActionList>
|
</ActionList>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
|
@ -128,5 +133,4 @@ export const Oid4Vci = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default Oid4Vci;
|
export default Oid4Vci;
|
|
@ -32,7 +32,11 @@ import {
|
||||||
} from "@patternfly/react-table";
|
} from "@patternfly/react-table";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ContinueCancelModal, useAlerts, useEnvironment } from "@keycloak/keycloak-ui-shared";
|
import {
|
||||||
|
ContinueCancelModal,
|
||||||
|
useAlerts,
|
||||||
|
useEnvironment,
|
||||||
|
} from "@keycloak/keycloak-ui-shared";
|
||||||
import { fetchPermission, fetchResources, updatePermissions } from "../api";
|
import { fetchPermission, fetchResources, updatePermissions } from "../api";
|
||||||
import { getPermissionRequests } from "../api/methods";
|
import { getPermissionRequests } from "../api/methods";
|
||||||
import { Links } from "../api/parse-links";
|
import { Links } from "../api/parse-links";
|
||||||
|
|
|
@ -61,7 +61,7 @@ export const PersonalInfoRoute: IndexRouteObject = {
|
||||||
export const Oid4VciRoute: RouteObject = {
|
export const Oid4VciRoute: RouteObject = {
|
||||||
path: "oid4vci",
|
path: "oid4vci",
|
||||||
element: <Oid4Vci />,
|
element: <Oid4Vci />,
|
||||||
}
|
};
|
||||||
|
|
||||||
export const RootRoute: RouteObject = {
|
export const RootRoute: RouteObject = {
|
||||||
path: decodeURIComponent(new URL(environment.baseUrl).pathname),
|
path: decodeURIComponent(new URL(environment.baseUrl).pathname),
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
import { expect, test } from "@playwright/test";
|
import { expect, test } from "@playwright/test";
|
||||||
import { login } from "../login";
|
import { login } from "../login";
|
||||||
|
|
||||||
const realm = "verifiable-credentials"
|
|
||||||
|
|
||||||
test.describe("Verifiable Credentials page", () => {
|
test.describe("Verifiable Credentials page", () => {
|
||||||
|
|
||||||
test("Get offer for test-credential.", async ({ page }) => {
|
test("Get offer for test-credential.", async ({ page }) => {
|
||||||
|
await login(page, "test-user", "test");
|
||||||
await login(page, "test-user", "test")
|
await expect(page.getByTestId("qr-code")).toBeHidden();
|
||||||
await expect(page.getByTestId("qr-code")).toBeHidden
|
await page.getByTestId("oid4vci").click();
|
||||||
await page.getByTestId("oid4vci").click
|
await page.getByTestId("credential-select").click();
|
||||||
await page.getByTestId("credential-select").click
|
await expect(
|
||||||
await expect(page.getByTestId("select-verifiable-credential")).toBeVisible
|
page.getByTestId("select-verifiable-credential"),
|
||||||
await expect(page.getByTestId("select-natural-person")).toBeVisible
|
).toBeVisible();
|
||||||
await page.getByTestId("select-natural-person").click
|
await expect(page.getByTestId("select-natural-person")).toBeVisible();
|
||||||
await expect(page.getByTestId("qr-code")).toBeVisible
|
await page.getByTestId("select-natural-person").click();
|
||||||
})
|
await expect(page.getByTestId("qr-code")).toBeVisible();
|
||||||
})
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in a new issue