Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
Copy Markdown
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
9 changes: 5 additions & 4 deletions frontend/app/element/expandablemenu.tsx
Original file line number Diff line number Diff line change
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/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/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
2 changes: 1 addition & 1 deletion 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
2 changes: 1 addition & 1 deletion frontend/app/tab/tab.tsx
Original file line number Diff line number Diff line change
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
8 changes: 4 additions & 4 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
4 changes: 2 additions & 2 deletions frontend/app/view/sysinfo/sysinfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ function SingleLinePlot({
sparkline = false,
targetLen,
}: SingleLinePlotProps) {
const containerRef = React.useRef<HTMLInputElement>();
const containerRef = React.useRef<HTMLInputElement>(null);
Copy link
Copy Markdown
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 @@ -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<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.ReactElement | string {
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: (string | React.ReactElement)[] = [];
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.ReactElement | string {
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): (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) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Type-return mismatch: convertChildren returns null but signature excludes it.

The function returns null at Lines 300 and 310, but the signature is (string | React.ReactElement)[]. Use React.ReactNode which naturally includes arrays, strings, elements, and null.

Apply this diff:

-function convertChildren(elem: VDomElem, model: VDomModel): (string | React.ReactElement)[] {
+function convertChildren(elem: VDomElem, model: VDomModel): React.ReactNode {
@@
-    let childrenComps: (string | React.ReactElement)[] = [];
+    let childrenComps: React.ReactNode[] = [];
📝 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
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) {
function convertChildren(elem: VDomElem, model: VDomModel): React.ReactNode {
if (elem.children == null || elem.children.length == 0) {
return null;
}
let childrenComps: React.ReactNode[] = [];
for (let child of elem.children) {
if (child == null) {
// ...
}
// ...
}
// ...
}
🤖 Prompt for AI Agents
In frontend/app/view/vdom/vdom.tsx around lines 298 to 304 (and the later return
at ~310), the function signature currently declares a return type of (string |
React.ReactElement)[] but the implementation returns null in some code paths;
change the return type to React.ReactNode (which already permits arrays,
strings, elements and null), update any local variables (e.g. childrenComps) to
use React.ReactNode or React.ReactNode[] as appropriate, and ensure all return
statements and the function signature consistently use React.ReactNode so null
returns are valid.

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: [],
};
}
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" />
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,16 @@
"@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",
"@types/throttle-debounce": "^5",
"@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",
Expand Down Expand Up @@ -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",
Expand Down
6 changes: 5 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
}
}
Loading
Loading