mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-29 08:57:18 +02:00
Style update for User Info Endpoint (#3055)
* style changes from mui 5 * fix spacing issue on small screen * remove unneeded import * add default exports * make linter happy * more style changes * use startCase from lodash Co-authored-by: Caleb Doxsey <cdoxsey@pomerium.com>
This commit is contained in:
parent
f0843d6f44
commit
fd8ec0099e
16 changed files with 400 additions and 214 deletions
20
ui/src/components/Avatar.tsx
Normal file
20
ui/src/components/Avatar.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import React from 'react';
|
||||
import {User} from "react-feather";
|
||||
import MuiAvatar from "@mui/material/Avatar";
|
||||
|
||||
type AvatarProps = {
|
||||
name: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export const Avatar = ({url, name}:AvatarProps): JSX.Element => {
|
||||
if (url === 'https://graph.microsoft.com/v1.0/me/photo/$value') {
|
||||
url = null;
|
||||
}
|
||||
|
||||
return url ? (
|
||||
<MuiAvatar alt={name} src={url} />
|
||||
) : (
|
||||
<User />
|
||||
);
|
||||
};
|
|
@ -1,57 +0,0 @@
|
|||
import { Claims } from "../types";
|
||||
import ClaimValue from "./ClaimValue";
|
||||
import Alert from "@mui/material/Alert";
|
||||
import Table from "@mui/material/Table";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
import TableContainer from "@mui/material/TableContainer";
|
||||
import TableHead from "@mui/material/TableHead";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import React, { FC } from "react";
|
||||
|
||||
type ClaimsTableProps = {
|
||||
claims: Claims;
|
||||
};
|
||||
const ClaimsTable: FC<ClaimsTableProps> = ({ claims }) => {
|
||||
const entries = Object.entries(claims || {});
|
||||
entries.sort(([a], [b]) => a.localeCompare(b));
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell variant="head">Claims</TableCell>
|
||||
<TableCell variant="head"></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{entries.length > 0 ? (
|
||||
entries.map(([key, values]) => (
|
||||
<TableRow key={key}>
|
||||
<TableCell>{key}</TableCell>
|
||||
<TableCell>
|
||||
{values?.map((v, i) => (
|
||||
<React.Fragment key={`${v}`}>
|
||||
{i > 0 ? <br /> : <></>}
|
||||
<ClaimValue claimKey={key} claimValue={v} />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={2} padding="none">
|
||||
<Alert severity="warning" square={true}>
|
||||
No Claims Found
|
||||
</Alert>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
};
|
||||
export default ClaimsTable;
|
|
@ -8,7 +8,7 @@ type DeviceEnrolledPageProps = {
|
|||
};
|
||||
const DeviceEnrolledPage: FC<DeviceEnrolledPageProps> = () => {
|
||||
return (
|
||||
<Container>
|
||||
<Container maxWidth={false}>
|
||||
<HeroSection
|
||||
title="Device Enrolled"
|
||||
text="Device Successfully Enrolled"
|
||||
|
|
|
@ -14,7 +14,7 @@ export type ErrorPageProps = {
|
|||
};
|
||||
export const ErrorPage: FC<ErrorPageProps> = ({ data }) => {
|
||||
return (
|
||||
<Container>
|
||||
<Container maxWidth={false}>
|
||||
<Paper sx={{ overflow: "hidden" }}>
|
||||
<Stack>
|
||||
<Box sx={{ padding: "16px" }}>
|
||||
|
|
|
@ -1,39 +1,51 @@
|
|||
import Box from "@mui/material/Box";
|
||||
import Container from "@mui/material/Container";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import React, { FC } from "react";
|
||||
import {FooterLink} from "./FooterLink";
|
||||
import AppBar from "@mui/material/AppBar";
|
||||
|
||||
const Footer: FC = () => {
|
||||
return (
|
||||
<Container component="footer">
|
||||
<AppBar
|
||||
position="fixed"
|
||||
sx={{
|
||||
zIndex: (theme) => theme.zIndex.drawer + 1,
|
||||
top: 'auto',
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={2}
|
||||
spacing={8}
|
||||
justifyContent="center"
|
||||
sx={{
|
||||
fontSize: "0.85rem",
|
||||
padding: "16px"
|
||||
padding: "16px",
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<a href="https://pomerium.com/">Home</a>
|
||||
<FooterLink
|
||||
href="https://pomerium.com/"
|
||||
>
|
||||
Home
|
||||
</FooterLink>
|
||||
</Box>
|
||||
<Box>
|
||||
<a href="https://pomerium.com/docs">Docs</a>
|
||||
<FooterLink
|
||||
href="https://pomerium.com/docs"
|
||||
>
|
||||
Docs
|
||||
</FooterLink>
|
||||
</Box>
|
||||
<Box>
|
||||
<a href="https://pomerium.com/docs/community/">Support</a>
|
||||
</Box>
|
||||
<Box>
|
||||
<a href="https://github.com/pomerium">GitHub</a>
|
||||
</Box>
|
||||
<Box>
|
||||
<a href="https://twitter.com/pomerium_io">@pomerium_io</a>
|
||||
</Box>
|
||||
<Box flexGrow={1} sx={{ textAlign: "right" }}>
|
||||
© Pomerium, Inc.
|
||||
<FooterLink
|
||||
href="https://discuss.pomerium.com"
|
||||
>
|
||||
Support
|
||||
</FooterLink>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Container>
|
||||
</AppBar>
|
||||
);
|
||||
};
|
||||
export default Footer;
|
||||
|
|
10
ui/src/components/FooterLink.tsx
Normal file
10
ui/src/components/FooterLink.tsx
Normal file
|
@ -0,0 +1,10 @@
|
|||
import * as React from 'react';
|
||||
import { styled } from '@mui/system';
|
||||
import {Link} from "@mui/material";
|
||||
|
||||
export const FooterLink = styled(Link)(({ theme }) => ({
|
||||
fontSize: '1.25rem',
|
||||
fontWeight: `bold`,
|
||||
color: theme.palette.background.default,
|
||||
}));
|
||||
export default FooterLink;
|
|
@ -1,32 +1,124 @@
|
|||
import CsrfInput from "./CsrfInput";
|
||||
import Logo from "./Logo";
|
||||
import AppBar from "@mui/material/AppBar";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import Toolbar from "@mui/material/Toolbar";
|
||||
import React, { FC } from "react";
|
||||
import React, {FC, useState} from "react";
|
||||
import {useTheme} from "@mui/material/styles";
|
||||
import {Drawer, IconButton, Menu, MenuItem, useMediaQuery} from "@mui/material";
|
||||
import {ToolbarOffset} from "./ToolbarOffset";
|
||||
import UserSidebarContent from "./UserSidebarContent";
|
||||
import {ChevronLeft, ChevronRight, Menu as MenuIcon} from "react-feather";
|
||||
import styled from "@mui/material/styles/styled";
|
||||
import {Avatar} from "./Avatar";
|
||||
import {PageData} from "../types";
|
||||
import {get} from 'lodash';
|
||||
|
||||
const DrawerHeader = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
padding: theme.spacing(0, 1),
|
||||
justifyContent: 'flex-end',
|
||||
}));
|
||||
|
||||
type HeaderProps = {
|
||||
csrfToken: string;
|
||||
signOutUrl: string;
|
||||
includeSidebar: boolean;
|
||||
data: PageData;
|
||||
};
|
||||
const Header: FC<HeaderProps> = ({ csrfToken, signOutUrl }) => {
|
||||
const Header: FC<HeaderProps> = ({ includeSidebar, data }) => {
|
||||
const theme = useTheme();
|
||||
const mdUp = useMediaQuery(() => theme.breakpoints.up('md'), {
|
||||
defaultMatches: true,
|
||||
noSsr: false
|
||||
});
|
||||
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||
const handleMenuOpen = e => {
|
||||
setAnchorEl(e.currentTarget);
|
||||
};
|
||||
const handleMenuClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
const userName = get(data, 'user.name') || get(data, 'user.claims.given_name');
|
||||
|
||||
const handleDrawerOpen = () => {
|
||||
setDrawerOpen(true);
|
||||
};
|
||||
|
||||
const handleDrawerClose = ():void => {
|
||||
setDrawerOpen(false);
|
||||
};
|
||||
|
||||
const handleLogout = (evt: React.MouseEvent):void => {
|
||||
evt.preventDefault();
|
||||
location.href = "/.pomerium/sign_out";
|
||||
}
|
||||
|
||||
return (
|
||||
<AppBar position="sticky">
|
||||
<AppBar
|
||||
position="fixed"
|
||||
sx={{ zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||
>
|
||||
<Toolbar>
|
||||
<a href="/.pomerium">
|
||||
<Logo />
|
||||
</a>
|
||||
<Box flexGrow={1} />
|
||||
{signOutUrl ? (
|
||||
<form action={signOutUrl}>
|
||||
<CsrfInput csrfToken={csrfToken} />
|
||||
<Button variant="text" color="inherit" type="submit">
|
||||
Logout
|
||||
</Button>
|
||||
</form>
|
||||
{!mdUp && includeSidebar ? (
|
||||
<>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
aria-label="open drawer"
|
||||
onClick={handleDrawerOpen}
|
||||
edge="start"
|
||||
sx={{ mr: 2, ...(drawerOpen && { display: 'none' }) }}
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Drawer
|
||||
sx={{
|
||||
width: 256,
|
||||
flexShrink: 0,
|
||||
'& .MuiDrawer-paper': {
|
||||
width: 256,
|
||||
boxSizing: 'border-box',
|
||||
backgroundColor: 'neutral.900',
|
||||
height: '100vh',
|
||||
},
|
||||
}}
|
||||
variant="persistent"
|
||||
anchor="left"
|
||||
open={drawerOpen}
|
||||
>
|
||||
<DrawerHeader>
|
||||
<IconButton onClick={handleDrawerClose}>
|
||||
{theme.direction === 'ltr' ? <ChevronLeft /> : <ChevronRight />}
|
||||
</IconButton>
|
||||
</DrawerHeader>
|
||||
<UserSidebarContent close={handleDrawerClose}/>
|
||||
<ToolbarOffset />
|
||||
</Drawer>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
<a href="/.pomerium">
|
||||
<Logo />
|
||||
</a>
|
||||
)}
|
||||
<Box flexGrow={1} />
|
||||
{userName && (
|
||||
<>
|
||||
<IconButton color="inherit" onClick={handleMenuOpen}>
|
||||
<Avatar name={userName} url={get(data, 'claims.picture', null)} />
|
||||
</IconButton>
|
||||
<Menu
|
||||
onClose={handleMenuClose}
|
||||
anchorOrigin={{
|
||||
vertical: 'bottom',
|
||||
horizontal: 'center'
|
||||
}}
|
||||
keepMounted
|
||||
open={!!anchorEl}
|
||||
anchorEl={anchorEl}
|
||||
>
|
||||
<MenuItem onClick={handleLogout}>Logout</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
)}
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
|
|
|
@ -21,10 +21,10 @@ export const Section: FC<SectionProps> = ({
|
|||
<Paper sx={{ overflow: "hidden" }}>
|
||||
<Stack>
|
||||
<Toolbar>
|
||||
<Typography variant="h4" flexGrow={1}>
|
||||
<Typography variant="h4">
|
||||
{title}
|
||||
</Typography>
|
||||
{icon ? <Box>{icon}</Box> : <></>}
|
||||
{!!icon && (<Box sx={{marginLeft: (theme) => theme.spacing(3)}}>{icon}</Box>)}
|
||||
</Toolbar>
|
||||
<Box sx={{ padding: 3, paddingTop: 0 }}>{children}</Box>
|
||||
{footer ? (
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Session } from "../types";
|
||||
import ClaimsTable from "./ClaimsTable";
|
||||
import IDField from "./IDField";
|
||||
import Section from "./Section";
|
||||
import Stack from "@mui/material/Stack";
|
||||
|
@ -9,37 +8,52 @@ import TableCell from "@mui/material/TableCell";
|
|||
import TableContainer from "@mui/material/TableContainer";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import React, { FC } from "react";
|
||||
import ClaimValue from "./ClaimValue";
|
||||
import {startCase} from "lodash";
|
||||
|
||||
export type SessionDetailsProps = {
|
||||
session: Session;
|
||||
};
|
||||
export const SessionDetails: FC<SessionDetailsProps> = ({ session }) => {
|
||||
return (
|
||||
<Section title="Session Details">
|
||||
<Section title="User Details">
|
||||
<Stack spacing={3}>
|
||||
<TableContainer>
|
||||
<Table size="small">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>ID</TableCell>
|
||||
<TableCell>
|
||||
<TableCell width={'18%'} variant="head">Session ID</TableCell>
|
||||
<TableCell align="left">
|
||||
<IDField value={session?.id} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>User ID</TableCell>
|
||||
<TableCell>
|
||||
<TableCell variant="head">User ID</TableCell>
|
||||
<TableCell align="left">
|
||||
<IDField value={session?.userId} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>Expires At</TableCell>
|
||||
<TableCell>{session?.expiresAt || ""}</TableCell>
|
||||
<TableCell variant="head">Expires At</TableCell>
|
||||
<TableCell align="left">{session?.expiresAt || ""}</TableCell>
|
||||
</TableRow>
|
||||
{Object.entries(session?.claims || {}).map(
|
||||
([key, values]) => (
|
||||
<TableRow key={key}>
|
||||
<TableCell variant="head">{startCase(key)}</TableCell>
|
||||
<TableCell align="left">
|
||||
{values?.map((v, i) => (
|
||||
<React.Fragment key={`${v}`}>
|
||||
{i > 0 ? <br /> : <></>}
|
||||
<ClaimValue claimKey={key} claimValue={v} />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<ClaimsTable claims={session?.claims} />
|
||||
</Stack>
|
||||
</Section>
|
||||
);
|
||||
|
|
6
ui/src/components/ToolbarOffset.tsx
Normal file
6
ui/src/components/ToolbarOffset.tsx
Normal file
|
@ -0,0 +1,6 @@
|
|||
import styled from "@mui/material/styles/styled";
|
||||
import {BaseCSSProperties} from "@mui/material/styles/createMixins";
|
||||
|
||||
export const ToolbarOffset = styled('div')(({ theme }) => ({
|
||||
...(theme.mixins.toolbar as BaseCSSProperties),
|
||||
}));
|
|
@ -1,17 +0,0 @@
|
|||
import { User } from "../types";
|
||||
import ClaimsTable from "./ClaimsTable";
|
||||
import JwtIcon from "./JwtIcon";
|
||||
import Section from "./Section";
|
||||
import React, { FC } from "react";
|
||||
|
||||
export type UserClaimsProps = {
|
||||
user: User;
|
||||
};
|
||||
export const UserClaims: FC<UserClaimsProps> = ({ user }) => {
|
||||
return (
|
||||
<Section title="User Claims" icon={<JwtIcon />}>
|
||||
<ClaimsTable claims={user?.claims} />
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
export default UserClaims;
|
|
@ -1,53 +1,70 @@
|
|||
import GroupDetails from "./GroupDetails";
|
||||
import HeroSection from "./HeroSection";
|
||||
import PersonIcon from "./PersonIcon";
|
||||
import SessionDetails from "./SessionDetails";
|
||||
import SessionDeviceCredentials from "./SessionDeviceCredentials";
|
||||
import UserClaims from "./UserClaims";
|
||||
import MuiAvatar from "@mui/material/Avatar";
|
||||
import Container from "@mui/material/Container";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import styled from "@mui/material/styles/styled";
|
||||
import React, { FC } from "react";
|
||||
import React, {FC, useContext} from "react";
|
||||
import { UserInfoPageData } from "src/types";
|
||||
|
||||
const Avatar = styled(MuiAvatar)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
height: 48,
|
||||
width: 48
|
||||
}));
|
||||
import {Drawer, useMediaQuery} from "@mui/material";
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { ToolbarOffset } from "./ToolbarOffset";
|
||||
import {UserSidebarContent} from "./UserSidebarContent";
|
||||
import {SubpageContext} from "../context/Subpage";
|
||||
import Stack from "@mui/material/Stack";
|
||||
|
||||
type UserInfoPageProps = {
|
||||
data: UserInfoPageData;
|
||||
};
|
||||
const UserInfoPage: FC<UserInfoPageProps> = ({ data }) => {
|
||||
const name = data?.user?.claims?.given_name?.[0] || data?.user?.name;
|
||||
const theme = useTheme();
|
||||
const mdUp = useMediaQuery(() => theme.breakpoints.up('md'), {
|
||||
defaultMatches: true,
|
||||
noSsr: false
|
||||
});
|
||||
const {subpage} = useContext(SubpageContext);
|
||||
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Stack spacing={3}>
|
||||
<HeroSection
|
||||
icon={
|
||||
<Avatar>
|
||||
<PersonIcon />
|
||||
</Avatar>
|
||||
}
|
||||
title={<>Hi {name}!</>}
|
||||
text={
|
||||
<>
|
||||
Welcome to the user info endpoint. Here you can view your current
|
||||
session details, and authorization context.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<SessionDetails session={data?.session} />
|
||||
<UserClaims user={data?.user} />
|
||||
<GroupDetails groups={data?.directoryGroups} />
|
||||
<SessionDeviceCredentials
|
||||
csrfToken={data?.csrfToken}
|
||||
session={data?.session}
|
||||
user={data?.user}
|
||||
webAuthnUrl={data?.webAuthnUrl}
|
||||
/>
|
||||
<Container maxWidth={false}>
|
||||
{mdUp && (
|
||||
<Drawer
|
||||
anchor="left"
|
||||
open
|
||||
PaperProps={{
|
||||
sx: {
|
||||
backgroundColor: 'neutral.900',
|
||||
width: 256,
|
||||
height: '100vh',
|
||||
}
|
||||
}}
|
||||
variant="persistent"
|
||||
>
|
||||
<ToolbarOffset />
|
||||
<UserSidebarContent close={null}/>
|
||||
<ToolbarOffset />
|
||||
</Drawer>
|
||||
)}
|
||||
<Stack
|
||||
spacing={3}
|
||||
sx={{
|
||||
marginLeft: mdUp ? '256px' : '0px',
|
||||
}}>
|
||||
|
||||
{subpage === 'User' && (
|
||||
<SessionDetails session={data?.session} />
|
||||
)}
|
||||
|
||||
{subpage === 'Groups Info' && (
|
||||
<GroupDetails groups={data?.directoryGroups} />
|
||||
)}
|
||||
|
||||
{subpage === 'Devices Info' && (
|
||||
<SessionDeviceCredentials
|
||||
csrfToken={data?.csrfToken}
|
||||
session={data?.session}
|
||||
user={data?.user}
|
||||
webAuthnUrl={data?.webAuthnUrl}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
</Container>
|
||||
);
|
||||
|
|
55
ui/src/components/UserSidebarContent.tsx
Normal file
55
ui/src/components/UserSidebarContent.tsx
Normal file
|
@ -0,0 +1,55 @@
|
|||
import React, {FC, ReactNode, useContext} from "react";
|
||||
import {SubpageContext} from "../context/Subpage";
|
||||
import {List, ListItemButton, ListItemIcon, ListItemText} from "@mui/material";
|
||||
import {User, Users} from "react-feather";
|
||||
import {Devices} from "@mui/icons-material";
|
||||
|
||||
export interface Subpage {
|
||||
icon: ReactNode;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export const sectionList: Subpage[] = [
|
||||
{
|
||||
title: 'User',
|
||||
icon: <User />
|
||||
},
|
||||
{
|
||||
title: 'Groups Info',
|
||||
icon: <Users />
|
||||
},
|
||||
{
|
||||
title: 'Devices Info',
|
||||
icon: <Devices />
|
||||
},
|
||||
]
|
||||
type UserSidebarContent = {
|
||||
close: () => void | null;
|
||||
};
|
||||
export const UserSidebarContent:FC<UserSidebarContent> = ({close}:UserSidebarContent):JSX.Element => {
|
||||
|
||||
const info = useContext(SubpageContext);
|
||||
|
||||
return (
|
||||
<List>
|
||||
{sectionList.map(({title, icon}) => {
|
||||
return (
|
||||
<ListItemButton
|
||||
key={'tab ' + title}
|
||||
selected={title === info.subpage}
|
||||
onClick={() => {
|
||||
info.setSubpage(title)
|
||||
!!close && close();
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
{icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={title} />
|
||||
</ListItemButton>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
);
|
||||
}
|
||||
export default UserSidebarContent;
|
|
@ -6,13 +6,15 @@ import Button from "@mui/material/Button";
|
|||
import Container from "@mui/material/Container";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import React, { FC, useRef, useState } from "react";
|
||||
import {
|
||||
WebAuthnCreationOptions,
|
||||
WebAuthnRegistrationPageData,
|
||||
WebAuthnRequestOptions
|
||||
} from "src/types";
|
||||
import JwtIcon from "./JwtIcon";
|
||||
import ClaimsTable from "./ClaimsTable";
|
||||
import Section from "./Section";
|
||||
|
||||
type CredentialForAuthenticate = {
|
||||
id: string;
|
||||
|
@ -154,48 +156,39 @@ const WebAuthnRegistrationPage: FC<WebAuthnRegistrationPageProps> = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Stack spacing={3}>
|
||||
<HeroSection
|
||||
title={
|
||||
<>
|
||||
WebAuthn Registration <ExperimentalIcon />
|
||||
</>
|
||||
}
|
||||
<Section title="WebAuthn Registration" icon={<ExperimentalIcon />}>
|
||||
<Paper sx={{ padding: "16px" }}>
|
||||
<Stack direction="row" justifyContent="center" spacing={3}>
|
||||
<Button onClick={handleClickRegister} variant="contained">
|
||||
Register New Device
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleClickAuthenticate}
|
||||
variant="contained"
|
||||
disabled={!enableAuthenticate}
|
||||
>
|
||||
Authenticate Existing Device
|
||||
</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<form ref={authenticateFormRef} method="post" action={data?.selfUrl}>
|
||||
<input type="hidden" name="_pomerium_csrf" value={data?.csrfToken} />
|
||||
<input type="hidden" name="action" value="authenticate" />
|
||||
<input
|
||||
type="hidden"
|
||||
name="authenticate_response"
|
||||
ref={authenticateResponseRef}
|
||||
/>
|
||||
<Paper sx={{ padding: "16px" }}>
|
||||
<Stack direction="row" justifyContent="center" spacing={3}>
|
||||
<Button onClick={handleClickRegister} variant="contained">
|
||||
Register New Device
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleClickAuthenticate}
|
||||
variant="contained"
|
||||
disabled={!enableAuthenticate}
|
||||
>
|
||||
Authenticate Existing Device
|
||||
</Button>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<form ref={authenticateFormRef} method="post" action={data?.selfUrl}>
|
||||
<input type="hidden" name="_pomerium_csrf" value={data?.csrfToken} />
|
||||
<input type="hidden" name="action" value="authenticate" />
|
||||
<input
|
||||
type="hidden"
|
||||
name="authenticate_response"
|
||||
ref={authenticateResponseRef}
|
||||
/>
|
||||
</form>
|
||||
<form ref={registerFormRef} method="POST" action={data?.selfUrl}>
|
||||
<input type="hidden" name="_pomerium_csrf" value={data?.csrfToken} />
|
||||
<input type="hidden" name="action" value="register" />
|
||||
<input
|
||||
type="hidden"
|
||||
name="register_response"
|
||||
ref={registerResponseRef}
|
||||
/>
|
||||
</form>
|
||||
</Stack>
|
||||
</form>
|
||||
<form ref={registerFormRef} method="POST" action={data?.selfUrl}>
|
||||
<input type="hidden" name="_pomerium_csrf" value={data?.csrfToken} />
|
||||
<input type="hidden" name="action" value="register" />
|
||||
<input
|
||||
type="hidden"
|
||||
name="register_response"
|
||||
ref={registerResponseRef}
|
||||
/>
|
||||
</form>
|
||||
<AlertDialog
|
||||
title="Error"
|
||||
severity="error"
|
||||
|
@ -204,7 +197,7 @@ const WebAuthnRegistrationPage: FC<WebAuthnRegistrationPageProps> = ({
|
|||
>
|
||||
{error}
|
||||
</AlertDialog>
|
||||
</Container>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
export default WebAuthnRegistrationPage;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue