From 3e3979804e785fe3902f82559f9e4c391b417b51 Mon Sep 17 00:00:00 2001 From: sawka Date: Wed, 20 Aug 2025 18:32:41 -0700 Subject: [PATCH 1/7] migrate to react 19, fix worst typescript errors --- frontend/app/block/block.tsx | 2 +- frontend/app/block/blockframe.tsx | 16 ++-- frontend/app/element/button.tsx | 2 +- frontend/app/element/expandablemenu.tsx | 9 ++- frontend/app/element/flyoutmenu.stories.tsx | 2 +- frontend/app/element/flyoutmenu.tsx | 8 +- frontend/app/element/popover.tsx | 2 +- frontend/app/modals/modalsrenderer.tsx | 2 +- frontend/app/modals/userinputmodal.tsx | 2 +- frontend/app/tab/tab.tsx | 2 +- .../app/view/preview/directorypreview.tsx | 8 +- frontend/app/view/sysinfo/sysinfo.tsx | 4 +- frontend/app/view/term/ijson.tsx | 4 +- frontend/app/view/vdom/vdom.tsx | 8 +- frontend/layout/tests/model.ts | 1 + frontend/types/jsx.d.ts | 4 + package.json | 10 +-- tsconfig.json | 6 +- yarn.lock | 79 ++++++++++++++----- 19 files changed, 112 insertions(+), 59 deletions(-) create mode 100644 frontend/types/jsx.d.ts diff --git a/frontend/app/block/block.tsx b/frontend/app/block/block.tsx index fe232ecc7c..4d849de9d1 100644 --- a/frontend/app/block/block.tsx +++ b/frontend/app/block/block.tsx @@ -63,7 +63,7 @@ function getViewElem( contentRef: React.RefObject, blockView: string, viewModel: ViewModel -): JSX.Element { +): React.ReactElement { if (isBlank(blockView)) { return No View; } diff --git a/frontend/app/block/blockframe.tsx b/frontend/app/block/blockframe.tsx index 06c255836a..d4be5393d3 100644 --- a/frontend/app/block/blockframe.tsx +++ b/frontend/app/block/blockframe.tsx @@ -82,7 +82,7 @@ function handleHeaderContextMenu( ContextMenuModel.showContextMenu(menu, e); } -function getViewIconElem(viewIconUnion: string | IconButtonDecl, blockData: Block): JSX.Element { +function getViewIconElem(viewIconUnion: string | IconButtonDecl, blockData: Block): React.ReactElement { if (viewIconUnion == null || typeof viewIconUnion === "string") { const viewIcon = viewIconUnion as string; return
{getBlockHeaderIcon(viewIcon, blockData)}
; @@ -108,8 +108,8 @@ function computeEndIcons( viewModel: ViewModel, nodeModel: NodeModel, onContextMenu: (e: React.MouseEvent) => void -): JSX.Element[] { - const endIconsElem: JSX.Element[] = []; +): React.ReactElement[] { + const endIconsElem: React.ReactElement[] = []; const endIconButtons = util.useAtomValueSafe(viewModel?.endIconButtons); const magnified = jotai.useAtomValue(nodeModel.isMagnified); const ephemeral = jotai.useAtomValue(nodeModel.isEphemeral); @@ -206,12 +206,12 @@ const BlockFrame_Header = ({ const endIconsElem = computeEndIcons(viewModel, nodeModel, onContextMenu); const viewIconElem = getViewIconElem(viewIconUnion, blockData); - let preIconButtonElem: JSX.Element = null; + let preIconButtonElem: React.ReactElement = null; if (preIconButton) { preIconButtonElem = ; } - const headerTextElems: JSX.Element[] = []; + const headerTextElems: React.ReactElement[] = []; if (typeof headerTextUnion === "string") { if (!util.isBlank(headerTextUnion)) { headerTextElems.push( @@ -310,8 +310,8 @@ const HeaderTextElem = React.memo(({ elem, preview }: { elem: HeaderElem; previe return null; }); -function renderHeaderElements(headerTextUnion: HeaderElem[], preview: boolean): JSX.Element[] { - const headerTextElems: JSX.Element[] = []; +function renderHeaderElements(headerTextUnion: HeaderElem[], preview: boolean): React.ReactElement[] { + const headerTextElems: React.ReactElement[] = []; for (let idx = 0; idx < headerTextUnion.length; idx++) { const elem = headerTextUnion[idx]; const renderedElement = ; @@ -536,7 +536,7 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => { const magnifiedBlockBlur = jotai.useAtomValue(magnifiedBlockBlurAtom); const [magnifiedBlockOpacityAtom] = React.useState(() => getSettingsKeyAtom("window:magnifiedblockopacity")); const magnifiedBlockOpacity = jotai.useAtomValue(magnifiedBlockOpacityAtom); - const connBtnRef = React.useRef(); + const connBtnRef = React.useRef(null); const noHeader = util.useAtomValueSafe(viewModel?.noHeader); React.useEffect(() => { diff --git a/frontend/app/element/button.tsx b/frontend/app/element/button.tsx index 00c98b8bca..55de0d963c 100644 --- a/frontend/app/element/button.tsx +++ b/frontend/app/element/button.tsx @@ -9,7 +9,7 @@ import "./button.scss"; interface ButtonProps extends React.ButtonHTMLAttributes { className?: string; children?: ReactNode; - as?: keyof JSX.IntrinsicElements | React.ComponentType; + as?: keyof React.JSX.IntrinsicElements | React.ComponentType; } const Button = memo( diff --git a/frontend/app/element/expandablemenu.tsx b/frontend/app/element/expandablemenu.tsx index f0d71b7058..0aa0cbd231 100644 --- a/frontend/app/element/expandablemenu.tsx +++ b/frontend/app/element/expandablemenu.tsx @@ -109,7 +109,7 @@ const ExpandableMenuItemGroup = ({ const [openGroups, setOpenGroups] = useAtom(openGroupsAtom); // Generate a unique ID for this group using useRef - const idRef = useRef(); + const idRef = useRef(null); if (!idRef.current) { // Generate a unique ID when the component is first rendered @@ -146,10 +146,11 @@ const ExpandableMenuItemGroup = ({ const renderChildren = Children.map(children, (child: ReactElement) => { if (child && child.type === ExpandableMenuItemGroupTitle) { - return cloneElement(child, { - ...child.props, + const childProps = child.props as ExpandableMenuItemGroupTitleProps; + return cloneElement(child as ReactElement, { + ...childProps, onClick: () => { - child.props.onClick?.(); + childProps.onClick?.(); toggleOpen(); }, }); diff --git a/frontend/app/element/flyoutmenu.stories.tsx b/frontend/app/element/flyoutmenu.stories.tsx index 7466c7fb92..0e3a3c9dfa 100644 --- a/frontend/app/element/flyoutmenu.stories.tsx +++ b/frontend/app/element/flyoutmenu.stories.tsx @@ -263,7 +263,7 @@ export const CustomRenderer: Story = { ); - const renderMenu = (subMenu: JSX.Element) =>
{subMenu}
; + const renderMenu = (subMenu: React.ReactElement) =>
{subMenu}
; const modifiedArgs = { ...args, diff --git a/frontend/app/element/flyoutmenu.tsx b/frontend/app/element/flyoutmenu.tsx index e99e832841..502421f302 100644 --- a/frontend/app/element/flyoutmenu.tsx +++ b/frontend/app/element/flyoutmenu.tsx @@ -14,8 +14,8 @@ type MenuProps = { placement?: Placement; onOpenChange?: (isOpen: boolean) => void; children: ReactNode | ReactNode[]; - renderMenu?: (subMenu: JSX.Element, props: any) => JSX.Element; - renderMenuItem?: (item: MenuItem, props: any) => JSX.Element; + renderMenu?: (subMenu: React.ReactElement, props: any) => React.ReactElement; + renderMenuItem?: (item: MenuItem, props: any) => React.ReactElement; }; const FlyoutMenuComponent = memo( @@ -214,8 +214,8 @@ type SubMenuProps = { item: MenuItem ) => void; handleOnClick: (e: React.MouseEvent, item: MenuItem) => void; - renderMenu?: (subMenu: JSX.Element, props: any) => JSX.Element; - renderMenuItem?: (item: MenuItem, props: any) => JSX.Element; + renderMenu?: (subMenu: React.ReactElement, props: any) => React.ReactElement; + renderMenuItem?: (item: MenuItem, props: any) => React.ReactElement; }; const SubMenu = memo( diff --git a/frontend/app/element/popover.tsx b/frontend/app/element/popover.tsx index b3a5b87b13..bc4665eb71 100644 --- a/frontend/app/element/popover.tsx +++ b/frontend/app/element/popover.tsx @@ -120,7 +120,7 @@ interface PopoverButtonProps extends React.ButtonHTMLAttributes any; - as?: keyof JSX.IntrinsicElements | React.ComponentType; + as?: keyof React.JSX.IntrinsicElements | React.ComponentType; } const PopoverButton = forwardRef( diff --git a/frontend/app/modals/modalsrenderer.tsx b/frontend/app/modals/modalsrenderer.tsx index 2496406377..ae9e57fca4 100644 --- a/frontend/app/modals/modalsrenderer.tsx +++ b/frontend/app/modals/modalsrenderer.tsx @@ -12,7 +12,7 @@ const ModalsRenderer = () => { const clientData = jotai.useAtomValue(atoms.client); const [tosOpen, setTosOpen] = jotai.useAtom(modalsModel.tosOpen); const [modals] = jotai.useAtom(modalsModel.modalsAtom); - const rtn: JSX.Element[] = []; + const rtn: React.ReactElement[] = []; for (const modal of modals) { const ModalComponent = getModalComponent(modal.displayName); if (ModalComponent) { diff --git a/frontend/app/modals/userinputmodal.tsx b/frontend/app/modals/userinputmodal.tsx index 9fbaec8005..7a1836292c 100644 --- a/frontend/app/modals/userinputmodal.tsx +++ b/frontend/app/modals/userinputmodal.tsx @@ -13,7 +13,7 @@ import "./userinputmodal.scss"; const UserInputModal = (userInputRequest: UserInputRequest) => { const [responseText, setResponseText] = useState(""); const [countdown, setCountdown] = useState(Math.floor(userInputRequest.timeoutms / 1000)); - const checkboxRef = useRef(); + const checkboxRef = useRef(null); const handleSendErrResponse = useCallback(() => { fireAndForget(() => diff --git a/frontend/app/tab/tab.tsx b/frontend/app/tab/tab.tsx index 2024b06c31..e4bbe164c6 100644 --- a/frontend/app/tab/tab.tsx +++ b/frontend/app/tab/tab.tsx @@ -53,7 +53,7 @@ const Tab = memo( const [isEditable, setIsEditable] = useState(false); const editableRef = useRef(null); - const editableTimeoutRef = useRef(); + const editableTimeoutRef = useRef(null); const loadedRef = useRef(false); const tabRef = useRef(null); diff --git a/frontend/app/view/preview/directorypreview.tsx b/frontend/app/view/preview/directorypreview.tsx index b213da03df..871c4eab46 100644 --- a/frontend/app/view/preview/directorypreview.tsx +++ b/frontend/app/view/preview/directorypreview.tsx @@ -411,8 +411,8 @@ function DirectoryTable({ return colSizes; }, [table.getState().columnSizingInfo]); - const osRef = useRef(); - const bodyRef = useRef(); + const osRef = useRef(null); + const bodyRef = useRef(null); const [scrollHeight, setScrollHeight] = useState(0); const onScroll = useCallback( @@ -518,8 +518,8 @@ function TableBody({ setRefreshVersion, osRef, }: TableBodyProps) { - const dummyLineRef = useRef(); - const warningBoxRef = useRef(); + const dummyLineRef = useRef(null); + const warningBoxRef = useRef(null); const conn = useAtomValue(model.connection); const setErrorMsg = useSetAtom(model.errorMsgAtom); diff --git a/frontend/app/view/sysinfo/sysinfo.tsx b/frontend/app/view/sysinfo/sysinfo.tsx index dc26528498..f424818bc4 100644 --- a/frontend/app/view/sysinfo/sysinfo.tsx +++ b/frontend/app/view/sysinfo/sysinfo.tsx @@ -408,7 +408,7 @@ function SingleLinePlot({ sparkline = false, targetLen, }: SingleLinePlotProps) { - const containerRef = React.useRef(); + const containerRef = React.useRef(null); const domRect = useDimensionsWithExistingRef(containerRef, 300); const plotHeight = domRect?.height ?? 0; const plotWidth = domRect?.width ?? 0; @@ -520,7 +520,7 @@ const SysinfoViewInner = React.memo(({ model }: SysinfoViewProps) => { const plotData = jotai.useAtomValue(model.dataAtom); const yvals = jotai.useAtomValue(model.metrics); const plotMeta = jotai.useAtomValue(model.plotMetaAtom); - const osRef = React.useRef(); + const osRef = React.useRef(null); const targetLen = jotai.useAtomValue(model.numPoints) + 1; let title = false; let cols2 = false; diff --git a/frontend/app/view/term/ijson.tsx b/frontend/app/view/term/ijson.tsx index b002f411fc..3b2e8ce39c 100644 --- a/frontend/app/view/term/ijson.tsx +++ b/frontend/app/view/term/ijson.tsx @@ -12,7 +12,7 @@ type IJsonNode = { const TagMap: Record> = {}; -function convertNodeToTag(node: IJsonNode | string, idx?: number): JSX.Element | string { +function convertNodeToTag(node: IJsonNode | string, idx?: number): React.ReactElement | string { if (node == null) { return null; } @@ -44,7 +44,7 @@ function IJsonHtmlTag({ node }: { node: IJsonNode }) { } } } - let childrenComps: (string | JSX.Element)[] = []; + let childrenComps: (string | React.ReactElement)[] = []; if (children != null) { for (let idx = 0; idx < children.length; idx++) { let comp = convertNodeToTag(children[idx], idx); diff --git a/frontend/app/view/vdom/vdom.tsx b/frontend/app/view/vdom/vdom.tsx index 3a4c9c00f9..f21063f96b 100644 --- a/frontend/app/view/vdom/vdom.tsx +++ b/frontend/app/view/vdom/vdom.tsx @@ -31,7 +31,7 @@ const VDomObjType_Func = "func"; const dlog = debug("wave:vdom"); -type VDomReactTagType = (props: { elem: VDomElem; model: VDomModel }) => JSX.Element; +type VDomReactTagType = (props: { elem: VDomElem; model: VDomModel }) => React.ReactElement; const WaveTagMap: Record = { "wave:markdown": WaveMarkdown, @@ -169,7 +169,7 @@ function convertVDomFunc(model: VDomModel, fnDecl: VDomFunc, compId: string, pro }; } -function convertElemToTag(elem: VDomElem, model: VDomModel): JSX.Element | string { +function convertElemToTag(elem: VDomElem, model: VDomModel): React.ReactElement | string { if (elem == null) { return null; } @@ -295,11 +295,11 @@ function convertProps(elem: VDomElem, model: VDomModel): [GenericPropsType, Set< return [props, atomKeys]; } -function convertChildren(elem: VDomElem, model: VDomModel): (string | JSX.Element)[] { +function convertChildren(elem: VDomElem, model: VDomModel): (string | React.ReactElement)[] { if (elem.children == null || elem.children.length == 0) { return null; } - let childrenComps: (string | JSX.Element)[] = []; + let childrenComps: (string | React.ReactElement)[] = []; for (let child of elem.children) { if (child == null) { continue; diff --git a/frontend/layout/tests/model.ts b/frontend/layout/tests/model.ts index 01b043fd4b..fd67c9fae2 100644 --- a/frontend/layout/tests/model.ts +++ b/frontend/layout/tests/model.ts @@ -7,5 +7,6 @@ export function newLayoutTreeState(rootNode: LayoutNode): LayoutTreeState { return { rootNode, generation: 0, + pendingBackendActions: [], }; } diff --git a/frontend/types/jsx.d.ts b/frontend/types/jsx.d.ts new file mode 100644 index 0000000000..992c50a3cb --- /dev/null +++ b/frontend/types/jsx.d.ts @@ -0,0 +1,4 @@ +// Copyright 2025, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +/// \ No newline at end of file diff --git a/package.json b/package.json index fb3c3cae21..dcd2fe37dd 100644 --- a/package.json +++ b/package.json @@ -51,8 +51,8 @@ "@types/papaparse": "^5", "@types/pngjs": "^6.0.5", "@types/prop-types": "^15", - "@types/react": "^18.3.23", - "@types/react-dom": "^18.3.7", + "@types/react": "19", + "@types/react-dom": "19", "@types/semver": "^7", "@types/shell-quote": "^1", "@types/sprintf-js": "^1", @@ -60,7 +60,7 @@ "@types/tinycolor2": "^1", "@types/uuid": "^10.0.0", "@types/ws": "^8", - "@vitejs/plugin-react-swc": "^4.0.0", + "@vitejs/plugin-react-swc": "4.0.1", "@vitest/coverage-istanbul": "^3.0.9", "electron": "^37.3.0", "electron-builder": "^26.0", @@ -131,10 +131,10 @@ "parse-srcset": "^1.0.2", "pngjs": "^7.0.0", "prop-types": "^15.8.1", - "react": "^18.3.1", + "react": "19.1.1", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^18.3.1", + "react-dom": "19.1.1", "react-frame-component": "^5.2.7", "react-gauge-chart": "^0.5.1", "react-hook-form": "^7.62.0", diff --git a/tsconfig.json b/tsconfig.json index 893b4ad21a..024373bfe2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,6 +23,10 @@ "@/element/*": ["frontend/app/element/*"], "@/shadcn/*": ["frontend/app/shadcn/*"] }, - "types": ["vite/client", "vite-plugin-svgr/client"] + "types": ["vite/client", "vite-plugin-svgr/client"], + "lib": ["dom", "dom.iterable", "es6"], + "allowJs": true, + "strict": false, + "noEmit": true } } diff --git a/yarn.lock b/yarn.lock index e2479e133a..2c319be208 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4591,10 +4591,10 @@ __metadata: languageName: node linkType: hard -"@rolldown/pluginutils@npm:1.0.0-beta.30": - version: 1.0.0-beta.30 - resolution: "@rolldown/pluginutils@npm:1.0.0-beta.30" - checksum: 10c0/aff8b532cb9d82d94c9a4101fa12ecb10620ad47d52dbb9135a5c65bde1ad19895b41026b821f4d607083699239a5d0010198401b6a6a54ab6a10d0015302768 +"@rolldown/pluginutils@npm:1.0.0-beta.32": + version: 1.0.0-beta.32 + resolution: "@rolldown/pluginutils@npm:1.0.0-beta.32" + checksum: 10c0/ba3582fc3c35c8eb57b0df2d22d0733b1be83d37edcc258203364773f094f58fc0cb7a056d604603573a69dd0105a466506cad467f59074e1e53d0dc26191f06 languageName: node linkType: hard @@ -6484,7 +6484,16 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:^18.3.0, @types/react-dom@npm:^18.3.7": +"@types/react-dom@npm:19": + version: 19.1.7 + resolution: "@types/react-dom@npm:19.1.7" + peerDependencies: + "@types/react": ^19.0.0 + checksum: 10c0/8db5751c1567552fe4e1ece9f5823b682f2994ec8d30ed34ba0ef984e3c8ace1435f8be93d02f55c350147e78ac8c4dbcd8ed2c3b6a60f575bc5374f588c51c9 + languageName: node + linkType: hard + +"@types/react-dom@npm:^18.3.0": version: 18.3.7 resolution: "@types/react-dom@npm:18.3.7" peerDependencies: @@ -6535,7 +6544,16 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^18.3.0, @types/react@npm:^18.3.23": +"@types/react@npm:19": + version: 19.1.10 + resolution: "@types/react@npm:19.1.10" + dependencies: + csstype: "npm:^3.0.2" + checksum: 10c0/fb583deacd0a815e2775dc1b9f764532d8cacb748ddd2c2914805a46c257ce6c237b4078f44009692074db212ab61a390301c6470f07f5aa5bfdeb78a2acfda1 + languageName: node + linkType: hard + +"@types/react@npm:^18.3.0": version: 18.3.23 resolution: "@types/react@npm:18.3.23" dependencies: @@ -6899,15 +6917,15 @@ __metadata: languageName: node linkType: hard -"@vitejs/plugin-react-swc@npm:^4.0.0": - version: 4.0.0 - resolution: "@vitejs/plugin-react-swc@npm:4.0.0" +"@vitejs/plugin-react-swc@npm:4.0.1": + version: 4.0.1 + resolution: "@vitejs/plugin-react-swc@npm:4.0.1" dependencies: - "@rolldown/pluginutils": "npm:1.0.0-beta.30" + "@rolldown/pluginutils": "npm:1.0.0-beta.32" "@swc/core": "npm:^1.13.2" peerDependencies: vite: ^4 || ^5 || ^6 || ^7 - checksum: 10c0/f9253956669dad67c028051a01767960b62e5ca234c20ba1ebf1fc453923c07ee730eda0fffa754b6b83fa96fd21eb2f087ad77f686252d9470fb96982e7c1b2 + checksum: 10c0/5f3ff14659490eea81b6be59a5dbc3c5d98c8fd02bfe8112edac26269adf69cb603136c44240b78e3ee0abb3c95a95e0d1172549a7debca1b79d7f52fa511f27 languageName: node linkType: hard @@ -18101,6 +18119,17 @@ __metadata: languageName: node linkType: hard +"react-dom@npm:19.1.1": + version: 19.1.1 + resolution: "react-dom@npm:19.1.1" + dependencies: + scheduler: "npm:^0.26.0" + peerDependencies: + react: ^19.1.1 + checksum: 10c0/8c91198510521299c56e4e8d5e3a4508b2734fb5e52f29eeac33811de64e76fe586ad32c32182e2e84e070d98df67125da346c3360013357228172dbcd20bcdd + languageName: node + linkType: hard + "react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0": version: 19.0.0 resolution: "react-dom@npm:19.0.0" @@ -18112,7 +18141,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^18.0.0, react-dom@npm:^18.3.1": +"react-dom@npm:^18.0.0": version: 18.3.1 resolution: "react-dom@npm:18.3.1" dependencies: @@ -18361,6 +18390,13 @@ __metadata: languageName: node linkType: hard +"react@npm:19.1.1": + version: 19.1.1 + resolution: "react@npm:19.1.1" + checksum: 10c0/8c9769a2dfd02e603af6445058325e6c8a24b47b185d0e461f66a6454765ddcaecb3f0a90184836c68bb509f3c38248359edbc42f0d07c23eb500a5c30c87b4e + languageName: node + linkType: hard + "react@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0": version: 19.0.0 resolution: "react@npm:19.0.0" @@ -18368,7 +18404,7 @@ __metadata: languageName: node linkType: hard -"react@npm:^18.0.0, react@npm:^18.3.1": +"react@npm:^18.0.0": version: 18.3.1 resolution: "react@npm:18.3.1" dependencies: @@ -19759,6 +19795,13 @@ __metadata: languageName: node linkType: hard +"scheduler@npm:^0.26.0": + version: 0.26.0 + resolution: "scheduler@npm:0.26.0" + checksum: 10c0/5b8d5bfddaae3513410eda54f2268e98a376a429931921a81b5c3a2873aab7ca4d775a8caac5498f8cbc7d0daeab947cf923dbd8e215d61671f9f4e392d34356 + languageName: node + linkType: hard + "schema-utils@npm:2.7.0": version: 2.7.0 resolution: "schema-utils@npm:2.7.0" @@ -22392,8 +22435,8 @@ __metadata: "@types/papaparse": "npm:^5" "@types/pngjs": "npm:^6.0.5" "@types/prop-types": "npm:^15" - "@types/react": "npm:^18.3.23" - "@types/react-dom": "npm:^18.3.7" + "@types/react": "npm:19" + "@types/react-dom": "npm:19" "@types/semver": "npm:^7" "@types/shell-quote": "npm:^1" "@types/sprintf-js": "npm:^1" @@ -22401,7 +22444,7 @@ __metadata: "@types/tinycolor2": "npm:^1" "@types/uuid": "npm:^10.0.0" "@types/ws": "npm:^8" - "@vitejs/plugin-react-swc": "npm:^4.0.0" + "@vitejs/plugin-react-swc": "npm:4.0.1" "@vitest/coverage-istanbul": "npm:^3.0.9" "@xterm/addon-fit": "npm:^0.10.0" "@xterm/addon-search": "npm:^0.15.0" @@ -22442,10 +22485,10 @@ __metadata: prettier-plugin-jsdoc: "npm:^1.3.3" prettier-plugin-organize-imports: "npm:^4.1.0" prop-types: "npm:^15.8.1" - react: "npm:^18.3.1" + react: "npm:19.1.1" react-dnd: "npm:^16.0.1" react-dnd-html5-backend: "npm:^16.0.1" - react-dom: "npm:^18.3.1" + react-dom: "npm:19.1.1" react-frame-component: "npm:^5.2.7" react-gauge-chart: "npm:^0.5.1" react-hook-form: "npm:^7.62.0" From b9eeb5dd33eadee72046364863cbefae56011f05 Mon Sep 17 00:00:00 2001 From: sawka Date: Fri, 22 Aug 2025 09:56:24 -0700 Subject: [PATCH 2/7] fix react 19 issue with ref types --- frontend/app/view/preview/directorypreview.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/app/view/preview/directorypreview.tsx b/frontend/app/view/preview/directorypreview.tsx index 871c4eab46..be8201546e 100644 --- a/frontend/app/view/preview/directorypreview.tsx +++ b/frontend/app/view/preview/directorypreview.tsx @@ -732,6 +732,10 @@ const TableRow = React.forwardRef(function ({ [dragItem] ); + const dragRef = useCallback((node: HTMLDivElement | null) => { + drag(node); + }, [drag]); + return (
setFocusIndex(idx)} onContextMenu={(e) => handleFileContextMenu(e, row.original)} - ref={drag} + ref={dragRef} > {row.getVisibleCells().map((cell) => (
Date: Mon, 25 Aug 2025 20:23:05 -0700 Subject: [PATCH 3/7] fix svg typing issues --- frontend/types/vite-env.d.ts | 5 +++++ tsconfig.json | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 frontend/types/vite-env.d.ts diff --git a/frontend/types/vite-env.d.ts b/frontend/types/vite-env.d.ts new file mode 100644 index 0000000000..191d853a2e --- /dev/null +++ b/frontend/types/vite-env.d.ts @@ -0,0 +1,5 @@ +// Copyright 2025, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +/// +/// diff --git a/tsconfig.json b/tsconfig.json index 024373bfe2..92c7ae5b98 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,7 +23,6 @@ "@/element/*": ["frontend/app/element/*"], "@/shadcn/*": ["frontend/app/shadcn/*"] }, - "types": ["vite/client", "vite-plugin-svgr/client"], "lib": ["dom", "dom.iterable", "es6"], "allowJs": true, "strict": false, From ba23687c0cb34cfa768b7fc10398000f62431c3d Mon Sep 17 00:00:00 2001 From: sawka Date: Mon, 25 Aug 2025 20:25:52 -0700 Subject: [PATCH 4/7] fix editor:fontsize meta type --- frontend/types/gotypes.d.ts | 1 + pkg/waveobj/metaconsts.go | 1 + pkg/waveobj/wtypemeta.go | 9 +++++---- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index 3b9c29b2fd..9b4e8c5be9 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -559,6 +559,7 @@ declare global { "editor:minimapenabled"?: boolean; "editor:stickyscrollenabled"?: boolean; "editor:wordwrap"?: boolean; + "editor:fontsize"?: number; "graph:*"?: boolean; "graph:numpoints"?: number; "graph:metrics"?: string[]; diff --git a/pkg/waveobj/metaconsts.go b/pkg/waveobj/metaconsts.go index 68caa25f7b..7a45a5804a 100644 --- a/pkg/waveobj/metaconsts.go +++ b/pkg/waveobj/metaconsts.go @@ -76,6 +76,7 @@ const ( MetaKey_EditorMinimapEnabled = "editor:minimapenabled" MetaKey_EditorStickyScrollEnabled = "editor:stickyscrollenabled" MetaKey_EditorWordWrap = "editor:wordwrap" + MetaKey_EditorFontSize = "editor:fontsize" MetaKey_GraphClear = "graph:*" MetaKey_GraphNumPoints = "graph:numpoints" diff --git a/pkg/waveobj/wtypemeta.go b/pkg/waveobj/wtypemeta.go index b272e17d4f..c0ebb92919 100644 --- a/pkg/waveobj/wtypemeta.go +++ b/pkg/waveobj/wtypemeta.go @@ -74,10 +74,11 @@ type MetaTSType struct { AiMaxTokens float64 `json:"ai:maxtokens,omitempty"` AiTimeoutMs float64 `json:"ai:timeoutms,omitempty"` - EditorClear bool `json:"editor:*,omitempty"` - EditorMinimapEnabled bool `json:"editor:minimapenabled,omitempty"` - EditorStickyScrollEnabled bool `json:"editor:stickyscrollenabled,omitempty"` - EditorWordWrap bool `json:"editor:wordwrap,omitempty"` + EditorClear bool `json:"editor:*,omitempty"` + EditorMinimapEnabled bool `json:"editor:minimapenabled,omitempty"` + EditorStickyScrollEnabled bool `json:"editor:stickyscrollenabled,omitempty"` + EditorWordWrap bool `json:"editor:wordwrap,omitempty"` + EditorFontSize float64 `json:"editor:fontsize,omitempty"` GraphClear bool `json:"graph:*,omitempty"` GraphNumPoints int `json:"graph:numpoints,omitempty"` From 79edea6fa0113d06974f5242a59b7ae51d14d83c Mon Sep 17 00:00:00 2001 From: sawka Date: Mon, 25 Aug 2025 20:28:03 -0700 Subject: [PATCH 5/7] fix ref ts error --- frontend/app/view/preview/csvview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/view/preview/csvview.tsx b/frontend/app/view/preview/csvview.tsx index f3055dbcd1..a897ef2fc5 100644 --- a/frontend/app/view/preview/csvview.tsx +++ b/frontend/app/view/preview/csvview.tsx @@ -193,7 +193,7 @@ const CSVView = ({ parentRef, filename, content }: CSVViewProps) => { {table.getRowModel().rows.map((row, index) => ( - (rowRef.current[index] = el)} id={row.id} tabIndex={index}> + { rowRef.current[index] = el; }} id={row.id} tabIndex={index}> {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} From 17965bd266f92a00c08138b6a507308680d3362f Mon Sep 17 00:00:00 2001 From: sawka Date: Mon, 25 Aug 2025 20:51:51 -0700 Subject: [PATCH 6/7] fix some small typescript weirdness --- frontend/app/element/copybutton.tsx | 2 +- frontend/app/element/expandablemenu.tsx | 2 +- frontend/app/element/linkbutton.tsx | 2 +- frontend/app/element/markdown.tsx | 2 +- frontend/app/element/typingindicator.tsx | 2 +- frontend/app/element/windowdrag.tsx | 2 +- frontend/app/modals/userinputmodal.tsx | 2 +- frontend/app/tab/tab.tsx | 2 +- frontend/app/view/preview/csvview.tsx | 11 +++++++++-- frontend/app/view/term/ijson.tsx | 4 ++-- frontend/app/view/vdom/vdom.tsx | 6 +++--- 11 files changed, 22 insertions(+), 15 deletions(-) diff --git a/frontend/app/element/copybutton.tsx b/frontend/app/element/copybutton.tsx index e33d9109d3..027311a096 100644 --- a/frontend/app/element/copybutton.tsx +++ b/frontend/app/element/copybutton.tsx @@ -1,7 +1,7 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 -import { clsx } from "clsx"; +import clsx from "clsx"; import { useEffect, useRef, useState } from "react"; import "./copybutton.scss"; import { IconButton } from "./iconbutton"; diff --git a/frontend/app/element/expandablemenu.tsx b/frontend/app/element/expandablemenu.tsx index 0aa0cbd231..3a5b60210d 100644 --- a/frontend/app/element/expandablemenu.tsx +++ b/frontend/app/element/expandablemenu.tsx @@ -1,7 +1,7 @@ // Copyright 2025, Command Line // SPDX-License-Identifier: Apache-2.0 -import { clsx } from "clsx"; +import clsx from "clsx"; import { atom, useAtom } from "jotai"; import { Children, ReactElement, ReactNode, cloneElement, isValidElement, useRef } from "react"; diff --git a/frontend/app/element/linkbutton.tsx b/frontend/app/element/linkbutton.tsx index 93707355a4..295aa34d06 100644 --- a/frontend/app/element/linkbutton.tsx +++ b/frontend/app/element/linkbutton.tsx @@ -1,7 +1,7 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 -import { clsx } from "clsx"; +import clsx from "clsx"; import * as React from "react"; import "./linkbutton.scss"; diff --git a/frontend/app/element/markdown.tsx b/frontend/app/element/markdown.tsx index 96f2235e82..81488ff76c 100644 --- a/frontend/app/element/markdown.tsx +++ b/frontend/app/element/markdown.tsx @@ -10,7 +10,7 @@ import { transformBlocks, } from "@/app/element/markdown-util"; import { boundNumber, useAtomValueSafe } from "@/util/util"; -import { clsx } from "clsx"; +import clsx from "clsx"; import { Atom } from "jotai"; import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react"; import { useEffect, useMemo, useRef, useState } from "react"; diff --git a/frontend/app/element/typingindicator.tsx b/frontend/app/element/typingindicator.tsx index 7d39ba78c4..ff9f3e242d 100644 --- a/frontend/app/element/typingindicator.tsx +++ b/frontend/app/element/typingindicator.tsx @@ -1,7 +1,7 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 -import { clsx } from "clsx"; +import clsx from "clsx"; import "./typingindicator.scss"; diff --git a/frontend/app/element/windowdrag.tsx b/frontend/app/element/windowdrag.tsx index 6d9cc8e5ed..f5af2b7c06 100644 --- a/frontend/app/element/windowdrag.tsx +++ b/frontend/app/element/windowdrag.tsx @@ -1,7 +1,7 @@ // Copyright 2025, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 -import { clsx } from "clsx"; +import clsx from "clsx"; import React, { forwardRef } from "react"; import "./windowdrag.scss"; diff --git a/frontend/app/modals/userinputmodal.tsx b/frontend/app/modals/userinputmodal.tsx index 7a1836292c..d277a73236 100644 --- a/frontend/app/modals/userinputmodal.tsx +++ b/frontend/app/modals/userinputmodal.tsx @@ -115,7 +115,7 @@ const UserInputModal = (userInputRequest: UserInputRequest) => { className="userinput-checkbox" ref={checkboxRef} /> - +
); diff --git a/frontend/app/tab/tab.tsx b/frontend/app/tab/tab.tsx index e4bbe164c6..156d740b0a 100644 --- a/frontend/app/tab/tab.tsx +++ b/frontend/app/tab/tab.tsx @@ -7,7 +7,7 @@ import { TabRpcClient } from "@/app/store/wshrpcutil"; import { Button } from "@/element/button"; import { ContextMenuModel } from "@/store/contextmenu"; import { fireAndForget } from "@/util/util"; -import { clsx } from "clsx"; +import clsx from "clsx"; import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react"; import { ObjectService } from "../store/services"; import { makeORef, useWaveObjectValue } from "../store/wos"; diff --git a/frontend/app/view/preview/csvview.tsx b/frontend/app/view/preview/csvview.tsx index a897ef2fc5..ef781077ae 100644 --- a/frontend/app/view/preview/csvview.tsx +++ b/frontend/app/view/preview/csvview.tsx @@ -9,7 +9,7 @@ import { getSortedRowModel, useReactTable, } from "@tanstack/react-table"; -import { clsx } from "clsx"; +import clsx from "clsx"; import Papa from "papaparse"; import { useEffect, useMemo, useRef, useState } from "react"; @@ -193,7 +193,14 @@ const CSVView = ({ parentRef, filename, content }: CSVViewProps) => { {table.getRowModel().rows.map((row, index) => ( - { rowRef.current[index] = el; }} id={row.id} tabIndex={index}> + { + rowRef.current[index] = el; + }} + id={row.id} + tabIndex={index} + > {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} diff --git a/frontend/app/view/term/ijson.tsx b/frontend/app/view/term/ijson.tsx index 3b2e8ce39c..617a6e094d 100644 --- a/frontend/app/view/term/ijson.tsx +++ b/frontend/app/view/term/ijson.tsx @@ -12,7 +12,7 @@ type IJsonNode = { const TagMap: Record> = {}; -function convertNodeToTag(node: IJsonNode | string, idx?: number): React.ReactElement | string { +function convertNodeToTag(node: IJsonNode | string, idx?: number): React.ReactNode { if (node == null) { return null; } @@ -44,7 +44,7 @@ function IJsonHtmlTag({ node }: { node: IJsonNode }) { } } } - let childrenComps: (string | React.ReactElement)[] = []; + let childrenComps: React.ReactNode[] = []; if (children != null) { for (let idx = 0; idx < children.length; idx++) { let comp = convertNodeToTag(children[idx], idx); diff --git a/frontend/app/view/vdom/vdom.tsx b/frontend/app/view/vdom/vdom.tsx index f21063f96b..4634defd87 100644 --- a/frontend/app/view/vdom/vdom.tsx +++ b/frontend/app/view/vdom/vdom.tsx @@ -169,7 +169,7 @@ function convertVDomFunc(model: VDomModel, fnDecl: VDomFunc, compId: string, pro }; } -function convertElemToTag(elem: VDomElem, model: VDomModel): React.ReactElement | string { +function convertElemToTag(elem: VDomElem, model: VDomModel): React.ReactNode { if (elem == null) { return null; } @@ -295,11 +295,11 @@ function convertProps(elem: VDomElem, model: VDomModel): [GenericPropsType, Set< return [props, atomKeys]; } -function convertChildren(elem: VDomElem, model: VDomModel): (string | React.ReactElement)[] { +function convertChildren(elem: VDomElem, model: VDomModel): React.ReactNode[] { if (elem.children == null || elem.children.length == 0) { return null; } - let childrenComps: (string | React.ReactElement)[] = []; + let childrenComps: React.ReactNode[] = []; for (let child of elem.children) { if (child == null) { continue; From e12cde5980dd67f63f6e81e92d11f667a8d39fe5 Mon Sep 17 00:00:00 2001 From: sawka Date: Mon, 25 Aug 2025 21:16:04 -0700 Subject: [PATCH 7/7] small fix --- frontend/app/element/windowdrag.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/app/element/windowdrag.tsx b/frontend/app/element/windowdrag.tsx index f5af2b7c06..7e4ed733da 100644 --- a/frontend/app/element/windowdrag.tsx +++ b/frontend/app/element/windowdrag.tsx @@ -19,5 +19,6 @@ const WindowDrag = forwardRef(({ children, clas ); }); +WindowDrag.displayName = "WindowDrag"; export { WindowDrag };