mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
fix: remove @mui/* dependencies from <TemplateInsightsPage /> (#21993)
This pull-request looks at various components within `<TemplatesInsightsPage />` and ensures that they aren't using the MUI variants of components.
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
import Menu from "@mui/material/Menu";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import { Button } from "components/Button/Button";
|
||||
import { CheckIcon, ChevronDownIcon } from "lucide-react";
|
||||
import { type FC, useRef, useState } from "react";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "components/DropdownMenu/DropdownMenu";
|
||||
import { ChevronDownIcon } from "lucide-react";
|
||||
import type { FC } from "react";
|
||||
|
||||
const insightsIntervals = {
|
||||
day: {
|
||||
@@ -21,62 +26,26 @@ interface IntervalMenuProps {
|
||||
}
|
||||
|
||||
export const IntervalMenu: FC<IntervalMenuProps> = ({ value, onChange }) => {
|
||||
const anchorRef = useRef<HTMLButtonElement>(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
ref={anchorRef}
|
||||
id="interval-button"
|
||||
aria-controls={open ? "interval-menu" : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={open ? "true" : undefined}
|
||||
onClick={() => setOpen(true)}
|
||||
variant="outline"
|
||||
>
|
||||
{insightsIntervals[value].label}
|
||||
<ChevronDownIcon className="size-icon-xs ml-1" />
|
||||
</Button>
|
||||
<Menu
|
||||
id="interval-menu"
|
||||
anchorEl={anchorRef.current}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
"aria-labelledby": "interval-button",
|
||||
}}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "left",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
>
|
||||
{Object.entries(insightsIntervals).map(([interval, { label }]) => {
|
||||
return (
|
||||
<MenuItem
|
||||
css={{ fontSize: 14, justifyContent: "space-between" }}
|
||||
key={interval}
|
||||
onClick={() => {
|
||||
onChange(interval as InsightsInterval);
|
||||
handleClose();
|
||||
}}
|
||||
>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">
|
||||
{insightsIntervals[value].label}
|
||||
<ChevronDownIcon className="!size-icon-xs" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuRadioGroup
|
||||
value={value}
|
||||
onValueChange={(v) => onChange(v as InsightsInterval)}
|
||||
>
|
||||
{Object.entries(insightsIntervals).map(([interval, { label }]) => (
|
||||
<DropdownMenuRadioItem key={interval} value={interval}>
|
||||
{label}
|
||||
<div css={{ width: 16, height: 16 }}>
|
||||
{value === interval && <CheckIcon className="size-icon-xs" />}
|
||||
</div>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
</div>
|
||||
</DropdownMenuRadioItem>
|
||||
))}
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { useTheme } from "@emotion/react";
|
||||
import LinearProgress from "@mui/material/LinearProgress";
|
||||
import Link from "@mui/material/Link";
|
||||
import { getErrorDetail, getErrorMessage } from "api/errors";
|
||||
import {
|
||||
insightsTemplate,
|
||||
@@ -29,6 +26,7 @@ import {
|
||||
HelpTooltipText,
|
||||
HelpTooltipTitle,
|
||||
} from "components/HelpTooltip/HelpTooltip";
|
||||
import { Link } from "components/Link/Link";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
import {
|
||||
@@ -37,11 +35,7 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "components/Tooltip/Tooltip";
|
||||
import {
|
||||
CircleCheck as CircleCheckIcon,
|
||||
CircleXIcon,
|
||||
LinkIcon,
|
||||
} from "lucide-react";
|
||||
import { CircleCheck as CircleCheckIcon, CircleXIcon } from "lucide-react";
|
||||
import { useTemplateLayoutContext } from "pages/TemplatePage/TemplateLayout";
|
||||
import {
|
||||
type FC,
|
||||
@@ -396,15 +390,23 @@ const TemplateUsagePanel: FC<TemplateUsagePanelProps> = ({
|
||||
className,
|
||||
...panelProps
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
// The API returns a row for each app, even if the user didn't use it.
|
||||
const validUsage = data
|
||||
?.filter((u) => u.seconds > 0)
|
||||
.sort((a, b) => b.seconds - a.seconds);
|
||||
const totalInSeconds =
|
||||
validUsage?.reduce((total, usage) => total + usage.seconds, 0) ?? 1;
|
||||
const style = getComputedStyle(document.documentElement);
|
||||
const successHsl = style
|
||||
.getPropertyValue("--content-success")
|
||||
.trim()
|
||||
.replace(/ /g, ", ");
|
||||
const warningHsl = style
|
||||
.getPropertyValue("--content-warning")
|
||||
.trim()
|
||||
.replace(/ /g, ", ");
|
||||
const usageColors = chroma
|
||||
.scale([theme.roles.success.fill.solid, theme.roles.warning.fill.solid])
|
||||
.scale([`hsl(${successHsl})`, `hsl(${warningHsl})`])
|
||||
.mode("lch")
|
||||
.colors(validUsage?.length ?? 0);
|
||||
|
||||
@@ -434,17 +436,15 @@ const TemplateUsagePanel: FC<TemplateUsagePanelProps> = ({
|
||||
</div>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<LinearProgress
|
||||
value={percentage}
|
||||
variant="determinate"
|
||||
className="w-full h-2 bg-surface-quaternary"
|
||||
css={{
|
||||
"& .MuiLinearProgress-bar": {
|
||||
<div className="relative w-full h-2 rounded-full bg-surface-quaternary">
|
||||
<div
|
||||
className="absolute inset-y-0 left-0 rounded-full"
|
||||
style={{
|
||||
width: `${percentage}%`,
|
||||
backgroundColor: usageColors[i],
|
||||
borderRadius: 999,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{Math.floor(percentage)}%
|
||||
@@ -497,12 +497,7 @@ const TemplateParametersUsagePanel: FC<TemplateParametersUsagePanelProps> = ({
|
||||
return (
|
||||
<div
|
||||
key={parameter.name}
|
||||
className="flex items-start gap-6 border-0 border-t border-solid border-surface-quaternary p-6 -mx-6"
|
||||
css={{
|
||||
"&:first-of-type": {
|
||||
borderTop: 0,
|
||||
},
|
||||
}}
|
||||
className="flex items-start gap-6 border-0 border-t border-solid border-surface-quaternary p-6 -mx-6 first:border-t-0"
|
||||
>
|
||||
<div className="flex-1">
|
||||
<div className="font-medium">{label}</div>
|
||||
@@ -603,14 +598,8 @@ const ParameterUsageLabel: FC<ParameterUsageLabelProps> = ({
|
||||
|
||||
if (usage.value.startsWith("http")) {
|
||||
return (
|
||||
<Link
|
||||
href={usage.value}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="flex items-center gap-[1px] text-content-primary"
|
||||
>
|
||||
<Link href={usage.value} target="_blank" rel="noreferrer">
|
||||
<TextValue>{usage.value}</TextValue>
|
||||
<LinkIcon className="size-icon-xs text-content-link" />
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import Menu from "@mui/material/Menu";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import { Button } from "components/Button/Button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "components/DropdownMenu/DropdownMenu";
|
||||
import dayjs from "dayjs";
|
||||
import { CheckIcon, ChevronDownIcon } from "lucide-react";
|
||||
import { type FC, useRef, useState } from "react";
|
||||
import { ChevronDownIcon } from "lucide-react";
|
||||
import type { FC } from "react";
|
||||
import type { DateRangeValue } from "./DateRange";
|
||||
import { lastWeeks } from "./utils";
|
||||
|
||||
@@ -17,70 +22,31 @@ interface WeekPickerProps {
|
||||
}
|
||||
|
||||
export const WeekPicker: FC<WeekPickerProps> = ({ value, onChange }) => {
|
||||
const anchorRef = useRef<HTMLButtonElement>(null);
|
||||
const [open, setOpen] = useState(false);
|
||||
const numberOfWeeks = dayjs(value.endDate).diff(
|
||||
dayjs(value.startDate),
|
||||
"week",
|
||||
);
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
variant="outline"
|
||||
ref={anchorRef}
|
||||
id="interval-button"
|
||||
aria-controls={open ? "interval-menu" : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={open ? "true" : undefined}
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
Last {numberOfWeeks} weeks
|
||||
<ChevronDownIcon />
|
||||
</Button>
|
||||
<Menu
|
||||
id="interval-menu"
|
||||
anchorEl={anchorRef.current}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
MenuListProps={{
|
||||
"aria-labelledby": "interval-button",
|
||||
}}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "left",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
>
|
||||
{numberOfWeeksOptions.map((option) => {
|
||||
const optionRange = lastWeeks(option);
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
css={{ fontSize: 14, justifyContent: "space-between" }}
|
||||
key={option}
|
||||
onClick={() => {
|
||||
onChange(optionRange);
|
||||
handleClose();
|
||||
}}
|
||||
>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">
|
||||
Last {numberOfWeeks} weeks
|
||||
<ChevronDownIcon className="!size-icon-xs" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start">
|
||||
<DropdownMenuRadioGroup
|
||||
value={String(numberOfWeeks)}
|
||||
onValueChange={(v) => onChange(lastWeeks(Number(v)))}
|
||||
>
|
||||
{numberOfWeeksOptions.map((option) => (
|
||||
<DropdownMenuRadioItem key={option} value={String(option)}>
|
||||
Last {option} weeks
|
||||
<div css={{ width: 16, height: 16 }}>
|
||||
{numberOfWeeks === option && (
|
||||
<CheckIcon className="size-icon-xs" />
|
||||
)}
|
||||
</div>
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
</div>
|
||||
</DropdownMenuRadioItem>
|
||||
))}
|
||||
</DropdownMenuRadioGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user