From 02ceb7faa7493c20e6a9d2c0f40e5d5bd44695e0 Mon Sep 17 00:00:00 2001 From: Tom Herold Date: Thu, 3 Jul 2025 14:55:12 +0200 Subject: [PATCH 1/7] Refactored several React class components as functional components --- .../components/disable_generic_dnd.ts | 30 ++-- .../components/fixed_expandable_table.tsx | 130 ++++++++-------- .../components/highlightable_row.tsx | 41 +++-- frontend/javascripts/components/loop.ts | 29 ++-- .../components/select_experience_domain.tsx | 140 ++++++++---------- .../components/text_with_description.tsx | 117 +++++++-------- .../javascripts/libs/shortcut_component.ts | 27 ++-- 7 files changed, 236 insertions(+), 278 deletions(-) diff --git a/frontend/javascripts/components/disable_generic_dnd.ts b/frontend/javascripts/components/disable_generic_dnd.ts index 9d3f618a4b6..6647d82f64c 100644 --- a/frontend/javascripts/components/disable_generic_dnd.ts +++ b/frontend/javascripts/components/disable_generic_dnd.ts @@ -1,22 +1,20 @@ import window from "libs/window"; import React from "react"; -import type { EmptyObject } from "types/globals"; -export default class DisableGenericDnd extends React.Component { - componentDidMount() { - window.addEventListener("dragover", this.preventDefault, false); - window.addEventListener("drop", this.preventDefault, false); - } - componentWillUnmount() { - window.removeEventListener("dragover", this.preventDefault); - window.removeEventListener("drop", this.preventDefault); - } +const preventDefault = (e: Event) => { + e.preventDefault(); +}; - preventDefault = (e: Event) => { - e.preventDefault(); - }; +export default function DisableGenericDnd() { + React.useEffect(() => { + window.addEventListener("dragover", preventDefault, false); + window.addEventListener("drop", preventDefault, false); - render() { - return null; - } + return () => { + window.removeEventListener("dragover", preventDefault); + window.removeEventListener("drop", preventDefault); + }; + }, []); + + return null; } diff --git a/frontend/javascripts/components/fixed_expandable_table.tsx b/frontend/javascripts/components/fixed_expandable_table.tsx index 372013692f7..1189fa8a595 100644 --- a/frontend/javascripts/components/fixed_expandable_table.tsx +++ b/frontend/javascripts/components/fixed_expandable_table.tsx @@ -1,11 +1,7 @@ import { Button, Table, type TableProps } from "antd"; import type { ColumnsType, GetRowKey } from "antd/lib/table/interface"; -import React from "react"; +import React, { useEffect } from "react"; -type State = { - expandedRows: Array; - className?: string; -}; /** This is a wrapper for large tables that have fixed columns and support expanded rows. * This wrapper ensures that when rows are expanded no column is fixed as this creates rendering bugs. * If you are using this wrapper, you do not need to set the class "large-table" @@ -17,72 +13,70 @@ type OwnTableProps = TableProps & { columns: ColumnsType; }; -const EMPTY_ARRAY: string[] = [] as const; +const EMPTY_ARRAY: readonly string[] = [] as const; -export default class FixedExpandableTable extends React.PureComponent { - state: State = { - expandedRows: EMPTY_ARRAY, - }; +const getAllRowIds = ( + dataSource: readonly any[] | undefined, + rowKey: string | number | symbol | GetRowKey | undefined, +) => { + const canUseRowKey = typeof rowKey === "string"; + return dataSource != null && canUseRowKey ? dataSource.map((row) => row[rowKey]) : []; +}; - getAllRowIds( - dataSource: readonly any[] | undefined, - rowKey: string | number | symbol | GetRowKey | undefined, - ) { - const canUseRowKey = typeof rowKey === "string"; - return dataSource != null && canUseRowKey ? dataSource.map((row) => row[rowKey]) : []; - } +export default function FixedExpandableTable({ + className, + expandable, + dataSource, + rowKey, + columns, + ...restProps +}: OwnTableProps) { + const [expandedRows, setExpandedRows] = React.useState(EMPTY_ARRAY); - componentDidUpdate(prevProps: Readonly>): void { - if (prevProps.dataSource !== this.props.dataSource) { - this.setState({ expandedRows: EMPTY_ARRAY }); - } - } + // biome-ignore lint/correctness/useExhaustiveDependencies: Collapse all rows when source changes + useEffect(() => { + setExpandedRows(EMPTY_ARRAY); + }, [dataSource]); - render() { - const { expandedRows } = this.state; - const { className, expandable, ...restProps } = this.props; - const { dataSource, rowKey } = this.props; - const areAllRowsExpanded = - dataSource != null && this.state.expandedRows.length === dataSource?.length; + const areAllRowsExpanded = dataSource != null && expandedRows.length === dataSource?.length; - const columnTitleCollapsed = ( -