Conversation
|
CodeAnt AI is reviewing your PR. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
CodeAnt AI is running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
| // Supports: | ||
| // # 1. Creation | ||
| // # 1۔ تخلیق | ||
| const OBS_HEADING_REGEX = /^#+\s*(\d+)\s*[.۔]\s*(.+)$/u; |
There was a problem hiding this comment.
Suggestion: The regex accepts any heading depth (##, ###, etc.) even though the expected format is a top-level story heading (# <number>...). This can incorrectly parse numbered subheadings as story metadata and produce wrong story number/title extraction. Restrict the pattern to a single # for the metadata heading. [incorrect condition logic]
Severity Level: Major ⚠️
- ❌ Subsection headings parsed as primary OBS story metadata.
- ❌ Story numbers/titles misaligned with actual markdown structure.
- ⚠️ Users confused when preview shows subsection titles as stories.Steps of Reproduction ✅
1. Create an OBS markdown file where the first heading in the file is a subsection rather
than the main story heading, for example:
- Line 1: `Intro text`
- Line 2: ``
- Line 3: `## 5. Subsection title`
- Line 4: ``
- Line 5: `# 5. Correct story title`
This file will be handled by `parseOBSMarkdown` in
`frontend/src/utils/obsParser.ts:70-82`.
2. On the OBS upload page (`frontend/src/pages/OBS.tsx`), select this markdown file so
that `handleFiles` calls `parseOBSMarkdownFiles(mdFiles)` at `OBS.tsx:17-27`, which
internally maps each file to `parseOBSMarkdown` at `obsParser.ts:90-96`.
3. Inside `parseOBSMarkdown`, the heading line is selected via `lines.find((l) =>
l.trim().startsWith("#"))` at `obsParser.ts:75`, which returns the first heading line `"##
5. Subsection title"`; this line is then passed to `extractHeadingData`.
4. `extractHeadingData` at `obsParser.ts:20-37` applies `OBS_HEADING_REGEX =
/^#+\s*(\d+)\s*[.۔]\s*(.+)$/u;` from `obsParser.ts:9`, which allows any number of `#`
characters (`^#+`), so `"## 5. Subsection title"` matches and yields `story_no = 5` and
`title = "Subsection title"`. This metadata is treated as the story's canonical
number/title (used in upload preview and persisted via `OBSUploadPreviewDialog` and the
API), even though the actual intended story heading `# 5. Correct story title` on line 5
is ignored, contrary to the UI's own expectation message `"Expected: '# 1. Title'"` in
`frontend/src/components/OBSViewDialog.tsx:155`.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** frontend/src/utils/obsParser.ts
**Line:** 9:9
**Comment:**
*Incorrect Condition Logic: The regex accepts any heading depth (`##`, `###`, etc.) even though the expected format is a top-level story heading (`# <number>...`). This can incorrectly parse numbered subheadings as story metadata and produce wrong story number/title extraction. Restrict the pattern to a single `#` for the metadata heading.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const normalized = headingLine.normalize("NFC"); | ||
|
|
||
| const match = normalized.match(OBS_HEADING_REGEX); |
There was a problem hiding this comment.
Suggestion: The heading parser validates candidates using l.trim().startsWith("#") but then matches the untrimmed headingLine against a start-anchored regex. Headings with leading whitespace or a UTF-8 BOM will be detected as headings and then rejected as invalid, causing valid markdown uploads/edits to fail. Normalize and trim (and strip BOM) before applying the regex. [logic error]
Severity Level: Critical 🚨
- ❌ OBS markdown uploads fail for indented heading lines.
- ❌ OBS editor rejects valid stories with indented headings.
- ⚠️ Users see confusing "Invalid OBS heading" errors.Steps of Reproduction ✅
1. Open the OBS upload page implemented in `frontend/src/pages/OBS.tsx` and select one or
more `.md` files via the file input that triggers `handleFiles` (see `OBS.tsx:42-49` for
the input and `handleFiles` wiring).
2. Ensure at least one markdown file has its story heading indented, e.g. first line `" #
1. Creation"` (leading spaces before `#`) or similar; this is read in `parseOBSMarkdown`
at `frontend/src/utils/obsParser.ts:70-75`, where `lines.find((l) =>
l.trim().startsWith("#"))` will correctly detect this indented line as a heading
candidate.
3. The original, untrimmed line (still containing leading spaces) is passed as
`headingLine` into `extractHeadingData` at `obsParser.ts:81` and normalized via `const
normalized = headingLine.normalize("NFC");` at `obsParser.ts:24` but never trimmed or
BOM-stripped before `normalized.match(OBS_HEADING_REGEX)` at `obsParser.ts:26`, so the
start-anchored regex `/^#+\s*(\d+)\s*[.۔]\s*(.+)$/u` fails to match because the string
starts with whitespace, not `#`.
4. `extractHeadingData` then throws `new Error("Invalid OBS heading. Expected '# 1. Title'
or '# 1۔ عنوان'")` at `obsParser.ts:28-31`, causing `parseOBSMarkdownFiles` at
`obsParser.ts:90-96` to reject; this rejection is caught in `handleFiles` in
`OBS.tsx:26-33`, which shows `toast.error(e.message)` and prevents preview/upload, even
though the heading format is semantically valid apart from leading whitespace.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** frontend/src/utils/obsParser.ts
**Line:** 24:26
**Comment:**
*Logic Error: The heading parser validates candidates using `l.trim().startsWith("#")` but then matches the untrimmed `headingLine` against a start-anchored regex. Headings with leading whitespace or a UTF-8 BOM will be detected as headings and then rejected as invalid, causing valid markdown uploads/edits to fail. Normalize and trim (and strip BOM) before applying the regex.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
CodeAnt AI finished reviewing your PR. |
|
A review was recently triggered for this PR. Please wait 50s before retriggering. |
Sequence DiagramThis diagram shows how OBS markdown files are parsed into stories with more tolerant headings and how story content and details are rendered with automatic text direction to support right-to-left languages. sequenceDiagram
participant User
participant OBSUI as OBS UI
participant Parser as OBS Parser
participant Storage
participant Dialog as Details dialog
User->>OBSUI: Upload OBS markdown file
OBSUI->>Parser: Parse markdown heading and text
Parser->>Parser: Normalize heading and extract story number and title
Parser-->>OBSUI: Return parsed OBS story
OBSUI->>Storage: Save or update OBS story
User->>OBSUI: Open story preview or editor
OBSUI->>OBSUI: Render content and fields with auto text direction
User->>Dialog: Open long details in dialog
Dialog->>Dialog: Show full text with auto direction or fallback message
Generated by CodeAnt AI |
|
A review was recently triggered for this PR. Please wait 30s before retriggering. |
| const headingLine = lines.find((l) => l.trim().startsWith("#")); | ||
|
|
||
| if (!headingLine) { | ||
| throw new Error("Invalid OBS markdown: missing heading"); | ||
| } | ||
|
|
||
| const match = headingLine.match(/^#+\s*(\d+)[.\s]+(.+)/); | ||
|
|
||
| if (!match) { | ||
| throw new Error("Invalid OBS heading. Expected format: '# 1. Title'"); | ||
| } | ||
|
|
||
| const story_no = Number(match[1]); | ||
| const title = match[2].trim(); | ||
| const { story_no, title } = extractHeadingData(headingLine); | ||
|
|
There was a problem hiding this comment.
🟠 Architect Review — HIGH
OBS markdown heading detection now finds lines with leading spaces using l.trim().startsWith("#"), but passes the untrimmed line into extractHeadingData, whose regex (^#+) requires # at the start of the string; headings like " # 1. Title" are still rejected instead of being accepted as intended.
Suggestion: Trim (or otherwise normalize) the heading line before calling extractHeadingData, so the regex sees # at the start, and ensure both file parsing and metadata extraction use this same normalization path for consistent behavior.
Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is an **Architect / Logical Review** comment left during a code review. These reviews are first-class, important findings — not optional suggestions. Do NOT dismiss this as a 'big architectural change' just because the title says architect review; most of these can be resolved with a small, localized fix once the intent is understood.
**Path:** frontend/src/utils/obsParser.ts
**Line:** 75:82
**Comment:**
*HIGH: OBS markdown heading detection now finds lines with leading spaces using `l.trim().startsWith("#")`, but passes the untrimmed line into `extractHeadingData`, whose regex (`^#+`) requires `#` at the start of the string; headings like `" # 1. Title"` are still rejected instead of being accepted as intended.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
If a suggested approach is provided above, use it as the authoritative instruction. If no explicit code suggestion is given, you MUST still draft and apply your own minimal, localized fix — do not punt back with 'no suggestion provided, review manually'. Keep the change as small as possible: add a guard clause, gate on a loading state, reorder an await, wrap in a conditional, etc. Do not refactor surrounding code or expand scope beyond the finding.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| {isTruncated && ( | ||
| <> | ||
| {triggerVariant === "text" && ( | ||
| <button | ||
| type="button" | ||
| onClick={handleOpen} | ||
| className="text-xs underline shrink-0" | ||
| > | ||
| See More | ||
| </button> | ||
| )} | ||
|
|
||
| {triggerVariant === "icon" && ( | ||
| <button | ||
| type="button" | ||
| onClick={handleOpen} | ||
| className="shrink-0 inline-flex items-center justify-center rounded-md | ||
| hover:bg-gray-200 transition-all group mt-1 p-1" | ||
| title="See More" | ||
| > | ||
| <MoreHorizontal className="w-5 h-5 text-gray-600 group-hover:text-gray-900" /> | ||
| </button> | ||
| )} | ||
| </> | ||
| )} | ||
| title="See More" | ||
| > | ||
| <MoreHorizontal className="w-5 h-5 text-gray-600 group-hover:text-gray-900" /> | ||
| </button> | ||
| )} | ||
| </> | ||
| )} |
There was a problem hiding this comment.
Suggestion: The fallback "No details available." is unreachable for empty values because the dialog trigger is rendered only when text is truncated. For empty text, isTruncated is false, so users cannot open the dialog and never see the fallback message. Render a trigger for empty values (or show the fallback inline) so the intended empty-state behavior is actually visible. [incomplete implementation]
Severity Level: Major ⚠️
- ⚠️ OBS upload preview hides empty story descriptions silently.
- ⚠️ Users never see intended "No details available" message.Steps of Reproduction ✅
1. Open the OBS admin page implemented in `frontend/src/pages/OBS.tsx` and trigger the
upload flow handled by `OBSDataAction`'s `handleFiles` function at lines 114–165 by
clicking the upload button when there is no OBS data.
2. Upload an ISL OBS CSV file where at least one row has `storyNo`, `title`, and `url`
populated but an empty `description` column; `parseISLOBSCSV` in
`frontend/src/utils/obsParser.ts` (lines 40–63) maps this row into an `OBSStory` with
`text` set to an empty string.
3. After parsing, `OBSDataAction` sets `rows` and opens `OBSUploadPreviewDialog` (OBS.tsx
lines 139–143 and 193–204), which renders its preview table in
`frontend/src/components/OBSUploadPreviewDialog.tsx` using a `DetailsDialog` for the
"Text" column at lines 72–80 with `text={row.original.text}` and `limit={40}`.
4. For the row with empty `text`, `DetailsDialog` in
`frontend/src/components/DetailsDialog.tsx` computes `value = text ?? ""` (line 29),
`isTruncated = value.length > limit` (line 31) which is `false` for `""`, and `display`
returns `""` because `!value` (line 40); since `isTruncated` is false, the trigger block
guarded by `{isTruncated && (...)}` (lines 66–90) is not rendered, so `handleOpen` (line
51) is never invoked and the dialog never opens, meaning the fallback `{value || "No
details available."}` (lines 101–103) is unreachable for this empty-state row.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** frontend/src/components/DetailsDialog.tsx
**Line:** 66:90
**Comment:**
*Incomplete Implementation: The fallback `"No details available."` is unreachable for empty values because the dialog trigger is rendered only when text is truncated. For empty text, `isTruncated` is false, so users cannot open the dialog and never see the fallback message. Render a trigger for empty values (or show the fallback inline) so the intended empty-state behavior is actually visible.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
CodeAnt AI finished running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
CodeAnt AI is running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
Sequence DiagramThis PR improves OBS parsing to handle flexible headings and Arabic punctuation, and updates story and details views to auto-detect text direction and show a clear fallback when details are empty. sequenceDiagram
participant User
participant Frontend
participant OBSParser
participant DetailsDialog
User->>Frontend: Upload OBS markdown or CSV
Frontend->>OBSParser: Parse OBS content for stories
OBSParser->>OBSParser: Normalize headers and headings with English and Arabic punctuation
OBSParser-->>Frontend: Return parsed OBS stories with story number and title
User->>Frontend: Open OBS story details
Frontend->>DetailsDialog: Show story text in dialog
DetailsDialog->>DetailsDialog: Auto detect text direction and apply layout with fallback text
DetailsDialog-->>User: Display OBS details with correct RTL or LTR rendering
Generated by CodeAnt AI |
| ISL_HEADERS.every((h) => | ||
| headers.map((x) => x.toLowerCase()).includes(h.toLowerCase()), | ||
| ); | ||
| ISL_HEADERS.every((h) => headers.map(cleanHeader).includes(h.toLowerCase())); |
There was a problem hiding this comment.
Suggestion: Header validation now accepts case/spacing/BOM variants, but row extraction still reads fixed keys (row.storyNo, row.title, etc.). This creates a contract mismatch: files that pass validation can still parse into NaN/undefined fields at runtime. Normalize the row keys (or remap headers from meta.fields) before reading values so accepted header variants are actually supported. [api mismatch]
Severity Level: Critical 🚨
- ❌ ISL OBS CSV uploads create stories with NaN story numbers.
- ❌ Backend receives malformed OBS stories undermining data integrity.
- ⚠️ Preview table shows blank titles/text for affected CSV rows.Steps of Reproduction ✅
1. In `frontend/src/pages/OBS.tsx:114-145`, a user without existing OBS data clicks the
upload icon, selects a single `.csv` file, and `handleFiles()` detects `hasCSV` as true
and calls `parseISLOBSCSV(arr[0])`.
2. The CSV file's header row contains variants like `" StoryNo"` or `"StoryNo"` (different
casing/spacing/BOM) instead of the exact `"storyNo"`. Papa.parse (see
`frontend/src/utils/obsParser.ts:40-45`) parses with `header: true`, so `meta.fields`
contains these raw header strings and each `row` object is keyed with the same raw header
names.
3. `isISLOBSCSV()` at `frontend/src/utils/obsParser.ts:17-18` maps `headers` through
`cleanHeader()` (lines 11-15), stripping BOM, trimming, and lowercasing, so the normalized
headers include `"storyno"`, `"title"`, `"url"`, `"description"`, and the CSV is accepted
as valid.
4. Still in `parseISLOBSCSV()` (lines 56-62), the mapper reads `row.storyNo`, `row.title`,
`row.url`, and `row.description`, but because the actual keys are e.g. `" StoryNo"` or
`"StoryNo"`, these properties are `undefined`. `Number(row.storyNo)` becomes `NaN`, and
`title`, `url`, and `text` fields become `undefined` in the resulting `OBSStory[]`.
5. Back in `frontend/src/pages/OBS.tsx:20-23`, the parsed rows (with `story_no: NaN`,
`title/text: undefined`) are saved into `rows` state and shown in `OBSUploadPreviewDialog`
(see `frontend/src/components/OBSUploadPreviewDialog.tsx:20-27,46-83`), and then uploaded
via `handleUpload()` (lines 30-37), sending malformed `OBSStory` objects to the backend.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** frontend/src/utils/obsParser.ts
**Line:** 18:18
**Comment:**
*Api Mismatch: Header validation now accepts case/spacing/BOM variants, but row extraction still reads fixed keys (`row.storyNo`, `row.title`, etc.). This creates a contract mismatch: files that pass validation can still parse into `NaN`/`undefined` fields at runtime. Normalize the row keys (or remap headers from `meta.fields`) before reading values so accepted header variants are actually supported.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
CodeAnt AI finished running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
CodeAnt AI is running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
Sequence DiagramThis PR updates OBS parsing and dialogs so story headings are parsed from multiple heading styles and all OBS text areas render with automatic left to right or right to left direction and a clear fallback when details are empty. sequenceDiagram
participant User
participant OBSImportUI
participant OBSParser
participant OBSViewer
participant DetailsDialog
participant Browser
User->>OBSImportUI: Upload OBS markdown or CSV
OBSImportUI->>OBSParser: Parse OBS file
OBSParser->>OBSParser: Normalize headers and extract story number and title
OBSParser-->>OBSImportUI: OBS stories with titles and text
User->>OBSViewer: Open OBS story dialog
OBSViewer->>Browser: Render preview or editor with auto text direction
User->>DetailsDialog: Open story details
DetailsDialog->>Browser: Render details with auto direction and fallback text
Generated by CodeAnt AI |
|
CodeAnt AI is running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
| export const isISLOBSCSV = (headers: string[]) => | ||
| ISL_HEADERS.every((h) => | ||
| headers.map((x) => x.toLowerCase()).includes(h.toLowerCase()), | ||
| ); | ||
| ISL_HEADERS.every((h) => headers.map(cleanHeader).includes(h.toLowerCase())); |
There was a problem hiding this comment.
🔴 Architect Review — CRITICAL
Header validation now normalizes casing/whitespace/BOM (isISLOBSCSV), but row extraction still reads raw keys storyNo, title, url, description from Papa rows. CSVs whose headers differ in case or include leading/trailing spaces/BOM will pass validation but produce undefined/NaN fields during import.
Suggestion: Normalize headers at parse time (e.g., via Papa's transformHeader that strips BOM, trims, and lowercases) and access row fields using these normalized keys, rejecting rows that are missing required normalized fields before upload.
Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is an **Architect / Logical Review** comment left during a code review. These reviews are first-class, important findings — not optional suggestions. Do NOT dismiss this as a 'big architectural change' just because the title says architect review; most of these can be resolved with a small, localized fix once the intent is understood.
**Path:** frontend/src/utils/obsParser.ts
**Line:** 17:18
**Comment:**
*CRITICAL: Header validation now normalizes casing/whitespace/BOM (`isISLOBSCSV`), but row extraction still reads raw keys `storyNo`, `title`, `url`, `description` from Papa rows. CSVs whose headers differ in case or include leading/trailing spaces/BOM will pass validation but produce undefined/NaN fields during import.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
If a suggested approach is provided above, use it as the authoritative instruction. If no explicit code suggestion is given, you MUST still draft and apply your own minimal, localized fix — do not punt back with 'no suggestion provided, review manually'. Keep the change as small as possible: add a guard clause, gate on a loading state, reorder an await, wrap in a conditional, etc. Do not refactor surrounding code or expand scope beyond the finding.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const normalized = headingLine.normalize("NFC"); | ||
|
|
||
| const match = normalized.match(OBS_HEADING_REGEX); | ||
|
|
There was a problem hiding this comment.
🟠 Architect Review — HIGH
Heading detection uses l.trim().startsWith("#"), but extractHeadingData matches the untrimmed line against a ^#+-anchored regex, so headings with leading spaces (e.g., " # 1. Title") are detected but then rejected, leaving leading-space support incomplete.
Suggestion: Normalize the heading line (e.g., trim leading whitespace) before applying OBS_HEADING_REGEX in extractHeadingData so detection and extraction accept the same set of headings in both markdown upload and metadata edit flows.
Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is an **Architect / Logical Review** comment left during a code review. These reviews are first-class, important findings — not optional suggestions. Do NOT dismiss this as a 'big architectural change' just because the title says architect review; most of these can be resolved with a small, localized fix once the intent is understood.
**Path:** frontend/src/utils/obsParser.ts
**Line:** 24:27
**Comment:**
*HIGH: Heading detection uses `l.trim().startsWith("#")`, but `extractHeadingData` matches the untrimmed line against a `^#+`-anchored regex, so headings with leading spaces (e.g., " # 1. Title") are detected but then rejected, leaving leading-space support incomplete.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
If a suggested approach is provided above, use it as the authoritative instruction. If no explicit code suggestion is given, you MUST still draft and apply your own minimal, localized fix — do not punt back with 'no suggestion provided, review manually'. Keep the change as small as possible: add a guard clause, gate on a loading state, reorder an await, wrap in a conditional, etc. Do not refactor surrounding code or expand scope beyond the finding.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| export const isISLOBSCSV = (headers: string[]) => | ||
| ISL_HEADERS.every((h) => | ||
| headers.map((x) => x.toLowerCase()).includes(h.toLowerCase()), | ||
| ); | ||
| ISL_HEADERS.every((h) => headers.map(cleanHeader).includes(h.toLowerCase())); |
There was a problem hiding this comment.
Suggestion: The header check now accepts normalized CSV headers (trimmed/lowercased/BOM-stripped), but the parser still reads rows using fixed property names like row.storyNo. When a file passes validation with headers such as " storyNo " or different casing, parsed fields become undefined/NaN at runtime. Normalize header keys before row mapping (or map columns by resolved header names) so accepted files are parsed correctly. [api mismatch]
Severity Level: Critical 🚨
- ❌ ISL OBS CSVs with BOM/spaces parse into NaN/undefined data.
- ❌ OBS upload preview shows invalid story numbers and empty fields.
- ❌ Backend receives malformed OBS stories through `uploadOBS`.
- ⚠️ DetailsDialog receives undefined text, compounding empty-state issues.Steps of Reproduction ✅
1. Prepare an ISL OBS CSV where the first header has a BOM or spaces, e.g. `"storyNo
,Title,Url,Description"` (note the hidden BOM / space before `storyNo`). PapaParse will
expose headers as `meta.fields` with the raw names including BOM/spacing.
2. In `frontend/src/utils/obsParser.ts:11-18`, `isISLOBSCSV()` is called from
`parseISLOBSCSV()` (line 47). It transforms `headers` with `cleanHeader()` (stripping BOM,
trimming, lowercasing) and successfully validates the file because `"storyNo "` normalizes
to `"storyno"`, which matches `ISL_HEADERS`.
3. Still in `parseISLOBSCSV()` at lines 56-62, the mapping uses fixed property names
`row.storyNo`, `row.title`, `row.url`, and `row.description`. However, PapaParse keys
`row` by the raw header names (e.g. `"storyNo "`), so `row.storyNo` and the other fields
are `undefined`, producing `story_no: Number(undefined)` (`NaN`) and `title`, `url`,
`text` as `undefined`.
4. In `frontend/src/pages/OBS.tsx:32-44`, `handleFiles()` calls `parseISLOBSCSV(arr[0])`
and passes the resulting `OBSStory[]` (containing `NaN` and `undefined` values) to
`OBSUploadPreviewDialog` (`rows` prop) and later to `uploadOBS` via
`OBSUploadPreviewDialog.handleUpload()`
(`frontend/src/components/OBSUploadPreviewDialog.tsx:30-39` and
`frontend/src/utils/api.ts:14-19`), leading to a preview table with broken data and
potentially invalid payloads sent to the backend.Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** frontend/src/utils/obsParser.ts
**Line:** 17:18
**Comment:**
*Api Mismatch: The header check now accepts normalized CSV headers (trimmed/lowercased/BOM-stripped), but the parser still reads rows using fixed property names like `row.storyNo`. When a file passes validation with headers such as `" storyNo "` or different casing, parsed fields become `undefined`/`NaN` at runtime. Normalize header keys before row mapping (or map columns by resolved header names) so accepted files are parsed correctly.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
CodeAnt AI finished running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
Sequence DiagramThis PR improves how OBS content is imported and displayed by making CSV and markdown parsing more tolerant and ensuring story text and details dialogs render with automatic text direction, especially for RTL languages. sequenceDiagram
participant User
participant OBSImportUI
participant OBSParser
participant OBSViewer
User->>OBSImportUI: Upload OBS CSV or markdown file
OBSImportUI->>OBSParser: Parse headers and headings with tolerant matching
OBSParser-->>OBSImportUI: Return parsed OBS stories with story number and title
User->>OBSImportUI: Open story or details dialog
OBSImportUI->>OBSViewer: Render story text with automatic text direction
OBSViewer-->>User: Show correctly oriented text or fallback when details are empty
Generated by CodeAnt AI |
|
A review was recently triggered for this PR. Please wait 24s before retriggering. |
|
CodeAnt AI is running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
| .trim() | ||
| .toLowerCase(); | ||
|
|
||
| export const isISLOBSCSV = (headers: string[]) => |
There was a problem hiding this comment.
🔴 Architect Review — CRITICAL
CSV header normalization is only applied during validation (isISLOBSCSV), but parseISLOBSCSV still reads hard-coded keys (row.storyNo, row.title, etc.). For CSVs whose headers differ by case/spacing/BOM (which now pass validation via cleanHeader), the parsed row fields become undefined/NaN, so the preview and subsequent upload operate on invalid OBS data.
Suggestion: Normalize headers at parse time (e.g., via Papa.parse transformHeader or a canonical header-to-field mapping) so row access uses the normalized keys, and add row-level validation to reject records with invalid story_no/title/url/description with a clear import error instead of uploading bad data.
Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is an **Architect / Logical Review** comment left during a code review. These reviews are first-class, important findings — not optional suggestions. Do NOT dismiss this as a 'big architectural change' just because the title says architect review; most of these can be resolved with a small, localized fix once the intent is understood.
**Path:** frontend/src/utils/obsParser.ts
**Line:** 17:62
**Comment:**
*CRITICAL: CSV header normalization is only applied during validation (`isISLOBSCSV`), but `parseISLOBSCSV` still reads hard-coded keys (`row.storyNo`, `row.title`, etc.). For CSVs whose headers differ by case/spacing/BOM (which now pass validation via `cleanHeader`), the parsed row fields become `undefined`/`NaN`, so the preview and subsequent upload operate on invalid OBS data.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
If a suggested approach is provided above, use it as the authoritative instruction. If no explicit code suggestion is given, you MUST still draft and apply your own minimal, localized fix — do not punt back with 'no suggestion provided, review manually'. Keep the change as small as possible: add a guard clause, gate on a loading state, reorder an await, wrap in a conditional, etc. Do not refactor surrounding code or expand scope beyond the finding.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
Sequence DiagramThis PR updates OBS parsing to handle RTL headings and tolerant CSV headers, and adjusts dialogs so OBS and detail text render with automatic reading direction and a clear empty-state message. sequenceDiagram
participant User
participant OBSView
participant OBSParser
participant MarkdownRenderer
participant DetailsDialog
User->>OBSView: Upload OBS markdown or CSV
OBSView->>OBSParser: Parse OBS heading and story text
OBSParser-->>OBSView: Story number, title, text
OBSView->>MarkdownRenderer: Render story with auto direction
MarkdownRenderer-->>User: Show correctly ordered OBS content
User->>DetailsDialog: Click See More for details
DetailsDialog->>DetailsDialog: Pick text or default message
DetailsDialog-->>User: Show dialog with auto direction content
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
| .trim() | ||
| .toLowerCase(); | ||
|
|
||
| export const isISLOBSCSV = (headers: string[]) => |
There was a problem hiding this comment.
🟠 Architect Review — HIGH
CSV header normalization via cleanHeader is only applied during header validation in isISLOBSCSV, not to the actual row keys. For headers that cleanHeader newly accepts (e.g. with BOM or leading/trailing spaces), parseISLOBSCSV still reads row.storyNo, row.title, row.url, and row.description based on the unnormalized header names, so those properties are undefined and story_no becomes NaN, causing failed or corrupted uploads for exactly the CSVs this change is meant to support.
Suggestion: Normalize headers at parse time (for example by using Papa.parse's transformHeader with the same cleanHeader logic) and build OBSStory objects from these canonical keys so header validation and row extraction stay consistent for all accepted header variants.
Fix in Cursor | Fix in VSCode Claude
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is an **Architect / Logical Review** comment left during a code review. These reviews are first-class, important findings — not optional suggestions. Do NOT dismiss this as a 'big architectural change' just because the title says architect review; most of these can be resolved with a small, localized fix once the intent is understood.
**Path:** frontend/src/utils/obsParser.ts
**Line:** 17:62
**Comment:**
*HIGH: CSV header normalization via `cleanHeader` is only applied during header validation in `isISLOBSCSV`, not to the actual row keys. For headers that `cleanHeader` newly accepts (e.g. with BOM or leading/trailing spaces), `parseISLOBSCSV` still reads `row.storyNo`, `row.title`, `row.url`, and `row.description` based on the unnormalized header names, so those properties are `undefined` and `story_no` becomes `NaN`, causing failed or corrupted uploads for exactly the CSVs this change is meant to support.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
If a suggested approach is provided above, use it as the authoritative instruction. If no explicit code suggestion is given, you MUST still draft and apply your own minimal, localized fix — do not punt back with 'no suggestion provided, review manually'. Keep the change as small as possible: add a guard clause, gate on a loading state, reorder an await, wrap in a conditional, etc. Do not refactor surrounding code or expand scope beyond the finding.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
CodeAnt AI finished running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
CodeAnt AI is running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
Sequence DiagramThis diagram shows how OBS files are parsed with RTL-aware headings and then rendered with automatic text direction, plus how the details dialog provides a readable fallback when no content is available. sequenceDiagram
participant User
participant OBSUI
participant Parser
participant ViewDialog
participant DetailsDialog
User->>OBSUI: Upload OBS markdown or CSV
OBSUI->>Parser: Parse OBS file headers and text
Parser->>Parser: Normalize heading and extract story number and title
Parser-->>OBSUI: Return OBS story with metadata
OBSUI->>ViewDialog: Open OBS preview or editor with story text
ViewDialog->>ViewDialog: Render content with automatic text direction
User->>DetailsDialog: Open details dialog
DetailsDialog->>DetailsDialog: Show details text or fallback message when empty
Generated by CodeAnt AI |
|
CodeAnt AI finished running the review. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
User description
CodeAnt-AI Description
Support right-to-left OBS content and show empty details clearly
What Changed
Impact
✅ Correct RTL display in OBS✅ Fewer import failures for Arabic OBS files✅ Clearer empty-state details🔄 Retrigger CodeAnt AI Review
Details
💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.