@oussemasahbeni/keycloakify-login-shadcn 250004.0.7 → 250004.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/keycloak-theme/components/langauges.tsx +1 -1
- package/keycloak-theme/components/theme-toggle.tsx +0 -1
- package/keycloak-theme/components/ui/alert.tsx +69 -62
- package/keycloak-theme/components/ui/button.tsx +44 -39
- package/keycloak-theme/components/ui/card.tsx +59 -45
- package/keycloak-theme/components/ui/checkbox.tsx +24 -23
- package/keycloak-theme/components/ui/dropdown-menu.tsx +233 -168
- package/keycloak-theme/components/ui/field.tsx +50 -48
- package/keycloak-theme/components/ui/input-otp.tsx +55 -49
- package/keycloak-theme/components/ui/input.tsx +18 -22
- package/keycloak-theme/components/ui/label.tsx +19 -21
- package/keycloak-theme/components/ui/radio-group.tsx +27 -26
- package/keycloak-theme/components/ui/select.tsx +169 -122
- package/keycloak-theme/components/ui/separator.tsx +23 -24
- package/keycloak-theme/components/ui/tooltip.tsx +53 -24
- package/keycloak-theme/login/KcPage.tsx +2 -5
- package/keycloak-theme/login/components/LogoutOtherSessions.tsx +3 -5
- package/keycloak-theme/login/components/PasswordWrapper.tsx +4 -4
- package/keycloak-theme/login/components/Template/Template.tsx +110 -58
- package/keycloak-theme/login/components/UserProfileFormFields/AddRemoveButtonsMultiValuedAttribute.tsx +7 -3
- package/keycloak-theme/login/components/UserProfileFormFields/FieldErrors.tsx +8 -4
- package/keycloak-theme/login/components/UserProfileFormFields/GroupLabel.tsx +33 -14
- package/keycloak-theme/login/components/UserProfileFormFields/InputFieldByType.tsx +9 -2
- package/keycloak-theme/login/components/UserProfileFormFields/InputLabel.tsx +0 -1
- package/keycloak-theme/login/components/UserProfileFormFields/InputTag.tsx +25 -8
- package/keycloak-theme/login/components/UserProfileFormFields/InputTagSelects.tsx +30 -16
- package/keycloak-theme/login/components/UserProfileFormFields/SelectTag.tsx +32 -11
- package/keycloak-theme/login/components/UserProfileFormFields/TextareaTag.tsx +19 -7
- package/keycloak-theme/login/components/UserProfileFormFields/UserProfileFormFields.tsx +11 -5
- package/keycloak-theme/login/index.css +3 -20
- package/keycloak-theme/login/mocks/KcPageStory.tsx +6 -2
- package/keycloak-theme/login/pages/PageIndex.tsx +0 -4
- package/keycloak-theme/login/pages/code/Page.stories.tsx +4 -5
- package/keycloak-theme/login/pages/code/Page.tsx +6 -6
- package/keycloak-theme/login/pages/delete-account-confirm/Page.stories.tsx +0 -2
- package/keycloak-theme/login/pages/delete-account-confirm/Page.tsx +3 -6
- package/keycloak-theme/login/pages/delete-credential/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/delete-credential/Page.tsx +11 -6
- package/keycloak-theme/login/pages/error/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/error/Page.tsx +13 -12
- package/keycloak-theme/login/pages/frontchannel-logout/Page.tsx +2 -4
- package/keycloak-theme/login/pages/idp-review-user-profile/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/idp-review-user-profile/Page.tsx +2 -5
- package/keycloak-theme/login/pages/info/Page.tsx +8 -6
- package/keycloak-theme/login/pages/link-idp-action/Page.tsx +5 -3
- package/keycloak-theme/login/pages/login/Form.tsx +36 -38
- package/keycloak-theme/login/pages/login/Page.stories.tsx +4 -3
- package/keycloak-theme/login/pages/login/Page.tsx +0 -1
- package/keycloak-theme/login/pages/login/SocialProviders.tsx +14 -23
- package/keycloak-theme/login/pages/login/providers/github.svg +4 -3
- package/keycloak-theme/login/pages/login/providers/x.svg +4 -3
- package/keycloak-theme/login/pages/login/useProviderLogos.tsx +2 -3
- package/keycloak-theme/login/pages/login-config-totp/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-config-totp/Page.tsx +25 -12
- package/keycloak-theme/login/pages/login-idp-link-confirm/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-idp-link-confirm/Page.tsx +4 -7
- package/keycloak-theme/login/pages/login-idp-link-confirm-override/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-idp-link-confirm-override/Page.tsx +4 -7
- package/keycloak-theme/login/pages/login-idp-link-email/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-idp-link-email/Page.tsx +4 -7
- package/keycloak-theme/login/pages/login-oauth-grant/Page.tsx +21 -11
- package/keycloak-theme/login/pages/login-oauth2-device-verify-user-code/Page.tsx +5 -7
- package/keycloak-theme/login/pages/login-otp/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-otp/Page.tsx +35 -26
- package/keycloak-theme/login/pages/login-page-expired/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-page-expired/Page.tsx +4 -6
- package/keycloak-theme/login/pages/login-passkeys-conditional-authenticate/Page.tsx +153 -96
- package/keycloak-theme/login/pages/login-password/Page.tsx +14 -15
- package/keycloak-theme/login/pages/login-password/useScript.tsx +0 -1
- package/keycloak-theme/login/pages/login-recovery-authn-code-config/Page.tsx +5 -8
- package/keycloak-theme/login/pages/login-recovery-authn-code-input/Page.tsx +2 -3
- package/keycloak-theme/login/pages/login-reset-otp/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-reset-otp/Page.tsx +3 -4
- package/keycloak-theme/login/pages/login-reset-password/Form.tsx +5 -6
- package/keycloak-theme/login/pages/login-reset-password/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-reset-password/Page.tsx +3 -3
- package/keycloak-theme/login/pages/login-update-password/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-update-password/Page.tsx +5 -7
- package/keycloak-theme/login/pages/login-update-profile/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-update-profile/Page.tsx +6 -7
- package/keycloak-theme/login/pages/login-username/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-username/Page.tsx +6 -6
- package/keycloak-theme/login/pages/login-verify-email/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-verify-email/Page.tsx +3 -4
- package/keycloak-theme/login/pages/login-x509-info/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/login-x509-info/Page.tsx +3 -6
- package/keycloak-theme/login/pages/logout-confirm/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/logout-confirm/Page.tsx +3 -6
- package/keycloak-theme/login/pages/register/Form.tsx +8 -7
- package/keycloak-theme/login/pages/register/Page.stories.tsx +17 -8
- package/keycloak-theme/login/pages/register/TermsAcceptance.tsx +6 -7
- package/keycloak-theme/login/pages/saml-post-form/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/saml-post-form/Page.tsx +4 -6
- package/keycloak-theme/login/pages/select-authenticator/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/select-authenticator/Page.tsx +3 -6
- package/keycloak-theme/login/pages/select-organization/Page.tsx +5 -8
- package/keycloak-theme/login/pages/terms/Page.tsx +1 -3
- package/keycloak-theme/login/pages/update-email/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/update-email/Page.tsx +6 -7
- package/keycloak-theme/login/pages/webauthn-authenticate/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/webauthn-authenticate/Page.tsx +50 -46
- package/keycloak-theme/login/pages/webauthn-error/Page.stories.tsx +2 -5
- package/keycloak-theme/login/pages/webauthn-error/Page.tsx +3 -6
- package/keycloak-theme/login/pages/webauthn-register/Page.stories.tsx +0 -1
- package/keycloak-theme/login/pages/webauthn-register/Page.tsx +4 -4
- package/keycloak-theme/login/styleLevelCustomization.tsx +5 -6
- package/keycloak-theme/public/site.webmanifest +11 -1
- package/package.json +2 -2
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
|
2
|
+
import * as React from "react"
|
|
2
3
|
|
|
3
|
-
import
|
|
4
|
-
import * as React from "react";
|
|
4
|
+
import { cn } from '../lib/utils'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export { Separator };
|
|
6
|
+
function Separator({
|
|
7
|
+
className,
|
|
8
|
+
orientation = "horizontal",
|
|
9
|
+
decorative = true,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
|
|
12
|
+
return (
|
|
13
|
+
<SeparatorPrimitive.Root
|
|
14
|
+
data-slot="separator"
|
|
15
|
+
decorative={decorative}
|
|
16
|
+
orientation={orientation}
|
|
17
|
+
className={cn(
|
|
18
|
+
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
27
25
|
|
|
26
|
+
export { Separator }
|
|
@@ -1,31 +1,60 @@
|
|
|
1
|
-
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
|
2
|
-
import * as React from "react"
|
|
1
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
|
2
|
+
import * as React from "react"
|
|
3
3
|
|
|
4
|
-
import { cn } from
|
|
4
|
+
import { cn } from '../lib/utils'
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
function TooltipProvider({
|
|
7
|
+
delayDuration = 0,
|
|
8
|
+
...props
|
|
9
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
|
10
|
+
return (
|
|
11
|
+
<TooltipPrimitive.Provider
|
|
12
|
+
data-slot="tooltip-provider"
|
|
13
|
+
delayDuration={delayDuration}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
7
18
|
|
|
8
|
-
|
|
19
|
+
function Tooltip({
|
|
20
|
+
...props
|
|
21
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
22
|
+
return (
|
|
23
|
+
<TooltipProvider>
|
|
24
|
+
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
25
|
+
</TooltipProvider>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
9
28
|
|
|
10
|
-
|
|
29
|
+
function TooltipTrigger({
|
|
30
|
+
...props
|
|
31
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
|
32
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
|
|
33
|
+
}
|
|
11
34
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
function TooltipContent({
|
|
36
|
+
className,
|
|
37
|
+
sideOffset = 0,
|
|
38
|
+
children,
|
|
39
|
+
...props
|
|
40
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
41
|
+
return (
|
|
42
|
+
<TooltipPrimitive.Portal>
|
|
43
|
+
<TooltipPrimitive.Content
|
|
44
|
+
data-slot="tooltip-content"
|
|
45
|
+
sideOffset={sideOffset}
|
|
46
|
+
className={cn(
|
|
47
|
+
"bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
48
|
+
className
|
|
49
|
+
)}
|
|
50
|
+
{...props}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
<TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px]" />
|
|
54
|
+
</TooltipPrimitive.Content>
|
|
55
|
+
</TooltipPrimitive.Portal>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
29
58
|
|
|
30
|
-
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }
|
|
59
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }
|
|
31
60
|
|
|
@@ -4,13 +4,9 @@ import type { ReactNode } from "react";
|
|
|
4
4
|
import { assert } from "tsafe/assert";
|
|
5
5
|
import { type KcContext, KcContextProvider } from "./KcContext";
|
|
6
6
|
import { I18nProvider } from "./i18n";
|
|
7
|
-
import "./index.css";
|
|
8
7
|
import { PageIndex } from "./pages/PageIndex";
|
|
9
8
|
import { useStyleLevelCustomization } from "./styleLevelCustomization";
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
10
|
export default function KcPage(props: { kcContext: KcContext }) {
|
|
15
11
|
const { kcContext } = props;
|
|
16
12
|
|
|
@@ -28,7 +24,8 @@ export default function KcPage(props: { kcContext: KcContext }) {
|
|
|
28
24
|
function StyleLevelCustomization(props: { children: ReactNode }) {
|
|
29
25
|
const { children } = props;
|
|
30
26
|
|
|
31
|
-
const { doUseDefaultCss, classes, loadCustomStylesheet, Provider } =
|
|
27
|
+
const { doUseDefaultCss, classes, loadCustomStylesheet, Provider } =
|
|
28
|
+
useStyleLevelCustomization();
|
|
32
29
|
|
|
33
30
|
useExclusiveAppInstanceEffect({
|
|
34
31
|
effectId: "loadCustomStylesheet",
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { Checkbox } from
|
|
2
|
-
import { useI18n } from
|
|
3
|
-
import { Label } from
|
|
4
|
-
|
|
1
|
+
import { Checkbox } from "@/components/ui/checkbox";
|
|
2
|
+
import { useI18n } from "@/login/i18n";
|
|
3
|
+
import { Label } from "@radix-ui/react-label";
|
|
5
4
|
|
|
6
5
|
export function LogoutOtherSessions() {
|
|
7
|
-
|
|
8
6
|
const { msg } = useI18n();
|
|
9
7
|
|
|
10
8
|
return (
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { useI18n } from
|
|
2
|
-
import { useKcContext } from
|
|
1
|
+
import { useI18n } from "@/login/i18n";
|
|
2
|
+
import { useKcContext } from "@/login/KcContext";
|
|
3
3
|
import { useIsPasswordRevealed } from "keycloakify/tools/useIsPasswordRevealed";
|
|
4
|
+
import type { JSX } from 'react';
|
|
4
5
|
import { FiEye, FiEyeOff } from "react-icons/fi";
|
|
5
6
|
|
|
7
|
+
|
|
6
8
|
export function PasswordWrapper(props: {
|
|
7
9
|
passwordInputId: string;
|
|
8
10
|
children: JSX.Element;
|
|
@@ -12,12 +14,10 @@ export function PasswordWrapper(props: {
|
|
|
12
14
|
|
|
13
15
|
const { msgStr } = useI18n();
|
|
14
16
|
|
|
15
|
-
|
|
16
17
|
const { isPasswordRevealed, toggleIsPasswordRevealed } = useIsPasswordRevealed({
|
|
17
18
|
passwordInputId
|
|
18
19
|
});
|
|
19
20
|
|
|
20
|
-
|
|
21
21
|
return (
|
|
22
22
|
<div className="relative">
|
|
23
23
|
{children}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import { Languages } from
|
|
2
|
-
import { ModeToggle } from
|
|
3
|
-
import { Alert, AlertDescription } from
|
|
4
|
-
import { Button } from
|
|
5
|
-
import { Card, CardContent, CardHeader, CardTitle } from
|
|
6
|
-
import { redirectUrlOrigin } from
|
|
1
|
+
import { Languages } from "@/components/langauges";
|
|
2
|
+
import { ModeToggle } from "@/components/theme-toggle";
|
|
3
|
+
import { Alert, AlertDescription } from "@/components/ui/alert";
|
|
4
|
+
import { Button } from "@/components/ui/button";
|
|
5
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
6
|
+
import { redirectUrlOrigin } from "@/login/shared/redirectUrlOrigin";
|
|
7
7
|
import { kcSanitize } from "@keycloakify/login-ui/kcSanitize";
|
|
8
8
|
import { useKcClsx } from "@keycloakify/login-ui/useKcClsx";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
Tooltip,
|
|
11
|
+
TooltipContent,
|
|
12
|
+
TooltipProvider,
|
|
13
|
+
TooltipTrigger
|
|
14
|
+
} from "@radix-ui/react-tooltip";
|
|
10
15
|
import { useSetClassName } from "keycloakify/tools/useSetClassName";
|
|
11
|
-
import { RotateCcw } from
|
|
16
|
+
import { RotateCcw } from "lucide-react";
|
|
12
17
|
import type { ReactNode } from "react";
|
|
13
18
|
import { useEffect } from "react";
|
|
14
|
-
import { FiHome } from
|
|
19
|
+
import { FiHome } from "react-icons/fi";
|
|
15
20
|
import { useI18n } from "../../i18n";
|
|
16
21
|
import { useKcContext } from "../../KcContext";
|
|
17
22
|
import companylogo from "./../../assets/img/auth-logo.svg";
|
|
@@ -47,7 +52,6 @@ export function Template(props: {
|
|
|
47
52
|
|
|
48
53
|
const { auth, url, message, isAppInitiatedAction } = kcContext;
|
|
49
54
|
|
|
50
|
-
|
|
51
55
|
const { msg, msgStr, enabledLanguages } = useI18n();
|
|
52
56
|
|
|
53
57
|
const { kcClsx } = useKcClsx();
|
|
@@ -79,20 +83,15 @@ export function Template(props: {
|
|
|
79
83
|
<div className="flex flex-col gap-4 px-0 py-0 pb-6 lg:p-6 lg:md:p-10 lg:pt-10 min-h-screen lg:min-h-0">
|
|
80
84
|
{/* navigation */}
|
|
81
85
|
<div className="absolute top-4 right-4 lg:left-4 z-20 flex gap-2">
|
|
82
|
-
<Button variant="outline" size="icon"
|
|
86
|
+
<Button variant="outline" size="icon">
|
|
83
87
|
<a href={kcContext.client.baseUrl ?? redirectUrlOrigin}>
|
|
84
88
|
<FiHome />
|
|
85
89
|
</a>
|
|
86
90
|
</Button>
|
|
87
91
|
|
|
88
|
-
{enabledLanguages.length > 1 &&
|
|
89
|
-
<Languages />
|
|
90
|
-
)}
|
|
91
|
-
|
|
92
|
+
{enabledLanguages.length > 1 && <Languages />}
|
|
92
93
|
|
|
93
|
-
{kcContext.darkMode !== false &&
|
|
94
|
-
<ModeToggle />
|
|
95
|
-
)}
|
|
94
|
+
{kcContext.darkMode !== false && <ModeToggle />}
|
|
96
95
|
</div>
|
|
97
96
|
|
|
98
97
|
{/* Mobile header with logo */}
|
|
@@ -109,32 +108,54 @@ export function Template(props: {
|
|
|
109
108
|
<div className="flex flex-1 items-start lg:items-center justify-center lg:mt-0 ">
|
|
110
109
|
<div className="w-full max-w-xl ">
|
|
111
110
|
<Card className=" shadow-none bg-transparent lg:bg-card border-0 lg:rounded-lg lg:border lg:shadow-sm rounded-t-2xl">
|
|
112
|
-
<CardHeader className="text-center
|
|
111
|
+
<CardHeader className="text-center">
|
|
113
112
|
<CardTitle>
|
|
114
113
|
{(() => {
|
|
115
|
-
const node = !(
|
|
114
|
+
const node = !(
|
|
115
|
+
auth !== undefined &&
|
|
116
|
+
auth.showUsername &&
|
|
117
|
+
!auth.showResetCredentials
|
|
118
|
+
) ? (
|
|
116
119
|
<h1 className="text-xl">{headerNode}</h1>
|
|
117
120
|
) : (
|
|
118
|
-
<div
|
|
119
|
-
|
|
121
|
+
<div
|
|
122
|
+
id="kc-username"
|
|
123
|
+
className="flex items-center justify-center gap-2"
|
|
124
|
+
>
|
|
125
|
+
<label
|
|
126
|
+
className="font-semibold text-lg"
|
|
127
|
+
id="kc-attempted-username"
|
|
128
|
+
>
|
|
120
129
|
{auth.attemptedUsername}
|
|
121
130
|
</label>
|
|
122
131
|
|
|
123
132
|
<TooltipProvider>
|
|
124
133
|
<Tooltip>
|
|
125
134
|
<TooltipTrigger asChild>
|
|
126
|
-
<Button
|
|
135
|
+
<Button
|
|
136
|
+
variant="outline"
|
|
137
|
+
size="icon"
|
|
138
|
+
asChild
|
|
139
|
+
>
|
|
127
140
|
<a
|
|
128
141
|
id="reset-login"
|
|
129
|
-
href={
|
|
130
|
-
|
|
142
|
+
href={
|
|
143
|
+
url.loginRestartFlowUrl
|
|
144
|
+
}
|
|
145
|
+
aria-label={msgStr(
|
|
146
|
+
"restartLoginTooltip"
|
|
147
|
+
)}
|
|
131
148
|
>
|
|
132
149
|
<RotateCcw className="h-4 w-4" />
|
|
133
150
|
</a>
|
|
134
151
|
</Button>
|
|
135
152
|
</TooltipTrigger>
|
|
136
153
|
<TooltipContent>
|
|
137
|
-
<p>
|
|
154
|
+
<p>
|
|
155
|
+
{msg(
|
|
156
|
+
"restartLoginTooltip"
|
|
157
|
+
)}
|
|
158
|
+
</p>
|
|
138
159
|
</TooltipContent>
|
|
139
160
|
</Tooltip>
|
|
140
161
|
</TooltipProvider>
|
|
@@ -147,7 +168,9 @@ export function Template(props: {
|
|
|
147
168
|
<div>{node}</div>
|
|
148
169
|
<div>
|
|
149
170
|
<span className="subtitle">
|
|
150
|
-
<span className="text-red-500"
|
|
171
|
+
<span className="text-red-500">
|
|
172
|
+
*
|
|
173
|
+
</span>
|
|
151
174
|
{msg("requiredFields")}
|
|
152
175
|
</span>
|
|
153
176
|
</div>
|
|
@@ -159,42 +182,69 @@ export function Template(props: {
|
|
|
159
182
|
})()}
|
|
160
183
|
</CardTitle>
|
|
161
184
|
</CardHeader>
|
|
162
|
-
<CardContent
|
|
185
|
+
<CardContent >
|
|
163
186
|
<div id="kc-content">
|
|
164
187
|
<div id="kc-content-wrapper">
|
|
165
|
-
{displayMessage &&
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
188
|
+
{displayMessage &&
|
|
189
|
+
message !== undefined &&
|
|
190
|
+
(message.type !== "warning" ||
|
|
191
|
+
!isAppInitiatedAction) && (
|
|
192
|
+
<Alert
|
|
193
|
+
variant={message.type}
|
|
194
|
+
className="my-3"
|
|
195
|
+
>
|
|
196
|
+
<AlertDescription>
|
|
197
|
+
<div>
|
|
198
|
+
<span
|
|
199
|
+
dangerouslySetInnerHTML={{
|
|
200
|
+
__html: kcSanitize(
|
|
201
|
+
message.summary
|
|
202
|
+
)
|
|
203
|
+
}}
|
|
204
|
+
/>
|
|
205
|
+
</div>
|
|
206
|
+
</AlertDescription>
|
|
207
|
+
</Alert>
|
|
208
|
+
)}
|
|
178
209
|
<div className="children">{children}</div>
|
|
179
210
|
{socialProvidersNode}
|
|
180
|
-
{auth !== undefined &&
|
|
181
|
-
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
211
|
+
{auth !== undefined &&
|
|
212
|
+
auth.showTryAnotherWayLink && (
|
|
213
|
+
<form
|
|
214
|
+
id="kc-select-try-another-way-form"
|
|
215
|
+
action={url.loginAction}
|
|
216
|
+
method="post"
|
|
217
|
+
>
|
|
218
|
+
<div
|
|
219
|
+
className={kcClsx(
|
|
220
|
+
"kcFormGroupClass"
|
|
221
|
+
)}
|
|
191
222
|
>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
223
|
+
<input
|
|
224
|
+
type="hidden"
|
|
225
|
+
name="tryAnotherWay"
|
|
226
|
+
value="on"
|
|
227
|
+
/>
|
|
228
|
+
<a
|
|
229
|
+
href="#"
|
|
230
|
+
id="try-another-way"
|
|
231
|
+
onClick={() => {
|
|
232
|
+
document.forms[
|
|
233
|
+
"kc-select-try-another-way-form" as never
|
|
234
|
+
].submit();
|
|
235
|
+
return false;
|
|
236
|
+
}}
|
|
237
|
+
>
|
|
238
|
+
{msg("doTryAnotherWay")}
|
|
239
|
+
</a>
|
|
240
|
+
</div>
|
|
241
|
+
</form>
|
|
242
|
+
)}
|
|
243
|
+
{displayInfo && (
|
|
244
|
+
<div className="text-center text-sm mt-4">
|
|
245
|
+
{infoNode}
|
|
246
|
+
</div>
|
|
196
247
|
)}
|
|
197
|
-
{displayInfo && <div className="text-center text-sm mt-4">{infoNode}</div>}
|
|
198
248
|
</div>
|
|
199
249
|
</div>
|
|
200
250
|
</CardContent>
|
|
@@ -218,7 +268,9 @@ export function Template(props: {
|
|
|
218
268
|
<span className="text-white text-xl"> {APP_NAME}</span>
|
|
219
269
|
</div>
|
|
220
270
|
|
|
221
|
-
<p className="text-center text-gray-400 dark:text-white/60">
|
|
271
|
+
<p className="text-center text-gray-400 dark:text-white/60">
|
|
272
|
+
{msg("welcomeMessage")}
|
|
273
|
+
</p>
|
|
222
274
|
</div>
|
|
223
275
|
</div>
|
|
224
276
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Button } from
|
|
2
|
-
import { useI18n } from
|
|
1
|
+
import { Button } from "@/components/ui/button";
|
|
2
|
+
import { useI18n } from "@/login/i18n";
|
|
3
3
|
import type { Attribute } from "@keycloakify/login-ui/KcContext";
|
|
4
4
|
import {
|
|
5
5
|
getButtonToDisplayForMultivaluedAttributeField,
|
|
@@ -16,7 +16,11 @@ export function AddRemoveButtonsMultiValuedAttribute(props: {
|
|
|
16
16
|
|
|
17
17
|
const { msg } = useI18n();
|
|
18
18
|
|
|
19
|
-
const { hasAdd, hasRemove } = getButtonToDisplayForMultivaluedAttributeField({
|
|
19
|
+
const { hasAdd, hasRemove } = getButtonToDisplayForMultivaluedAttributeField({
|
|
20
|
+
attribute,
|
|
21
|
+
values,
|
|
22
|
+
fieldIndex
|
|
23
|
+
});
|
|
20
24
|
|
|
21
25
|
const idPostfix = `-${attribute.name}-${fieldIndex + 1}`;
|
|
22
26
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FieldError } from
|
|
1
|
+
import { FieldError } from "@/components/ui/field";
|
|
2
2
|
import type { Attribute } from "@keycloakify/login-ui/KcContext";
|
|
3
3
|
import type { FormFieldError } from "@keycloakify/login-ui/useUserProfileForm";
|
|
4
4
|
import { Fragment } from "react";
|
|
@@ -10,14 +10,18 @@ export function FieldErrors(props: {
|
|
|
10
10
|
}) {
|
|
11
11
|
const { attribute, fieldIndex } = props;
|
|
12
12
|
|
|
13
|
-
const displayableErrors = props.displayableErrors.filter(
|
|
13
|
+
const displayableErrors = props.displayableErrors.filter(
|
|
14
|
+
error => error.fieldIndex === fieldIndex
|
|
15
|
+
);
|
|
14
16
|
|
|
15
17
|
if (displayableErrors.length === 0) {
|
|
16
18
|
return null;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
return (
|
|
20
|
-
<FieldError
|
|
22
|
+
<FieldError
|
|
23
|
+
id={`input-error-${attribute.name}${fieldIndex === undefined ? "" : `-${fieldIndex}`}`}
|
|
24
|
+
>
|
|
21
25
|
{displayableErrors.map(({ errorMessage }, i, arr) => (
|
|
22
26
|
<Fragment key={i}>
|
|
23
27
|
{errorMessage}
|
|
@@ -26,4 +30,4 @@ export function FieldErrors(props: {
|
|
|
26
30
|
))}
|
|
27
31
|
</FieldError>
|
|
28
32
|
);
|
|
29
|
-
}
|
|
33
|
+
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { cn } from '@/components/lib/utils';
|
|
4
|
-
import { useI18n } from '@/login/i18n';
|
|
1
|
+
import { cn } from "@/components/lib/utils";
|
|
2
|
+
import { useI18n } from "@/login/i18n";
|
|
5
3
|
import type { Attribute } from "@keycloakify/login-ui/KcContext";
|
|
6
|
-
import { useKcClsx } from
|
|
4
|
+
import { useKcClsx } from "@keycloakify/login-ui/useKcClsx";
|
|
7
5
|
import { assert } from "tsafe/assert";
|
|
8
6
|
|
|
9
7
|
export function GroupLabel(props: {
|
|
@@ -18,7 +16,6 @@ export function GroupLabel(props: {
|
|
|
18
16
|
|
|
19
17
|
const { kcClsx } = useKcClsx();
|
|
20
18
|
|
|
21
|
-
|
|
22
19
|
if (attribute.group?.name !== groupNameRef.current) {
|
|
23
20
|
groupNameRef.current = attribute.group?.name ?? "";
|
|
24
21
|
|
|
@@ -27,32 +24,54 @@ export function GroupLabel(props: {
|
|
|
27
24
|
|
|
28
25
|
return (
|
|
29
26
|
<div
|
|
30
|
-
className={cn(
|
|
31
|
-
|
|
27
|
+
className={cn(
|
|
28
|
+
"space-y-4 p-4 border rounded-lg bg-card",
|
|
29
|
+
kcClsx("kcFormGroupClass")
|
|
30
|
+
)}
|
|
31
|
+
{...Object.fromEntries(
|
|
32
|
+
Object.entries(attribute.group.html5DataAnnotations).map(
|
|
33
|
+
([key, value]) => [`data-${key}`, value]
|
|
34
|
+
)
|
|
35
|
+
)}
|
|
32
36
|
>
|
|
33
37
|
{(() => {
|
|
34
38
|
const groupDisplayHeader = attribute.group.displayHeader ?? "";
|
|
35
|
-
const groupHeaderText =
|
|
39
|
+
const groupHeaderText =
|
|
40
|
+
groupDisplayHeader !== ""
|
|
41
|
+
? advancedMsg(groupDisplayHeader)
|
|
42
|
+
: attribute.group.name;
|
|
36
43
|
|
|
37
44
|
return (
|
|
38
45
|
<div className={cn("", kcClsx("kcContentWrapperClass"))}>
|
|
39
|
-
<h3
|
|
46
|
+
<h3
|
|
47
|
+
id={`header-${attribute.group.name}`}
|
|
48
|
+
className={cn(
|
|
49
|
+
"text-lg font-semibold",
|
|
50
|
+
kcClsx("kcFormGroupHeader")
|
|
51
|
+
)}
|
|
52
|
+
>
|
|
40
53
|
{groupHeaderText}
|
|
41
54
|
</h3>
|
|
42
55
|
</div>
|
|
43
56
|
);
|
|
44
57
|
})()}
|
|
45
58
|
{(() => {
|
|
46
|
-
const groupDisplayDescription =
|
|
59
|
+
const groupDisplayDescription =
|
|
60
|
+
attribute.group.displayDescription ?? "";
|
|
47
61
|
|
|
48
62
|
if (groupDisplayDescription !== "") {
|
|
49
|
-
const groupDescriptionText = advancedMsg(
|
|
63
|
+
const groupDescriptionText = advancedMsg(
|
|
64
|
+
groupDisplayDescription
|
|
65
|
+
);
|
|
50
66
|
|
|
51
67
|
return (
|
|
52
68
|
<div className={cn("", kcClsx("kcLabelWrapperClass"))}>
|
|
53
69
|
<p
|
|
54
70
|
id={`description-${attribute.group.name}`}
|
|
55
|
-
className={cn(
|
|
71
|
+
className={cn(
|
|
72
|
+
"text-sm text-muted-foreground",
|
|
73
|
+
kcClsx("kcLabelClass")
|
|
74
|
+
)}
|
|
56
75
|
>
|
|
57
76
|
{groupDescriptionText}
|
|
58
77
|
</p>
|
|
@@ -68,4 +87,4 @@ export function GroupLabel(props: {
|
|
|
68
87
|
}
|
|
69
88
|
|
|
70
89
|
return null;
|
|
71
|
-
}
|
|
90
|
+
}
|
|
@@ -23,7 +23,14 @@ export function InputFieldByType(props: InputFieldByTypeProps) {
|
|
|
23
23
|
// NOTE: Unfortunately, keycloak won't let you define input type="hidden" in the Admin Console.
|
|
24
24
|
// sometimes in the future it might.
|
|
25
25
|
case "hidden":
|
|
26
|
-
return
|
|
26
|
+
return (
|
|
27
|
+
<input
|
|
28
|
+
type="hidden"
|
|
29
|
+
id={attribute.name}
|
|
30
|
+
name={attribute.name}
|
|
31
|
+
value={valueOrValues as string}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
27
34
|
case "textarea":
|
|
28
35
|
return <TextareaTag {...props} />;
|
|
29
36
|
case "select":
|
|
@@ -56,4 +63,4 @@ export function InputFieldByType(props: InputFieldByTypeProps) {
|
|
|
56
63
|
return inputNode;
|
|
57
64
|
}
|
|
58
65
|
}
|
|
59
|
-
}
|
|
66
|
+
}
|