mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: show dormant and suspended users in groups (#10333)
* fix: show dormant and suspended users in groups * added status column
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import Box, { type BoxProps } from "@mui/material/Box";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export const LastSeen = ({
|
||||
value,
|
||||
...boxProps
|
||||
}: { value: string } & BoxProps) => {
|
||||
const theme = useTheme();
|
||||
const t = dayjs(value);
|
||||
const now = dayjs();
|
||||
|
||||
let message = t.fromNow();
|
||||
let color = theme.palette.text.secondary;
|
||||
|
||||
if (t.isAfter(now.subtract(1, "hour"))) {
|
||||
color = theme.palette.success.light;
|
||||
// Since the agent reports on a 10m interval,
|
||||
// the last_used_at can be inaccurate when recent.
|
||||
message = "Now";
|
||||
} else if (t.isAfter(now.subtract(3, "day"))) {
|
||||
color = theme.palette.text.secondary;
|
||||
} else if (t.isAfter(now.subtract(1, "month"))) {
|
||||
color = theme.palette.warning.light;
|
||||
} else if (t.isAfter(now.subtract(100, "year"))) {
|
||||
color = theme.palette.error.light;
|
||||
} else {
|
||||
message = "Never";
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="span"
|
||||
data-chromatic="ignore"
|
||||
{...boxProps}
|
||||
sx={{ color, ...boxProps.sx }}
|
||||
>
|
||||
{message}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -43,6 +43,9 @@ import {
|
||||
} from "api/queries/groups";
|
||||
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
|
||||
import { getErrorMessage } from "api/errors";
|
||||
import Box from "@mui/material/Box";
|
||||
import { LastSeen } from "components/LastSeen/LastSeen";
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import LoadingButton from "@mui/lab/LoadingButton";
|
||||
|
||||
export const GroupPage: FC = () => {
|
||||
@@ -150,7 +153,8 @@ export const GroupPage: FC = () => {
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell width="99%">User</TableCell>
|
||||
<TableCell width="59%">User</TableCell>
|
||||
<TableCell width="40">Status</TableCell>
|
||||
<TableCell width="1%"></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
@@ -259,7 +263,7 @@ const GroupMemberRow = (props: {
|
||||
|
||||
return (
|
||||
<TableRow key={member.id}>
|
||||
<TableCell width="99%">
|
||||
<TableCell width="59%">
|
||||
<AvatarData
|
||||
avatar={
|
||||
<UserAvatar
|
||||
@@ -271,6 +275,13 @@ const GroupMemberRow = (props: {
|
||||
subtitle={member.email}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell
|
||||
width="40%"
|
||||
css={[styles.status, member.status === "suspended" && styles.suspended]}
|
||||
>
|
||||
<Box>{member.status}</Box>
|
||||
<LastSeen value={member.last_seen_at} sx={{ fontSize: 12 }} />
|
||||
</TableCell>
|
||||
<TableCell width="1%">
|
||||
{canUpdate && (
|
||||
<TableRowMenu
|
||||
@@ -313,4 +324,13 @@ const useStyles = makeStyles((theme) => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const styles = {
|
||||
status: {
|
||||
textTransform: "capitalize",
|
||||
},
|
||||
suspended: (theme) => ({
|
||||
color: theme.palette.text.secondary,
|
||||
}),
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
|
||||
export default GroupPage;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Box, { type BoxProps } from "@mui/material/Box";
|
||||
import Box from "@mui/material/Box";
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import Skeleton from "@mui/material/Skeleton";
|
||||
import { type Interpolation, type Theme, useTheme } from "@emotion/react";
|
||||
import { type Interpolation, type Theme } from "@emotion/react";
|
||||
import { type FC } from "react";
|
||||
import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
@@ -22,6 +22,7 @@ import KeyOutlined from "@mui/icons-material/KeyOutlined";
|
||||
import GitHub from "@mui/icons-material/GitHub";
|
||||
import PasswordOutlined from "@mui/icons-material/PasswordOutlined";
|
||||
import ShieldOutlined from "@mui/icons-material/ShieldOutlined";
|
||||
import { LastSeen } from "components/LastSeen/LastSeen";
|
||||
import { UserRoleCell } from "./UserRoleCell";
|
||||
import { type GroupsByUserId } from "api/queries/groups";
|
||||
import { UserGroupsCell } from "./UserGroupsCell";
|
||||
@@ -273,41 +274,6 @@ const LoginType = ({
|
||||
);
|
||||
};
|
||||
|
||||
const LastSeen = ({ value, ...boxProps }: { value: string } & BoxProps) => {
|
||||
const theme = useTheme();
|
||||
const t = dayjs(value);
|
||||
const now = dayjs();
|
||||
|
||||
let message = t.fromNow();
|
||||
let color = theme.palette.text.secondary;
|
||||
|
||||
if (t.isAfter(now.subtract(1, "hour"))) {
|
||||
color = theme.palette.success.light;
|
||||
// Since the agent reports on a 10m interval,
|
||||
// the last_used_at can be inaccurate when recent.
|
||||
message = "Now";
|
||||
} else if (t.isAfter(now.subtract(3, "day"))) {
|
||||
color = theme.palette.text.secondary;
|
||||
} else if (t.isAfter(now.subtract(1, "month"))) {
|
||||
color = theme.palette.warning.light;
|
||||
} else if (t.isAfter(now.subtract(100, "year"))) {
|
||||
color = theme.palette.error.light;
|
||||
} else {
|
||||
message = "Never";
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="span"
|
||||
data-chromatic="ignore"
|
||||
{...boxProps}
|
||||
sx={{ color, ...boxProps.sx }}
|
||||
>
|
||||
{message}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = {
|
||||
status: {
|
||||
textTransform: "capitalize",
|
||||
|
||||
Reference in New Issue
Block a user