Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/app/block/block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function getViewElem(
contentRef: React.RefObject<HTMLDivElement>,
blockView: string,
viewModel: ViewModel
): JSX.Element {
): React.ReactElement {
if (isBlank(blockView)) {
return <CenteredDiv>No View</CenteredDiv>;
}
Expand Down
16 changes: 8 additions & 8 deletions frontend/app/block/blockframe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <div className="block-frame-view-icon">{getBlockHeaderIcon(viewIcon, blockData)}</div>;
Expand All @@ -108,8 +108,8 @@ function computeEndIcons(
viewModel: ViewModel,
nodeModel: NodeModel,
onContextMenu: (e: React.MouseEvent<HTMLDivElement>) => 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);
Expand Down Expand Up @@ -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 = <IconButton decl={preIconButton} className="block-frame-preicon-button" />;
}
Comment on lines +209 to 212
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Type mismatch: React.ReactElement cannot be null

preIconButtonElem is initialized with null but typed as React.ReactElement. This will fail under strict typing. Use a nullable union.

-    let preIconButtonElem: React.ReactElement = null;
+    let preIconButtonElem: React.ReactElement | null = null;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let preIconButtonElem: React.ReactElement = null;
if (preIconButton) {
preIconButtonElem = <IconButton decl={preIconButton} className="block-frame-preicon-button" />;
}
let preIconButtonElem: React.ReactElement | null = null;
if (preIconButton) {
preIconButtonElem = <IconButton decl={preIconButton} className="block-frame-preicon-button" />;
}
🤖 Prompt for AI Agents
In frontend/app/block/blockframe.tsx around lines 209 to 212, the variable
preIconButtonElem is declared as React.ReactElement but initialized to null
which violates strict typing; change its type to a nullable union (e.g.
React.ReactElement | null) or alternatively to React.ReactElement | undefined
and keep the null/undefined initialization, ensuring subsequent usage checks for
null/undefined before rendering.


