Add React performance lint rules (#4443)
This commit is contained in:
parent
c60fe4ebd7
commit
e62cd5aefb
|
|
@ -22,9 +22,11 @@
|
|||
"react/jsx-filename-extension": ["error", { "extensions": [".tsx", ".jsx"] }],
|
||||
"react/jsx-fragments": "error",
|
||||
"react/jsx-key": "error",
|
||||
"react/jsx-no-constructed-context-values": "error",
|
||||
"react/jsx-no-target-blank": "error",
|
||||
"react/jsx-no-useless-fragment": ["error", { "allowExpressions": true }],
|
||||
"react/jsx-pascal-case": "error",
|
||||
"react/no-object-type-as-default-prop": "error",
|
||||
"react/self-closing-comp": "error",
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"react-hooks/exhaustive-deps": "warn",
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ type FileContent = {
|
|||
loadError?: string
|
||||
}
|
||||
|
||||
const noopCloseMarkdownTableOfContents = (): void => {}
|
||||
|
||||
function matchesPendingEditorReveal(
|
||||
reveal: PendingEditorReveal | null,
|
||||
file: Pick<OpenFile, 'id' | 'filePath'>
|
||||
|
|
@ -106,7 +108,7 @@ export function EditorContent({
|
|||
isChangesMode,
|
||||
sideBySide,
|
||||
showMarkdownTableOfContents = false,
|
||||
onCloseMarkdownTableOfContents = () => {},
|
||||
onCloseMarkdownTableOfContents = noopCloseMarkdownTableOfContents,
|
||||
markdownAnnotationsEnabled = true,
|
||||
pendingEditorReveal,
|
||||
handleContentChange,
|
||||
|
|
|
|||
|
|
@ -89,6 +89,8 @@ import { findWorktreeById } from '@/store/slices/worktree-helpers'
|
|||
import { dirname } from '@/lib/path'
|
||||
import { relativePathInsideRoot } from '../../../../shared/cross-platform-path'
|
||||
|
||||
const EMPTY_MARKDOWN_DOCUMENTS: MarkdownDocument[] = []
|
||||
|
||||
type MarkdownPreviewProps = {
|
||||
content: string
|
||||
filePath: string
|
||||
|
|
@ -434,7 +436,7 @@ export default function MarkdownPreview({
|
|||
initialAnchor = null,
|
||||
showTableOfContents = false,
|
||||
onCloseTableOfContents,
|
||||
markdownDocuments = [],
|
||||
markdownDocuments = EMPTY_MARKDOWN_DOCUMENTS,
|
||||
onOpenDocument,
|
||||
markdownAnnotationsEnabled = false
|
||||
}: MarkdownPreviewProps): React.JSX.Element {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ import { getCodexAccountAuthWarning } from './codex-account-auth-warning'
|
|||
|
||||
export { ACCOUNTS_PANE_SEARCH_ENTRIES }
|
||||
|
||||
const EMPTY_WSL_DISTROS: string[] = []
|
||||
|
||||
type AccountsPaneProps = {
|
||||
settings: GlobalSettings
|
||||
updateSettings: (updates: Partial<GlobalSettings>) => void
|
||||
|
|
@ -234,7 +236,7 @@ export function AccountsPane({
|
|||
updateSettings,
|
||||
wslSupportedPlatform = false,
|
||||
wslAvailable = false,
|
||||
wslDistros = [],
|
||||
wslDistros = EMPTY_WSL_DISTROS,
|
||||
wslCapabilitiesLoading = false
|
||||
}: AccountsPaneProps): React.JSX.Element {
|
||||
const searchQuery = useAppStore((s) => s.settingsSearchQuery)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import type { GlobalSettings } from '../../../../shared/types'
|
|||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select'
|
||||
import { SettingsRow, SettingsSegmentedControl } from './SettingsFormControls'
|
||||
|
||||
const EMPTY_WSL_DISTROS: string[] = []
|
||||
|
||||
type AgentDetectionRuntime = {
|
||||
runtime: 'host' | 'wsl'
|
||||
wslDistro?: string | null
|
||||
|
|
@ -56,7 +58,7 @@ export function AgentLocationSetting({
|
|||
refresh,
|
||||
wslSupportedPlatform = false,
|
||||
wslAvailable = false,
|
||||
wslDistros = [],
|
||||
wslDistros = EMPTY_WSL_DISTROS,
|
||||
wslCapabilitiesLoading = false
|
||||
}: AgentLocationSettingProps): React.JSX.Element | null {
|
||||
const agentRuntime = getSelectedAgentRuntime(
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ import {
|
|||
|
||||
export { AGENTS_PANE_SEARCH_ENTRIES } from './agents-search'
|
||||
|
||||
const EMPTY_WSL_DISTROS: string[] = []
|
||||
|
||||
type AgentsPaneProps = {
|
||||
settings: GlobalSettings
|
||||
updateSettings: (updates: Partial<GlobalSettings>) => void | Promise<void>
|
||||
|
|
@ -360,7 +362,7 @@ export function AgentsPane({
|
|||
updateSettings,
|
||||
wslSupportedPlatform = false,
|
||||
wslAvailable = false,
|
||||
wslDistros = [],
|
||||
wslDistros = EMPTY_WSL_DISTROS,
|
||||
wslCapabilitiesLoading = false
|
||||
}: AgentsPaneProps): React.JSX.Element {
|
||||
const { detectedIds: detectedList, isRefreshing, refresh } = useDetectedAgents()
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ import { ManageSessionsSection } from './ManageSessionsSection'
|
|||
import { OSC52_CLIPBOARD_SETTING_ID } from '../terminal-pane/osc52-clipboard-setting-anchor'
|
||||
import { WINDOWS_GIT_BASH_SHELL } from '../../../../shared/windows-terminal-shell'
|
||||
|
||||
const EMPTY_WSL_DISTROS: string[] = []
|
||||
|
||||
type TerminalPaneProps = {
|
||||
settings: GlobalSettings
|
||||
updateSettings: (updates: Partial<GlobalSettings>) => void
|
||||
|
|
@ -59,7 +61,7 @@ export function TerminalPane({
|
|||
scrollbackMode,
|
||||
setScrollbackMode,
|
||||
wslAvailable,
|
||||
wslDistros = [],
|
||||
wslDistros = EMPTY_WSL_DISTROS,
|
||||
wslCapabilitiesLoading = false,
|
||||
pwshAvailable,
|
||||
gitBashAvailable = false
|
||||
|
|
|
|||
|
|
@ -203,10 +203,12 @@ const WorktreeContextMenu = React.memo(function WorktreeContextMenu({
|
|||
worktree,
|
||||
children,
|
||||
contentClassName,
|
||||
selectedWorktrees = [worktree],
|
||||
selectedWorktrees,
|
||||
onContextMenuSelect,
|
||||
onOpenChange
|
||||
}: Props) {
|
||||
const defaultSelectedWorktrees = useMemo(() => [worktree], [worktree])
|
||||
const effectiveSelectedWorktrees = selectedWorktrees ?? defaultSelectedWorktrees
|
||||
const updateWorktreeMeta = useAppStore((s) => s.updateWorktreeMeta)
|
||||
const workspaceStatuses = useAppStore((s) => s.workspaceStatuses)
|
||||
const openModal = useAppStore((s) => s.openModal)
|
||||
|
|
@ -217,7 +219,8 @@ const WorktreeContextMenu = React.memo(function WorktreeContextMenu({
|
|||
const deleteState = useAppStore((s) => s.deleteStateByWorktreeId[worktree.id])
|
||||
const [menuOpen, setMenuOpen] = useState(false)
|
||||
const [menuPoint, setMenuPoint] = useState({ x: 0, y: 0 })
|
||||
const [contextWorktrees, setContextWorktrees] = useState<readonly Worktree[]>(selectedWorktrees)
|
||||
const [contextWorktrees, setContextWorktrees] =
|
||||
useState<readonly Worktree[]>(effectiveSelectedWorktrees)
|
||||
const [createGroupDialogOpen, setCreateGroupDialogOpen] = useState(false)
|
||||
const isDeleting = deleteState?.isDeleting ?? false
|
||||
const repoMap = useRepoMap()
|
||||
|
|
@ -230,7 +233,7 @@ const WorktreeContextMenu = React.memo(function WorktreeContextMenu({
|
|||
const deleteStateByWorktreeId = useAppStore((s) => s.deleteStateByWorktreeId)
|
||||
const scopeRef = useRef<HTMLDivElement>(null)
|
||||
const contextMenuOpenedAtRef = useRef<number | null>(null)
|
||||
const activeContextWorktrees = menuOpen ? contextWorktrees : selectedWorktrees
|
||||
const activeContextWorktrees = menuOpen ? contextWorktrees : effectiveSelectedWorktrees
|
||||
const isMultiContext = activeContextWorktrees.length > 1
|
||||
const sleepableWorktrees = useMemo(
|
||||
() =>
|
||||
|
|
@ -469,7 +472,7 @@ const WorktreeContextMenu = React.memo(function WorktreeContextMenu({
|
|||
event.preventDefault()
|
||||
contextMenuOpenedAtRef.current = Date.now()
|
||||
window.dispatchEvent(new Event(CLOSE_ALL_CONTEXT_MENUS_EVENT))
|
||||
setContextWorktrees(onContextMenuSelect?.(event) ?? selectedWorktrees)
|
||||
setContextWorktrees(onContextMenuSelect?.(event) ?? effectiveSelectedWorktrees)
|
||||
const bounds = event.currentTarget.getBoundingClientRect()
|
||||
setMenuPoint({ x: event.clientX - bounds.left, y: event.clientY - bounds.top })
|
||||
setMenuOpenState(true)
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ const VirtualizedWorktreeViewport = React.memo(function VirtualizedWorktreeViewp
|
|||
reorderRepos,
|
||||
prCache,
|
||||
workspaceStatuses,
|
||||
projectGroups = [],
|
||||
projectGroups = EMPTY_PROJECT_GROUPS,
|
||||
onMoveWorktreeToStatus,
|
||||
onMoveWorktreesToStatus,
|
||||
onPinWorktree,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ import {
|
|||
} from './tab-agent-launch-options'
|
||||
import type { TuiAgent } from '../../../../shared/types'
|
||||
|
||||
const EMPTY_AGENT_OPTIONS: readonly TabAgentLaunchOption[] = []
|
||||
|
||||
type TabBarCreateEntryProps = {
|
||||
agentOptions?: readonly TabAgentLaunchOption[]
|
||||
groupId: string
|
||||
|
|
@ -28,7 +30,7 @@ type TabBarCreateEntryProps = {
|
|||
}
|
||||
|
||||
export default function TabBarCreateEntry({
|
||||
agentOptions = [],
|
||||
agentOptions = EMPTY_AGENT_OPTIONS,
|
||||
groupId,
|
||||
menuOpen,
|
||||
onDidOpenEntry,
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ type TerminalQuickCommandDialogProps = {
|
|||
onSave: (command: TerminalQuickCommand) => void
|
||||
}
|
||||
|
||||
const EMPTY_REPOS: Pick<Repo, 'id' | 'displayName' | 'path' | 'badgeColor'>[] = []
|
||||
|
||||
export function createTerminalQuickCommandDraft(
|
||||
scope: TerminalQuickCommandScope = { type: 'global' }
|
||||
): TerminalQuickCommand {
|
||||
|
|
@ -66,7 +68,7 @@ export function TerminalQuickCommandDialog({
|
|||
open,
|
||||
mode,
|
||||
command,
|
||||
repos = [],
|
||||
repos = EMPTY_REPOS,
|
||||
onOpenChange,
|
||||
onSave
|
||||
}: TerminalQuickCommandDialogProps): React.JSX.Element {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ function ToggleGroup({
|
|||
VariantProps<typeof toggleVariants> & {
|
||||
spacing?: number
|
||||
}) {
|
||||
const contextValue = React.useMemo(() => ({ variant, size, spacing }), [variant, size, spacing])
|
||||
|
||||
return (
|
||||
<ToggleGroupPrimitive.Root
|
||||
data-slot="toggle-group"
|
||||
|
|
@ -41,7 +43,7 @@ function ToggleGroup({
|
|||
)}
|
||||
{...props}
|
||||
>
|
||||
<ToggleGroupContext.Provider value={{ variant, size, spacing }}>
|
||||
<ToggleGroupContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</ToggleGroupContext.Provider>
|
||||
</ToggleGroupPrimitive.Root>
|
||||
|
|
|
|||
Loading…
Reference in New Issue