From 1f1a025509bedc7e5b7f5409d2a1afd97c8a521a Mon Sep 17 00:00:00 2001
From: Chaim
Date: Sat, 6 Jun 2026 13:29:30 +0000
Subject: [PATCH] =?UTF-8?q?fix(lint):=20=D7=AA=D7=99=D7=A7=D7=95=D7=9F=201?=
=?UTF-8?q?0=20=D7=A9=D7=92=D7=99=D7=90=D7=95=D7=AA=20ESLint=20+=20=D7=A0?=
=?UTF-8?q?=D7=99=D7=A7=D7=95=D7=99=20directives=20=D7=9E=D7=99=D7=95?=
=?UTF-8?q?=D7=AA=D7=A8=D7=99=D7=9D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
10 שגיאות (כולן קיימות-מראש, לא מהפיצ'רים האחרונים):
- react/no-unescaped-entities (3): legal-arguments-panel, precedent-edit-sheet
— escaping של מרכאות ב-JSX (“/")
- react-hooks/set-state-in-effect (6): documents-panel, chair-editor,
content-checklists, discussion-rules, golden-ratios, documents.ts
— disable-comment לדפוסי sync/reset לגיטימיים (false-positive ידוע)
- React Compiler reassign (1): subject-donut — refactor לחישוב prefix-sums
ללא mutable accumulator
ניקוי: הסרת 5 eslint-disable directives מיותרים (halacha-review-panel,
precedent-upload-sheet). תוצאה: 0 errors (היה 10), 24→ warnings (היה 29).
Co-Authored-By: Claude Opus 4.8 (1M context)
---
web-ui/src/components/cases/documents-panel.tsx | 2 ++
web-ui/src/components/cases/legal-arguments-panel.tsx | 2 +-
web-ui/src/components/compose/chair-editor.tsx | 1 +
.../components/methodology/content-checklists-panel.tsx | 1 +
.../components/methodology/discussion-rules-panel.tsx | 1 +
.../src/components/methodology/golden-ratios-panel.tsx | 1 +
.../src/components/precedents/halacha-review-panel.tsx | 1 -
.../src/components/precedents/precedent-edit-sheet.tsx | 2 +-
.../src/components/precedents/precedent-upload-sheet.tsx | 6 +-----
web-ui/src/components/training/subject-donut.tsx | 9 +++++----
web-ui/src/lib/api/documents.ts | 1 +
11 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/web-ui/src/components/cases/documents-panel.tsx b/web-ui/src/components/cases/documents-panel.tsx
index 3c53f57..6bda427 100644
--- a/web-ui/src/components/cases/documents-panel.tsx
+++ b/web-ui/src/components/cases/documents-panel.tsx
@@ -107,8 +107,10 @@ function DocumentPreviewDialog({
useEffect(() => {
if (!open) {
+ /* eslint-disable react-hooks/set-state-in-effect -- reset on close */
setText(null);
setError(null);
+ /* eslint-enable react-hooks/set-state-in-effect */
return;
}
let cancelled = false;
diff --git a/web-ui/src/components/cases/legal-arguments-panel.tsx b/web-ui/src/components/cases/legal-arguments-panel.tsx
index bb591a9..5783d76 100644
--- a/web-ui/src/components/cases/legal-arguments-panel.tsx
+++ b/web-ui/src/components/cases/legal-arguments-panel.tsx
@@ -203,7 +203,7 @@ export function LegalArgumentsPanel({ caseNumber }: LegalArgumentsPanelProps) {
) : !data?.total ? (
- אין טיעונים מאוגדים עדיין. לחץ "חשב טיעונים" כדי להריץ את ה-aggregator.
+ אין טיעונים מאוגדים עדיין. לחץ “חשב טיעונים” כדי להריץ את ה-aggregator.
) : (
diff --git a/web-ui/src/components/compose/chair-editor.tsx b/web-ui/src/components/compose/chair-editor.tsx
index c122796..61cc86d 100644
--- a/web-ui/src/components/compose/chair-editor.tsx
+++ b/web-ui/src/components/compose/chair-editor.tsx
@@ -34,6 +34,7 @@ export function ChairEditor({
/* Reset when the upstream analysis refetches (e.g. after initial load) */
useEffect(() => {
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- sync from server
setValue(initialValue);
lastSaved.current = initialValue;
}, [initialValue]);
diff --git a/web-ui/src/components/methodology/content-checklists-panel.tsx b/web-ui/src/components/methodology/content-checklists-panel.tsx
index 6e3970e..bbd945d 100644
--- a/web-ui/src/components/methodology/content-checklists-panel.tsx
+++ b/web-ui/src/components/methodology/content-checklists-panel.tsx
@@ -49,6 +49,7 @@ export function ContentChecklistsPanel() {
useEffect(() => {
if (!data?.items) return;
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- sync from server
setItems(
CHECKLIST_ORDER
.filter((k) => k in data.items)
diff --git a/web-ui/src/components/methodology/discussion-rules-panel.tsx b/web-ui/src/components/methodology/discussion-rules-panel.tsx
index e736837..e1daf76 100644
--- a/web-ui/src/components/methodology/discussion-rules-panel.tsx
+++ b/web-ui/src/components/methodology/discussion-rules-panel.tsx
@@ -40,6 +40,7 @@ export function DiscussionRulesPanel() {
useEffect(() => {
if (!data?.items) return;
const order = ["universal", "rejection", "partial_acceptance", "full_acceptance", "betterment_levy"];
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- sync from server
setSections(
order
.filter((k) => k in data.items)
diff --git a/web-ui/src/components/methodology/golden-ratios-panel.tsx b/web-ui/src/components/methodology/golden-ratios-panel.tsx
index af1f214..767dd43 100644
--- a/web-ui/src/components/methodology/golden-ratios-panel.tsx
+++ b/web-ui/src/components/methodology/golden-ratios-panel.tsx
@@ -46,6 +46,7 @@ export function GoldenRatiosPanel() {
// Sync from server
useEffect(() => {
if (!data?.items) return;
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- sync from server
setCards(
Object.entries(data.items).map(([key, item]) => ({
key,
diff --git a/web-ui/src/components/precedents/halacha-review-panel.tsx b/web-ui/src/components/precedents/halacha-review-panel.tsx
index 302b27b..fcd6b3e 100644
--- a/web-ui/src/components/precedents/halacha-review-panel.tsx
+++ b/web-ui/src/components/precedents/halacha-review-panel.tsx
@@ -474,7 +474,6 @@ function PendingPanel() {
useEffect(() => {
if (focusedId === null) return;
if (visibleItems.some((h) => h.id === focusedId)) return;
- // eslint-disable-next-line react-hooks/set-state-in-effect
setFocusedId(visibleItems[0]?.id ?? null);
}, [focusedId, visibleItems]);
diff --git a/web-ui/src/components/precedents/precedent-edit-sheet.tsx b/web-ui/src/components/precedents/precedent-edit-sheet.tsx
index 440e1e5..8460850 100644
--- a/web-ui/src/components/precedents/precedent-edit-sheet.tsx
+++ b/web-ui/src/components/precedents/precedent-edit-sheet.tsx
@@ -239,7 +239,7 @@ export function PrecedentEditSheet({ caseLawId, onOpenChange }: Props) {
-
+
setForm({ ...form, chair_name: e.target.value })}
placeholder="" />
diff --git a/web-ui/src/components/precedents/precedent-upload-sheet.tsx b/web-ui/src/components/precedents/precedent-upload-sheet.tsx
index 1b35191..3329767 100644
--- a/web-ui/src/components/precedents/precedent-upload-sheet.tsx
+++ b/web-ui/src/components/precedents/precedent-upload-sheet.tsx
@@ -75,15 +75,11 @@ export function PrecedentUploadSheet({ open, onOpenChange }: Props) {
useEffect(() => {
if (open) return;
- // eslint-disable-next-line react-hooks/set-state-in-effect
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- reset form on close
setFile(null); setCitation(""); setCaseName(""); setCourt("");
- // eslint-disable-next-line react-hooks/set-state-in-effect
setDecisionDate(""); setSourceType(""); setPrecedentLevel("");
- // eslint-disable-next-line react-hooks/set-state-in-effect
setPracticeArea(""); setAppealSubtype(""); setSubjectTags("");
- // eslint-disable-next-line react-hooks/set-state-in-effect
setHeadnote(""); setIsBinding(true); setTaskId(null); setConflict(null);
- // eslint-disable-next-line react-hooks/set-state-in-effect
setChairName(""); setDistrict(""); setCaseNumber("");
}, [open]);
diff --git a/web-ui/src/components/training/subject-donut.tsx b/web-ui/src/components/training/subject-donut.tsx
index 48f961c..4ec4d44 100644
--- a/web-ui/src/components/training/subject-donut.tsx
+++ b/web-ui/src/components/training/subject-donut.tsx
@@ -25,11 +25,12 @@ export function SubjectDonut({
segments: Array<{ label: string; count: number }>;
total: number;
}) {
- let pct = 0;
+ // Prefix sums without a mutable outer accumulator (React Compiler rejects
+ // reassigning a let after render). segments is tiny, so O(n²) is fine.
const parts = segments.map((s, i) => {
- const start = total === 0 ? 0 : (pct / total) * 360;
- pct += s.count;
- const end = total === 0 ? 360 : (pct / total) * 360;
+ const before = segments.slice(0, i).reduce((acc, x) => acc + x.count, 0);
+ const start = total === 0 ? 0 : (before / total) * 360;
+ const end = total === 0 ? 360 : ((before + s.count) / total) * 360;
return { ...s, start, end, color: DONUT_COLORS[i % DONUT_COLORS.length] };
});
diff --git a/web-ui/src/lib/api/documents.ts b/web-ui/src/lib/api/documents.ts
index c76264f..a734433 100644
--- a/web-ui/src/lib/api/documents.ts
+++ b/web-ui/src/lib/api/documents.ts
@@ -217,6 +217,7 @@ export function useProgress(taskId: string | null, caseNumber?: string) {
useEffect(() => {
if (!taskId) return;
+ // eslint-disable-next-line react-hooks/set-state-in-effect -- reset on taskId change
setEvent(null);
/* Self-heal fallback: if no SSE message arrives within 10s — usually
--
2.49.1