chore: upgrade to react 19 (#19829)

This commit is contained in:
ケイラ
2025-09-16 13:37:30 -06:00
committed by GitHub
parent 422bba44d9
commit 8db82d25b3
44 changed files with 773 additions and 752 deletions
+4 -4
View File
@@ -94,11 +94,11 @@
"lucide-react": "0.474.0",
"monaco-editor": "0.52.2",
"pretty-bytes": "6.1.1",
"react": "18.3.1",
"react": "19.1.1",
"react-color": "2.19.3",
"react-confetti": "6.2.2",
"react-date-range": "1.4.0",
"react-dom": "18.3.1",
"react-dom": "19.1.1",
"react-helmet-async": "2.0.5",
"react-markdown": "9.0.3",
"react-query": "npm:@tanstack/react-query@5.77.0",
@@ -146,10 +146,10 @@
"@types/jest": "29.5.14",
"@types/lodash": "4.17.15",
"@types/node": "20.17.16",
"@types/react": "18.3.12",
"@types/react": "19.1.13",
"@types/react-color": "3.0.13",
"@types/react-date-range": "1.4.4",
"@types/react-dom": "18.3.1",
"@types/react-dom": "19.1.9",
"@types/react-syntax-highlighter": "15.5.13",
"@types/react-virtualized-auto-sizer": "1.0.4",
"@types/react-window": "1.8.8",
+703 -705
View File
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,7 @@
import {
Children,
type FC,
type JSX,
type PropsWithChildren,
type ReactNode,
} from "react";
@@ -1,7 +1,7 @@
import { renderComponent } from "testHelpers/renderHelpers";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { act } from "react-dom/test-utils";
import { act } from "react";
import { DeleteDialog } from "./DeleteDialog";
const inputTestId = "delete-dialog-name-confirmation";
+2
View File
@@ -1,5 +1,7 @@
import SvgIcon, { type SvgIconProps } from "@mui/material/SvgIcon";
import type { JSX } from "react";
export const DockerIcon = (props: SvgIconProps): JSX.Element => (
<SvgIcon {...props} viewBox="0 0 32 32">
<path
+2
View File
@@ -1,5 +1,7 @@
import SvgIcon, { type SvgIconProps } from "@mui/material/SvgIcon";
import type { JSX } from "react";
export const EditSquare = (props: SvgIconProps): JSX.Element => (
<SvgIcon {...props} viewBox="0 0 48 48">
<path d="M9 47.4q-1.2 0-2.1-.9-.9-.9-.9-2.1v-30q0-1.2.9-2.1.9-.9 2.1-.9h20.25l-3 3H9v30h30V27l3-3v20.4q0 1.2-.9 2.1-.9.9-2.1.9Zm15-18Zm9.1-17.6 2.15 2.1L21 28.1v4.3h4.25l14.3-14.3 2.1 2.1L26.5 35.4H18v-8.5Zm8.55 8.4-8.55-8.4 5-5q.85-.85 2.125-.85t2.125.9l4.2 4.25q.85.9.85 2.125t-.9 2.075Z" />
+2
View File
@@ -1,5 +1,7 @@
import SvgIcon, { type SvgIconProps } from "@mui/material/SvgIcon";
import type { JSX } from "react";
export const ErrorIcon = (props: SvgIconProps): JSX.Element => (
<SvgIcon {...props} viewBox="0 0 24 24">
<path
+2
View File
@@ -1,5 +1,7 @@
import SvgIcon, { type SvgIconProps } from "@mui/material/SvgIcon";
import type { JSX } from "react";
export const GitIcon = (props: SvgIconProps): JSX.Element => (
<SvgIcon {...props} viewBox="0 0 96 96">
<path d="M92.71 44.408 52.591 4.291c-2.31-2.311-6.057-2.311-8.369 0l-8.33 8.332L46.459 23.19c2.456-.83 5.272-.273 7.229 1.685 1.969 1.97 2.521 4.81 1.67 7.275l10.186 10.185c2.465-.85 5.307-.3 7.275 1.671 2.75 2.75 2.75 7.206 0 9.958-2.752 2.751-7.208 2.751-9.961 0-2.068-2.07-2.58-5.11-1.531-7.658l-9.5-9.499v24.997c.67.332 1.303.774 1.861 1.332 2.75 2.75 2.75 7.206 0 9.959-2.75 2.749-7.209 2.749-9.957 0-2.75-2.754-2.75-7.21 0-9.959.68-.679 1.467-1.193 2.307-1.537v-25.23c-.84-.344-1.625-.853-2.307-1.537-2.083-2.082-2.584-5.14-1.516-7.698L31.798 16.715 4.288 44.222c-2.311 2.313-2.311 6.06 0 8.371l40.121 40.118c2.31 2.311 6.056 2.311 8.369 0L92.71 52.779c2.311-2.311 2.311-6.06 0-8.371z" />
@@ -1,5 +1,7 @@
import SvgIcon, { type SvgIconProps } from "@mui/material/SvgIcon";
import type { JSX } from "react";
export const JetBrainsIcon = (props: SvgIconProps): JSX.Element => (
<SvgIcon {...props} viewBox="0 0 100 100">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180" width="180">
+2
View File
@@ -1,5 +1,7 @@
import SvgIcon, { type SvgIconProps } from "@mui/material/SvgIcon";
import type { JSX } from "react";
export const RocketIcon = (props: SvgIconProps): JSX.Element => (
<SvgIcon {...props} viewBox="0 0 24 24">
<path d="M12 2.5s4.5 2.04 4.5 10.5c0 2.49-1.04 5.57-1.6 7H9.1c-.56-1.43-1.6-4.51-1.6-7C7.5 4.54 12 2.5 12 2.5zm2 8.5c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2zm-6.31 9.52c-.48-1.23-1.52-4.17-1.67-6.87l-1.13.75c-.56.38-.89 1-.89 1.67V22l3.69-1.48zM20 22v-5.93c0-.67-.33-1.29-.89-1.66l-1.13-.75c-.15 2.69-1.2 5.64-1.67 6.87L20 22z" />
@@ -1,5 +1,7 @@
import SvgIcon, { type SvgIconProps } from "@mui/material/SvgIcon";
import type { JSX } from "react";
export const TerminalIcon = (props: SvgIconProps): JSX.Element => (
<SvgIcon {...props} viewBox="0 0 24 24">
<path d="M20 4H4c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm0 14H4V8h16v10zm-2-1h-6v-2h6v2zM7.5 17l-1.41-1.41L8.67 13l-2.59-2.59L7.5 9l4 4-4 4z" />
+2
View File
@@ -1,5 +1,7 @@
import SvgIcon, { type SvgIconProps } from "@mui/material/SvgIcon";
import type { JSX } from "react";
export const VSCodeIcon = (props: SvgIconProps): JSX.Element => (
<SvgIcon {...props} viewBox="0 0 100 100">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="none">
@@ -1,5 +1,7 @@
import SvgIcon, { type SvgIconProps } from "@mui/material/SvgIcon";
import type { JSX } from "react";
export const VSCodeInsidersIcon = (props: SvgIconProps): JSX.Element => (
<SvgIcon {...props} viewBox="0 0 256 256">
<svg
+1 -1
View File
@@ -1,4 +1,4 @@
import type { FC } from "react";
import type { FC, JSX } from "react";
import {
containerWidth,
containerWidthMedium,
+2 -4
View File
@@ -13,7 +13,7 @@ import {
type HTMLProps,
isValidElement,
memo,
type ReactElement,
type PropsWithChildren,
type ReactNode,
} from "react";
import ReactMarkdown, { type Options } from "react-markdown";
@@ -251,9 +251,7 @@ function parseChildrenAsAlertContent(
return null;
}
const mainParentNode = jsxChildren.find((node): node is ReactElement =>
isValidElement(node),
);
const mainParentNode = jsxChildren.find(isValidElement<PropsWithChildren>);
let parentChildren = mainParentNode?.props.children;
if (typeof parentChildren === "string") {
// Children will only be an array if the parsed text contains other
+2 -2
View File
@@ -45,9 +45,9 @@ export const Pill: FC<PillProps> = forwardRef<HTMLDivElement, PillProps>(
ref={ref}
css={[
styles.pill,
icon && size === "md" && styles.pillWithIcon,
Boolean(icon) && size === "md" && styles.pillWithIcon,
size === "lg" && styles.pillLg,
icon && size === "lg" && styles.pillLgWithIcon,
Boolean(icon) && size === "lg" && styles.pillLgWithIcon,
typeStyles,
]}
{...divProps}
+1 -1
View File
@@ -1,5 +1,5 @@
import { TimelineDateRow } from "components/Timeline/TimelineDateRow";
import { Fragment } from "react";
import { Fragment, type JSX } from "react";
type GetDateFn<TData> = (data: TData) => Date;
@@ -21,7 +21,7 @@ import {
type TriggerMode = "hover" | "click";
type TriggerRef = RefObject<HTMLElement>;
type TriggerRef = RefObject<HTMLElement | null>;
// Have to append ReactNode type to satisfy React's cloneElement function. It
// has absolutely no bearing on what happens at runtime
@@ -146,6 +146,8 @@ export const PopoverTrigger: FC<PopoverTriggerProps> = (props) => {
return cloneElement(evaluatedChildren, {
...elementProps,
...(popover.mode === "click" ? clickProps : hoverProps),
// @ts-expect-error I would usually not hack around this, but this component
// is going to be deleted imminently.
"aria-haspopup": true,
"aria-owns": popover.id,
"aria-expanded": popover.open,
+1 -1
View File
@@ -23,7 +23,7 @@ export type UseClickableResult<
TElement extends ClickableElement = ClickableElement,
TRole extends ClickableAriaRole = ClickableAriaRole,
> = Readonly<{
ref: RefObject<TElement>;
ref: RefObject<TElement | null>;
tabIndex: 0;
role: TRole;
onClick: MouseEventHandler<TElement>;
+1 -1
View File
@@ -44,7 +44,7 @@ export const useClipboard = (input: UseClipboardInput): UseClipboardResult => {
const { textToCopy, onError: errorCallback } = input;
const [showCopiedSuccess, setShowCopiedSuccess] = useState(false);
const [error, setError] = useState<Error>();
const timeoutIdRef = useRef<number | undefined>();
const timeoutIdRef = useRef<number | undefined>(undefined);
useEffect(() => {
const clearIdOnUnmount = () => window.clearTimeout(timeoutIdRef.current);
+1 -1
View File
@@ -9,7 +9,7 @@ export const useWorkspaceBuildLogs = (
enabled = true,
) => {
const [logs, setLogs] = useState<ProvisionerJobLog[]>();
const socket = useRef<WebSocket>();
const socket = useRef<WebSocket>(undefined);
useEffect(() => {
if (!buildId || !enabled) {
@@ -22,7 +22,7 @@ import {
MonitorDownIcon,
SquareArrowOutUpRightIcon,
} from "lucide-react";
import type { FC } from "react";
import type { FC, JSX } from "react";
import { Link } from "react-router";
export const Language = {
@@ -2,7 +2,7 @@ import type { Interpolation, Theme } from "@emotion/react";
import Tooltip from "@mui/material/Tooltip";
import type { WorkspaceAgentLogSource } from "api/typesGenerated";
import type { Line } from "components/Logs/LogLine";
import { type ComponentProps, forwardRef, useMemo } from "react";
import { type ComponentProps, forwardRef, type JSX, useMemo } from "react";
import { FixedSizeList as List } from "react-window";
import { AGENT_LOG_LINE_HEIGHT, AgentLogLine } from "./AgentLogLine";
+1 -1
View File
@@ -6,7 +6,7 @@ import { CopyableValue } from "components/CopyableValue/CopyableValue";
import { DropdownArrow } from "components/DropdownArrow/DropdownArrow";
import { MemoizedInlineMarkdown } from "components/Markdown/Markdown";
import { Stack } from "components/Stack/Stack";
import { Children, type FC, useState } from "react";
import { Children, type FC, type JSX, useState } from "react";
import { ResourceAvatar } from "./ResourceAvatar";
import { SensitiveValue } from "./SensitiveValue";
+1 -1
View File
@@ -2,7 +2,7 @@ import Button from "@mui/material/Button";
import type { WorkspaceAgent, WorkspaceResource } from "api/typesGenerated";
import { DropdownArrow } from "components/DropdownArrow/DropdownArrow";
import { Stack } from "components/Stack/Stack";
import { type FC, useState } from "react";
import { type FC, type JSX, useState } from "react";
import { ResourceCard } from "./ResourceCard";
const countAgents = (resource: WorkspaceResource) => {
@@ -6,7 +6,13 @@ import MenuItem from "@mui/material/MenuItem";
import { SimpleTreeView, TreeItem } from "@mui/x-tree-view";
import { DockerIcon } from "components/Icons/DockerIcon";
import { ChevronRightIcon } from "lucide-react";
import { type CSSProperties, type ElementType, type FC, useState } from "react";
import {
type CSSProperties,
type ElementType,
type FC,
type JSX,
useState,
} from "react";
import type { FileTree } from "utils/filetree";
const isFolder = (content?: FileTree | string): content is FileTree =>
@@ -266,7 +266,7 @@ const DebouncedParameterField: FC<DebouncedParameterFieldProps> = ({
const debouncedLocalValue = useDebouncedValue(localValue, 500);
const onChangeEvent = useEffectEvent(onChange);
// prevDebouncedValueRef is to prevent calling the onChangeEvent on the initial render
const prevDebouncedValueRef = useRef<string | undefined>();
const prevDebouncedValueRef = useRef<string | undefined>(undefined);
const prevValueRef = useRef(value);
// Necessary for dynamic defaults or fields being set by preset parameters
@@ -19,7 +19,7 @@ type BuildLogsDrawerProps = {
open: boolean;
onClose: () => void;
templateVersion: TemplateVersion | undefined;
variablesSectionRef: React.RefObject<HTMLDivElement>;
variablesSectionRef: React.RefObject<HTMLDivElement | null>;
};
export const BuildLogsDrawer: FC<BuildLogsDrawerProps> = ({
@@ -186,7 +186,7 @@ type CreateTemplateFormProps = (
jobError?: string;
logs?: ProvisionerJobLog[];
allowAdvancedScheduling: boolean;
variablesSectionRef: React.RefObject<HTMLDivElement>;
variablesSectionRef: React.RefObject<HTMLDivElement | null>;
showOrganizationPicker?: boolean;
};
+1 -1
View File
@@ -3,7 +3,7 @@ import type { CreateTemplateOptions } from "api/queries/templates";
export type CreateTemplatePageViewProps = {
onCreateTemplate: (options: CreateTemplateOptions) => Promise<void>;
onOpenBuildLogsDrawer: () => void;
variablesSectionRef: React.RefObject<HTMLDivElement>;
variablesSectionRef: React.RefObject<HTMLDivElement | null>;
error: unknown;
isCreating: boolean;
};
@@ -1,6 +1,6 @@
import { type CSSObject, useTheme } from "@emotion/react";
import { Button } from "components/Button/Button";
import type { FC, FormEventHandler, ReactNode } from "react";
import type { FC, FormEventHandler, JSX, ReactNode } from "react";
interface FieldsetProps {
children: ReactNode;
@@ -7,6 +7,7 @@ import {
SettingsHeaderTitle,
} from "components/SettingsHeader/SettingsHeader";
import { Stack } from "components/Stack/Stack";
import type { JSX } from "react";
import {
deploymentGroupHasParent,
useDeploymentOptions,
+1 -1
View File
@@ -39,7 +39,7 @@ const AccessURLPage = () => {
{accessUrl.warnings.map((warning) => {
return (
<Alert
actions={HealthMessageDocsLink(warning)}
actions={<HealthMessageDocsLink {...warning} />}
key={warning.code}
severity="warning"
>
+2 -3
View File
@@ -1,4 +1,3 @@
import { css } from "@emotion/css";
import { useTheme } from "@emotion/react";
import Link from "@mui/material/Link";
import type { HealthCode, HealthSeverity } from "api/typesGenerated";
@@ -157,7 +156,7 @@ export const SectionLabel: FC<HTMLAttributes<HTMLHeadingElement>> = (props) => {
};
type PillProps = HTMLAttributes<HTMLDivElement> & {
icon: ReactElement;
icon: ReactElement<HTMLAttributes<HTMLElement>>;
};
export const Pill = forwardRef<HTMLDivElement, PillProps>((props, ref) => {
@@ -181,7 +180,7 @@ export const Pill = forwardRef<HTMLDivElement, PillProps>((props, ref) => {
}}
{...divProps}
>
{cloneElement(icon, { className: css({ width: 14, height: 14 }) })}
{cloneElement(icon, { className: "size-[14px]" })}
{children}
</div>
);
+2 -3
View File
@@ -3,7 +3,6 @@ import LocationOnOutlined from "@mui/icons-material/LocationOnOutlined";
import Button from "@mui/material/Button";
import type {
HealthcheckReport,
HealthMessage,
HealthSeverity,
NetcheckReport,
} from "api/typesGenerated";
@@ -65,10 +64,10 @@ const DERPPage: FC = () => {
</Header>
<Main>
{derp.warnings.map((warning: HealthMessage) => {
{derp.warnings.map((warning) => {
return (
<Alert
actions={HealthMessageDocsLink(warning)}
actions={<HealthMessageDocsLink {...warning} />}
key={warning.code}
severity="warning"
>
+2 -3
View File
@@ -4,7 +4,6 @@ import type {
DERPNodeReport,
DERPRegionReport,
HealthcheckReport,
HealthMessage,
HealthSeverity,
} from "api/typesGenerated";
import { Alert } from "components/Alert/Alert";
@@ -75,10 +74,10 @@ const DERPRegionPage: FC = () => {
</Header>
<Main>
{warnings.map((warning: HealthMessage) => {
{warnings.map((warning) => {
return (
<Alert
actions={HealthMessageDocsLink(warning)}
actions={<HealthMessageDocsLink {...warning} />}
key={warning.code}
severity="warning"
>
+1 -1
View File
@@ -37,7 +37,7 @@ const DatabasePage = () => {
{database.warnings.map((warning) => {
return (
<Alert
actions={HealthMessageDocsLink(warning)}
actions={<HealthMessageDocsLink {...warning} />}
key={warning.code}
severity="warning"
>
@@ -37,7 +37,7 @@ const ProvisionerDaemonsPage: FC = () => {
{daemons.warnings.map((warning) => {
return (
<Alert
actions={HealthMessageDocsLink(warning)}
actions={<HealthMessageDocsLink {...warning} />}
key={warning.code}
severity="warning"
>
@@ -47,7 +47,7 @@ const WorkspaceProxyPage: FC = () => {
{workspace_proxy.warnings.map((warning) => {
return (
<Alert
actions={HealthMessageDocsLink(warning)}
actions={<HealthMessageDocsLink {...warning} />}
key={warning.code}
severity="warning"
>
@@ -174,7 +174,7 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
}, [triggerPreview]);
// Automatically switch to the template preview tab when the build succeeds.
const previousVersion = useRef<TemplateVersion>();
const previousVersion = useRef<TemplateVersion>(undefined);
useEffect(() => {
if (!previousVersion.current) {
previousVersion.current = templateVersion;
+2 -2
View File
@@ -117,7 +117,7 @@ const TerminalPage: FC = () => {
appearanceSettingsQuery.data?.terminal_font || DEFAULT_TERMINAL_FONT;
// Create the terminal!
const fitAddonRef = useRef<FitAddon>();
const fitAddonRef = useRef<FitAddon>(undefined);
useEffect(() => {
if (!terminalWrapperRef.current || config.isLoading) {
return;
@@ -209,7 +209,7 @@ const TerminalPage: FC = () => {
}, [navigate, reconnectionToken, searchParams]);
// Hook up the terminal through a web socket.
const websocketRef = useRef<Websocket>();
const websocketRef = useRef<Websocket>(undefined);
useEffect(() => {
if (!terminal) {
return;
@@ -1,7 +1,7 @@
import type * as TypesGen from "api/typesGenerated";
import { CodeExample } from "components/CodeExample/CodeExample";
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
import type { FC } from "react";
import type { FC, JSX } from "react";
interface ResetPasswordDialogProps {
open: boolean;
@@ -118,7 +118,7 @@ const AutostopDisplay: FC<AutostopDisplayProps> = ({
);
const deadlinePlusEnabled = maxDeadlineIncrease >= 1;
const deadlineMinusEnabled = maxDeadlineDecrease >= 1;
const deadlineUpdateTimeout = useRef<number>();
const deadlineUpdateTimeout = useRef<number>(undefined);
const lastStableDeadline = useRef<Dayjs>(deadline);
const updateWorkspaceDeadlineQueryData = (deadline: Dayjs) => {
+2 -2
View File
@@ -12,7 +12,7 @@ import type { DashboardProvider } from "modules/dashboard/DashboardProvider";
import OrganizationSettingsLayout from "modules/management/OrganizationSettingsLayout";
import { TemplateSettingsLayout } from "pages/TemplateSettingsPage/TemplateSettingsLayout";
import { WorkspaceSettingsLayout } from "pages/WorkspaceSettingsPage/WorkspaceSettingsLayout";
import type { ReactNode } from "react";
import type { JSX, ReactNode } from "react";
import { QueryClient } from "react-query";
import {
createMemoryRouter,
@@ -236,7 +236,7 @@ export const waitForLoaderToBeRemoved = async (): Promise<void> => {
);
};
export const renderComponent = (component: React.ReactElement) => {
export const renderComponent = (component: React.ReactNode) => {
return testingLibraryRender(component, {
wrapper: ({ children }) => (
<ThemeOverride theme={themes[DEFAULT_THEME]}>{children}</ThemeOverride>