mirror of
https://github.com/coder/coder.git
synced 2025-04-06 12:23:57 +00:00
chore: add refresh token and error to user's external auth page (#13380)
* chore: add story for failed refresh error * chore: add refresh icon to tokens that can refresh
This commit is contained in:
@ -60,3 +60,33 @@ export const Unauthenticated: Story = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const Failed: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
auths: {
|
||||
providers: [MockGithubExternalProvider],
|
||||
links: [
|
||||
{
|
||||
...MockGithubAuthLink,
|
||||
validate_error: "Failed to refresh token",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const NoRefresh: Story = {
|
||||
args: {
|
||||
...meta.args,
|
||||
auths: {
|
||||
providers: [MockGithubExternalProvider],
|
||||
links: [
|
||||
{
|
||||
...MockGithubAuthLink,
|
||||
has_refresh_token: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1,11 +1,16 @@
|
||||
import { useTheme } from "@emotion/react";
|
||||
import AutorenewIcon from "@mui/icons-material/Autorenew";
|
||||
import LoadingButton from "@mui/lab/LoadingButton";
|
||||
import Badge from "@mui/material/Badge";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import { styled } from "@mui/material/styles";
|
||||
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 Tooltip from "@mui/material/Tooltip";
|
||||
import visuallyHidden from "@mui/utils/visuallyHidden";
|
||||
import { type FC, useState, useCallback, useEffect } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
@ -104,6 +109,25 @@ interface ExternalAuthRowProps {
|
||||
onValidateExternalAuth: () => void;
|
||||
}
|
||||
|
||||
const StyledBadge = styled(Badge)(({ theme }) => ({
|
||||
"& .MuiBadge-badge": {
|
||||
// Make a circular background for the icon. Background provides contrast, with a thin
|
||||
// border to separate it from the avatar image.
|
||||
backgroundColor: `${theme.palette.background.paper}`,
|
||||
borderStyle: "solid",
|
||||
borderColor: `${theme.palette.secondary.main}`,
|
||||
borderWidth: "thin",
|
||||
|
||||
// Override the default minimum sizes, as they are larger than what we want.
|
||||
minHeight: "0px",
|
||||
minWidth: "0px",
|
||||
// Override the default "height", which is usually set to some constant value.
|
||||
height: "auto",
|
||||
// Padding adds some room for the icon to live in.
|
||||
padding: "0.1em",
|
||||
},
|
||||
}));
|
||||
|
||||
const ExternalAuthRow: FC<ExternalAuthRowProps> = ({
|
||||
app,
|
||||
unlinked,
|
||||
@ -111,6 +135,7 @@ const ExternalAuthRow: FC<ExternalAuthRowProps> = ({
|
||||
onUnlinkExternalAuth,
|
||||
onValidateExternalAuth,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const name = app.display_name || app.id || app.type;
|
||||
const authURL = "/external-auth/" + app.id;
|
||||
|
||||
@ -125,22 +150,55 @@ const ExternalAuthRow: FC<ExternalAuthRowProps> = ({
|
||||
? externalAuth.authenticated
|
||||
: link?.authenticated ?? false;
|
||||
|
||||
let avatar = app.display_icon ? (
|
||||
<Avatar src={app.display_icon} variant="square" fitImage size="sm" />
|
||||
) : (
|
||||
<Avatar>{name}</Avatar>
|
||||
);
|
||||
|
||||
// If the link is authenticated and has a refresh token, show that it will automatically
|
||||
// attempt to authenticate when the token expires.
|
||||
if (link?.has_refresh_token && authenticated) {
|
||||
avatar = (
|
||||
<StyledBadge
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
color="default"
|
||||
overlap="circular"
|
||||
badgeContent={
|
||||
<Tooltip
|
||||
title="Authentication token will automatically refresh when expired."
|
||||
placement="right"
|
||||
>
|
||||
<AutorenewIcon
|
||||
sx={{
|
||||
fontSize: "1em",
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
{avatar}
|
||||
</StyledBadge>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow key={app.id}>
|
||||
<TableCell>
|
||||
<AvatarData
|
||||
title={name}
|
||||
avatar={
|
||||
app.display_icon && (
|
||||
<Avatar
|
||||
src={app.display_icon}
|
||||
variant="square"
|
||||
fitImage
|
||||
size="sm"
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
<AvatarData title={name} avatar={avatar} />
|
||||
{link?.validate_error && (
|
||||
<>
|
||||
<span
|
||||
css={{ paddingLeft: "1em", color: theme.palette.error.light }}
|
||||
>
|
||||
Error:{" "}
|
||||
</span>
|
||||
{link?.validate_error}
|
||||
</>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell css={{ textAlign: "right" }}>
|
||||
<LoadingButton
|
||||
|
Reference in New Issue
Block a user