const headerTextElems: JSX.Element[] = [];
const headerTextElems: React.ReactElement[] = [];
if (typeof headerTextUnion === "string") {
if (!util.isBlank(headerTextUnion)) {
headerTextElems.push(
Expand Down Expand Up @@ -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 = <HeaderTextElem elem={elem} key={idx} preview={preview} />;
Expand Down Expand Up @@ -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<HTMLDivElement>();
const connBtnRef = React.useRef<HTMLDivElement>(null);
const noHeader = util.useAtomValueSafe(viewModel?.noHeader);

React.useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/element/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "./button.scss";
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
className?: string;
children?: ReactNode;
as?: keyof JSX.IntrinsicElements | React.ComponentType<any>;
as?: keyof React.JSX.IntrinsicElements | React.ComponentType<any>;
}

const Button = memo(
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/element/copybutton.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down
11 changes: 6 additions & 5 deletions frontend/app/element/expandablemenu.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -109,7 +109,7 @@ const ExpandableMenuItemGroup = ({
const [openGroups, setOpenGroups] = useAtom(openGroupsAtom);

// Generate a unique ID for this group using useRef
const idRef = useRef<string>();
const idRef = useRef<string>(null);

if (!idRef.current) {
// Generate a unique ID when the component is first rendered
Expand Down Expand Up @@ -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<ExpandableMenuItemGroupTitleProps>, {
...childProps,
onClick: () => {
child.props.onClick?.();
childProps.onClick?.();
toggleOpen();
},
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/element/flyoutmenu.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ export const CustomRenderer: Story = {
</div>
);

const renderMenu = (subMenu: JSX.Element) => <div>{subMenu}</div>;
const renderMenu = (subMenu: React.ReactElement) => <div>{subMenu}</div>;

const modifiedArgs = {
...args,
Expand Down
8 changes: 4 additions & 4 deletions frontend/app/element/flyoutmenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -214,8 +214,8 @@ type SubMenuProps = {
item: MenuItem
) => void;
handleOnClick: (e: React.MouseEvent<HTMLDivElement>, 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(
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/element/linkbutton.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/element/markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/element/popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ interface PopoverButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
isActive?: boolean;
children: React.ReactNode;
getReferenceProps?: () => any;
as?: keyof JSX.IntrinsicElements | React.ComponentType<any>;
as?: keyof React.JSX.IntrinsicElements | React.ComponentType<any>;
}

const PopoverButton = forwardRef<HTMLButtonElement | HTMLDivElement, PopoverButtonProps>(
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/element/typingindicator.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand Down
3 changes: 2 additions & 1 deletion frontend/app/element/windowdrag.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -19,5 +19,6 @@ const WindowDrag = forwardRef<HTMLDivElement, WindowDragProps>(({ children, clas
</div>
);
});
WindowDrag.displayName = "WindowDrag";

export { WindowDrag };
2 changes: 1 addition & 1 deletion frontend/app/modals/modalsrenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/modals/userinputmodal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLInputElement>();
const checkboxRef = useRef<HTMLInputElement>(null);

const handleSendErrResponse = useCallback(() => {
fireAndForget(() =>
Expand Down Expand Up @@ -115,7 +115,7 @@ const UserInputModal = (userInputRequest: UserInputRequest) => {
className="userinput-checkbox"
ref={checkboxRef}
/>
<label htmlFor={`uicheckbox-${userInputRequest.requestid}}`}>{userInputRequest.checkboxmsg}</label>
<label htmlFor={`uicheckbox-${userInputRequest.requestid}`}>{userInputRequest.checkboxmsg}</label>
</div>
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/tab/tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -53,7 +53,7 @@ const Tab = memo(
const [isEditable, setIsEditable] = useState(false);

const editableRef = useRef<HTMLDivElement>(null);
const editableTimeoutRef = useRef<NodeJS.Timeout>();
const editableTimeoutRef = useRef<NodeJS.Timeout>(null);
const loadedRef = useRef(false);
const tabRef = useRef<HTMLDivElement>(null);

Expand Down
11 changes: 9 additions & 2 deletions frontend/app/view/preview/csvview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -193,7 +193,14 @@ const CSVView = ({ parentRef, filename, content }: CSVViewProps) => {
</thead>
<tbody style={{ height: `${state.tbodyHeight}px` }} ref={tbodyRef}>
{table.getRowModel().rows.map((row, index) => (
<tr key={row.id} ref={(el) => (rowRef.current[index] = el)} id={row.id} tabIndex={index}>
<tr
key={row.id}
ref={(el) => {
rowRef.current[index] = el;
}}
id={row.id}
tabIndex={index}
>
{row.getVisibleCells().map((cell) => (
<td key={cell.id} id={cell.id} tabIndex={index}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
Expand Down
14 changes: 9 additions & 5 deletions frontend/app/view/preview/directorypreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,8 @@ function DirectoryTable({
return colSizes;
}, [table.getState().columnSizingInfo]);

const osRef = useRef<OverlayScrollbarsComponentRef>();
const bodyRef = useRef<HTMLDivElement>();
const osRef = useRef<OverlayScrollbarsComponentRef>(null);
const bodyRef = useRef<HTMLDivElement>(null);
const [scrollHeight, setScrollHeight] = useState(0);

const onScroll = useCallback(
Expand Down Expand Up @@ -518,8 +518,8 @@ function TableBody({
setRefreshVersion,
osRef,
}: TableBodyProps) {
const dummyLineRef = useRef<HTMLDivElement>();
const warningBoxRef = useRef<HTMLDivElement>();
const dummyLineRef = useRef<HTMLDivElement>(null);
const warningBoxRef = useRef<HTMLDivElement>(null);
const conn = useAtomValue(model.connection);
const setErrorMsg = useSetAtom(model.errorMsgAtom);

Expand Down Expand Up @@ -732,6 +732,10 @@ const TableRow = React.forwardRef(function ({
[dragItem]
);

const dragRef = useCallback((node: HTMLDivElement | null) => {
drag(node);
}, [drag]);

return (
<div
className={clsx("dir-table-body-row", { focused: focusIndex === idx })}
Expand All @@ -743,7 +747,7 @@ const TableRow = React.forwardRef(function ({
}}
onClick={() => setFocusIndex(idx)}
onContextMenu={(e) => handleFileContextMenu(e, row.original)}
ref={drag}
ref={dragRef}
>
{row.getVisibleCells().map((cell) => (
<div
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/view/sysinfo/sysinfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ function SingleLinePlot({
sparkline = false,
targetLen,
}: SingleLinePlotProps) {
const containerRef = React.useRef<HTMLInputElement>();
const containerRef = React.useRef<HTMLInputElement>(null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Wrong ref element type: should be HTMLDivElement, not HTMLInputElement.

The ref is attached to a <div> (Line 516), and you call .append(plot) on it. Using HTMLInputElement is incorrect and can hide real type errors.

Apply this diff:

-const containerRef = React.useRef<HTMLInputElement>(null);
+const containerRef = React.useRef<HTMLDivElement>(null);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const containerRef = React.useRef<HTMLInputElement>(null);
const containerRef = React.useRef<HTMLDivElement>(null);
🤖 Prompt for AI Agents
In frontend/app/view/sysinfo/sysinfo.tsx around line 411, the ref is typed as
HTMLInputElement but it is attached to a div and used with .append(plot); change
the ref type to HTMLDivElement (preferably React.useRef<HTMLDivElement |
null>(null)) so the element type matches usage and avoid type errors, and update
any related null checks or usages accordingly.

const domRect = useDimensionsWithExistingRef(containerRef, 300);
const plotHeight = domRect?.height ?? 0;
const plotWidth = domRect?.width ?? 0;
Expand Down Expand Up @@ -519,7 +519,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<OverlayScrollbarsComponentRef>();
const osRef = React.useRef<OverlayScrollbarsComponentRef>(null);
const targetLen = jotai.useAtomValue(model.numPoints) + 1;
let title = false;
let cols2 = false;
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/view/term/ijson.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type IJsonNode = {

const TagMap: Record<string, React.ComponentType<{ node: IJsonNode }>> = {};

function convertNodeToTag(node: IJsonNode | string, idx?: number): JSX.Element | string {
function convertNodeToTag(node: IJsonNode | string, idx?: number): React.ReactNode {
if (node == null) {
return null;
}
Expand Down Expand Up @@ -44,7 +44,7 @@ function IJsonHtmlTag({ node }: { node: IJsonNode }) {
}
}
}
let childrenComps: (string | JSX.Element)[] = [];
let childrenComps: React.ReactNode[] = [];
if (children != null) {
for (let idx = 0; idx < children.length; idx++) {
let comp = convertNodeToTag(children[idx], idx);
Expand Down
8 changes: 4 additions & 4 deletions frontend/app/view/vdom/vdom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, VDomReactTagType> = {
"wave:markdown": WaveMarkdown,
Expand Down Expand Up @@ -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.ReactNode {
if (elem == null) {
return null;
}
Expand Down Expand Up @@ -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): React.ReactNode[] {
if (elem.children == null || elem.children.length == 0) {
return null;
}
let childrenComps: (string | JSX.Element)[] = [];
let childrenComps: React.ReactNode[] = [];
for (let child of elem.children) {
if (child == null) {
continue;
Expand Down
1 change: 1 addition & 0 deletions frontend/layout/tests/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ export function newLayoutTreeState(rootNode: LayoutNode): LayoutTreeState {
return {
rootNode,
generation: 0,
pendingBackendActions: [],
};
}
1 change: 1 addition & 0 deletions frontend/types/gotypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
4 changes: 4 additions & 0 deletions frontend/types/jsx.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0

/// <reference types="react/jsx-runtime" />
Loading
Loading