From 2eed4a3f605faecddf826b05f7f110a8e5a4743d Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Fri, 24 Apr 2026 03:32:57 +0700 Subject: [PATCH] chore(lint): no-array-index-key in app --- packages/app/src/components/callout-card.tsx | 2 +- packages/app/src/components/composer.tsx | 2 +- packages/app/src/components/diff-viewer.tsx | 16 ++++++--- packages/app/src/components/file-pane.tsx | 19 ++++++++--- packages/app/src/components/git-diff-pane.tsx | 34 ++++++++++--------- packages/app/src/components/message.tsx | 22 ++++++------ packages/app/src/components/pr-pane.tsx | 12 ++++--- .../app/src/components/question-form-card.tsx | 4 +-- .../sidebar-agent-list-skeleton.tsx | 10 ++++-- packages/app/src/components/synced-loader.tsx | 3 +- packages/app/src/components/ui/shortcut.tsx | 4 +-- 11 files changed, 78 insertions(+), 50 deletions(-) diff --git a/packages/app/src/components/callout-card.tsx b/packages/app/src/components/callout-card.tsx index 4bc92fa57..4bd2434a8 100644 --- a/packages/app/src/components/callout-card.tsx +++ b/packages/app/src/components/callout-card.tsx @@ -95,7 +95,7 @@ export function CalloutCard({ {visibleActions.map((action, index) => ( diff --git a/packages/app/src/components/composer.tsx b/packages/app/src/components/composer.tsx index 185534ee2..580583028 100644 --- a/packages/app/src/components/composer.tsx +++ b/packages/app/src/components/composer.tsx @@ -1156,7 +1156,7 @@ export function Composer({ if (attachment.kind === "image") { return ( {line.content[0]} - {line.segments.map((segment, segIdx) => ( - + {line.segments.map((segment) => ( + ))} ) : ( @@ -101,6 +105,10 @@ export function DiffViewer({ () => [styles.linesContainer, scrollViewWidth > 0 && { minWidth: scrollViewWidth }], [scrollViewWidth], ); + const keyedDiffLines = React.useMemo( + () => diffLines.map((line, index) => ({ key: `${index}-${line.type}-${line.content}`, line })), + [diffLines], + ); if (!diffLines.length) { return ( @@ -126,8 +134,8 @@ export function DiffViewer({ onLayout={handleInnerLayout} > - {diffLines.map((line, index) => ( - + {keyedDiffLines.map(({ key, line }) => ( + ))} diff --git a/packages/app/src/components/file-pane.tsx b/packages/app/src/components/file-pane.tsx index d5bf4f115..0ca0e08e4 100644 --- a/packages/app/src/components/file-pane.tsx +++ b/packages/app/src/components/file-pane.tsx @@ -105,15 +105,19 @@ const CodeLine = React.memo(function CodeLine({ () => [codeLineStyles.gutterText, { color: baseColor }], [baseColor], ); + const keyedTokens = useMemo( + () => tokens.map((token, index) => ({ key: `${index}-${token.text}`, token })), + [tokens], + ); return ( {String(lineNumber)} - {tokens.map((token, index) => ( + {keyedTokens.map(({ key, token }) => ( @@ -238,13 +242,18 @@ function FilePreviewBody({ } const lines = highlightedLines ?? [[{ text: preview.content ?? "", style: null }]]; + const keyedLines = lines.map((tokens, index) => ({ + key: `line-${index}`, + tokens, + lineNumber: index + 1, + })); const codeLines = ( - {lines.map((tokens, index) => ( + {keyedLines.map(({ key, tokens, lineNumber }) => ( tokens.map((token, index) => ({ key: `${index}-${token.text}`, token })), + [tokens], + ); + return ( - {tokens.map((token, index) => ( + {keyedTokens.map(({ key, token }) => ( rows.map((row, i) => ({ key: `row-${i}`, row })), [rows]); + if (wrapLines) { return ( - {rows.map((row, i) => { + {keyedRows.map(({ key, row }) => { if (row.kind === "header") { return ( - + {row.content} ); } return ( - {rows.map((row, i) => { + {keyedRows.map(({ key, row }) => { if (row.kind === "header") { return ( - + ); } const line = side === "left" ? row.left : row.right; return ( - {rows.map((row, i) => { + {keyedRows.map(({ key, row }) => { if (row.kind === "header") { return ( - + {row.content} ); } return ( diff --git a/packages/app/src/components/message.tsx b/packages/app/src/components/message.tsx index 4f3f64e93..bb08ed67f 100644 --- a/packages/app/src/components/message.tsx +++ b/packages/app/src/components/message.tsx @@ -421,8 +421,8 @@ export const UserMessage = memo(function UserMessage({ {hasImages ? ( - {images.map((image, index) => ( - + {images.map((image) => ( + ))} @@ -1416,6 +1416,10 @@ export const AssistantMessage = memo(function AssistantMessage({ }, [client, handleLinkPress, markdownParser, onInlinePathPress, serverId, workspaceRoot]); const blocks = useMemo(() => splitMarkdownBlocks(message), [message]); + const keyedBlocks = useMemo( + () => blocks.map((block, index) => ({ key: `${index}:${block.slice(0, 32)}`, block })), + [blocks], + ); const assistantContainerStyle = useMemo( () => [ @@ -1431,10 +1435,10 @@ export const AssistantMessage = memo(function AssistantMessage({ return ( - {blocks.map((block, index) => ( + {keyedBlocks.map(({ key, block }, index) => ( No tasks yet. ) : ( - items.map((item, idx) => ( - + items.map((item) => ( + )) )} diff --git a/packages/app/src/components/pr-pane.tsx b/packages/app/src/components/pr-pane.tsx index f6e3e99fa..4a6875a54 100644 --- a/packages/app/src/components/pr-pane.tsx +++ b/packages/app/src/components/pr-pane.tsx @@ -67,6 +67,10 @@ export function PrPane({ data }: { data: PrPaneData }) { const StateIcon = getStateIcon(data.state); const stateLabel = getStateLabel(data.state); const stateLabelStyle = useMemo(() => [styles.stateLabel, { color: stateColor }], [stateColor]); + const keyedActivity = useMemo( + () => data.activity.map((item, idx) => ({ key: `${item.author}-${item.kind}-${idx}`, item })), + [data.activity], + ); return ( @@ -116,8 +120,8 @@ export function PrPane({ data }: { data: PrPaneData }) { } > - {data.checks.map((check, idx) => ( - + {data.checks.map((check) => ( + ))} @@ -147,8 +151,8 @@ export function PrPane({ data }: { data: PrPaneData }) { } > - {data.activity.map((item, idx) => ( - + {keyedActivity.map(({ key, item }) => ( + ))} diff --git a/packages/app/src/components/question-form-card.tsx b/packages/app/src/components/question-form-card.tsx index 82170f66a..c64238858 100644 --- a/packages/app/src/components/question-form-card.tsx +++ b/packages/app/src/components/question-form-card.tsx @@ -356,7 +356,7 @@ export function QuestionFormCard({ permission, onRespond, isResponding }: Questi const otherText = otherTexts[qIndex] ?? ""; return ( - + {q.question} @@ -364,7 +364,7 @@ export function QuestionFormCard({ permission, onRespond, isResponding }: Questi {q.options.map((opt, optIndex) => ( `skeleton-section-${i}`); +const ROW_KEYS_BY_SECTION: readonly (readonly string[])[] = SECTION_OPACITIES.map((_, sIdx) => + [0, 1, 2].map((r) => `skeleton-row-${sIdx}-${r}`), +); function SkeletonPulse({ pulse, style }: { pulse: Animated.Value; style: StyleProp }) { const opacity = pulse.interpolate({ @@ -37,8 +41,8 @@ function SkeletonSection({ - {Array.from({ length: 3 }).map((__, rowIdx) => ( - + {ROW_KEYS_BY_SECTION[sectionIdx]?.map((key) => ( + @@ -76,7 +80,7 @@ export function SidebarAgentListSkeleton() { {SECTION_OPACITIES.map((sectionOpacity, sectionIdx) => ( `dot-${i}`); const sharedStepProgress = makeMutable(0); let sharedLoopStarted = false; @@ -91,7 +92,7 @@ export function SyncedLoader({ size = 10, color }: { size?: number; color: strin return ( - {displayChord.map(function (combo, index) { + {displayChord.map(function (combo) { return ( - + {formatShortcut(combo, shortcutOs)} );