Skip to content

csv result copy#4091

Open
souissimai wants to merge 2 commits into
mainfrom
copy_csv_security_analysis
Open

csv result copy#4091
souissimai wants to merge 2 commits into
mainfrom
copy_csv_security_analysis

Conversation

@souissimai

Copy link
Copy Markdown
Contributor

PR Summary

Signed-off-by: SOUISSI Maissa (Externe) <souissimai@gm0winl878.bureau.si.interne>
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Security analysis results add a CSV copy action that extracts and converts CSV data from a ZIP blob, while export and copy share translated enum values supplied by the result tab.

Security analysis actions

Layer / File(s) Summary
Translation mapping and action wiring
src/components/results/securityanalysis/security-analysis-result-tab.tsx
The result tab builds translated enum labels, adds the copy/export actions layout, and passes shared inputs to both controls.
CSV extraction and clipboard flow
src/components/results/securityanalysis/security-analysis-copy-button.tsx, package.json
The new copy button extracts CSV data with fflate, converts separators, copies the result, and manages loading, success, and error states.
Export translation input refactor
src/components/results/securityanalysis/security-analysis-export-button.tsx
The export button receives translated enum values through props instead of deriving them internally.

Sequence Diagram(s)

sequenceDiagram
  participant ResultTab
  participant SecurityAnalysisCopyButton
  participant downloadZipResult
  participant fflate
  participant Clipboard
  ResultTab->>SecurityAnalysisCopyButton: provide translated values and download callback
  SecurityAnalysisCopyButton->>downloadZipResult: request ZIP result
  downloadZipResult-->>SecurityAnalysisCopyButton: return ZIP Blob
  SecurityAnalysisCopyButton->>fflate: extract first CSV
  fflate-->>SecurityAnalysisCopyButton: return CSV text
  SecurityAnalysisCopyButton->>Clipboard: copy converted CSV
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description is only a placeholder template and does not describe the changes. Replace the placeholder with a brief summary of the new CSV copy behavior and related export button updates.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: adding CSV result copying for security analysis.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/results/securityanalysis/security-analysis-copy-button.tsx`:
- Line 50: Remove the entryNames[0] fallback from the csvEntryName assignment in
the security analysis copy-button logic, leaving it undefined when no .csv file
exists so the existing !csvEntryName check fails loudly for unexpected archive
contents.
- Around line 63-71: The convertDelimiter function must preserve CSV quoting,
embedded separators, and newlines instead of using plain split operations.
Replace its line and delimiter splitting with a CSV-aware parser and serializer,
while retaining the early return when separators match and ensuring equivalent
valid CSV output with the requested delimiter.
- Around line 46-57: Replace synchronous unzipSync usage in
extractCsvTextFromZipBlob with fflate’s asynchronous unzip API, awaiting
decompression before selecting and decoding the CSV entry. Preserve the existing
fallback entry selection, missing-entry error, UTF-8 decoding, and BOM removal
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4723026b-ba1f-4a32-b600-5a0b6ac2891d

📥 Commits

Reviewing files that changed from the base of the PR and between e1e6467 and 2b1f0e8.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • package.json
  • src/components/results/securityanalysis/security-analysis-copy-button.tsx
  • src/components/results/securityanalysis/security-analysis-export-button.tsx
  • src/components/results/securityanalysis/security-analysis-result-tab.tsx

Comment on lines +46 to +57
async function extractCsvTextFromZipBlob(blob: Blob): Promise<string> {
const buffer = new Uint8Array(await blob.arrayBuffer());
const unzipped = unzipSync(buffer);
const entryNames = Object.keys(unzipped);
const csvEntryName = entryNames.find((name) => name.toLowerCase().endsWith('.csv')) ?? entryNames[0];
if (!csvEntryName) {
throw new Error('No CSV entry found in zip archive');
}
// Decode as UTF-8 and strip a potential BOM (backend prefixes result.csv with one)
const text = new TextDecoder('utf-8').decode(unzipped[csvEntryName]);
return text.replace(/^\uFEFF/, '');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## target file\n'
git ls-files 'src/components/results/securityanalysis/security-analysis-copy-button.tsx'

printf '\n## package references\n'
rg -n '"fflate"|from '\''fflate'\''|from "fflate"' package.json pnpm-lock.yaml yarn.lock package-lock.json src -g '!**/node_modules/**'

printf '\n## inspect target file (bounded)\n'
wc -l src/components/results/securityanalysis/security-analysis-copy-button.tsx
cat -n src/components/results/securityanalysis/security-analysis-copy-button.tsx | sed -n '1,220p'

printf '\n## inspect any nearby zip/csv helpers\n'
rg -n "unzipSync|unzip\\(|arrayBuffer\\(|TextDecoder|result\\.csv|security analysis" src/components -g '!**/node_modules/**'

printf '\n## read fflate package metadata/docs if vendored in lockfile\n'
python3 - <<'PY'
import re, pathlib, json, sys
for p in ["package.json", "pnpm-lock.yaml", "yarn.lock", "package-lock.json"]:
    path = pathlib.Path(p)
    if path.exists():
        print(f"\n--- {p} ---")
        text = path.read_text(errors="ignore")
        if p == "package.json":
            try:
                data = json.loads(text)
                deps = {}
                for k in ("dependencies", "devDependencies", "peerDependencies", "optionalDependencies"):
                    deps.update(data.get(k, {}))
                if "fflate" in deps:
                    print("fflate:", deps["fflate"])
            except Exception as e:
                print("package.json parse error:", e)
        else:
            for m in re.finditer(r'fflate[@:/ ]([^\s"\'\n]+)', text):
                print("match:", m.group(0))
PY

printf '\n## if node_modules exists, inspect installed fflate docs without running repo code\n'
if [ -d node_modules/fflate ]; then
  sed -n '1,220p' node_modules/fflate/README.md
else
  echo "node_modules/fflate not present"
fi

Repository: gridsuite/gridstudy-app

Length of output: 593


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## target file, bounded\n'
wc -l src/components/results/securityanalysis/security-analysis-copy-button.tsx
cat -n src/components/results/securityanalysis/security-analysis-copy-button.tsx | sed -n '1,220p'

printf '\n## related references in src\n'
rg -n "unzipSync|unzip\\(|security-analysis-copy-button|result\\.csv|TextDecoder" src -g '!**/node_modules/**'

printf '\n## fflate docs from installed package if available\n'
if [ -d node_modules/fflate ]; then
  rg -n "worker|web worker|unzip\\(|unzipSync|async unzip|callback" node_modules/fflate/README.md node_modules/fflate/*.d.ts node_modules/fflate/*.js -g '!**/node_modules/**'
else
  echo "node_modules/fflate not present"
fi

Repository: gridsuite/gridstudy-app

Length of output: 9051


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## fflate README relevant excerpts\n'
sed -n '370,470p' node_modules/fflate/README.md

printf '\n## package.json dependency entry\n'
sed -n '1,70p' package.json

Repository: gridsuite/gridstudy-app

Length of output: 6695


Avoid synchronous ZIP decompression on the UI thread. unzipSync blocks the copy action for large result ZIPs; switch to fflate.unzip here so decompression runs off-thread. The async API has startup overhead, but this path is user-triggered and better fits larger archives.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/results/securityanalysis/security-analysis-copy-button.tsx`
around lines 46 - 57, Replace synchronous unzipSync usage in
extractCsvTextFromZipBlob with fflate’s asynchronous unzip API, awaiting
decompression before selecting and decoding the CSV entry. Preserve the existing
fallback entry selection, missing-entry error, UTF-8 decoding, and BOM removal
behavior.

const buffer = new Uint8Array(await blob.arrayBuffer());
const unzipped = unzipSync(buffer);
const entryNames = Object.keys(unzipped);
const csvEntryName = entryNames.find((name) => name.toLowerCase().endsWith('.csv')) ?? entryNames[0];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

csvEntryName fallback may silently process non-CSV files.

When no .csv entry is found, the code falls back to entryNames[0], which could be any file type (e.g., a metadata JSON or README). The subsequent if (!csvEntryName) check only catches empty archives. Remove the fallback to fail loudly on unexpected archive contents.

🛡️ Proposed fix
-    const csvEntryName = entryNames.find((name) => name.toLowerCase().endsWith('.csv')) ?? entryNames[0];
+    const csvEntryName = entryNames.find((name) => name.toLowerCase().endsWith('.csv'));
     if (!csvEntryName) {
         throw new Error('No CSV entry found in zip archive');
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const csvEntryName = entryNames.find((name) => name.toLowerCase().endsWith('.csv')) ?? entryNames[0];
const csvEntryName = entryNames.find((name) => name.toLowerCase().endsWith('.csv'));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/results/securityanalysis/security-analysis-copy-button.tsx` at
line 50, Remove the entryNames[0] fallback from the csvEntryName assignment in
the security analysis copy-button logic, leaving it undefined when no .csv file
exists so the existing !csvEntryName check fails loudly for unexpected archive
contents.

Comment on lines +63 to +71
function convertDelimiter(csvText: string, fromSeparator: string, toSeparator: string): string {
if (fromSeparator === toSeparator) {
return csvText;
}
return csvText
.split('\n')
.map((line) => line.replace(/\r$/, '').split(fromSeparator).join(toSeparator))
.join('\n');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== File outline ==\n'
ast-grep outline src/components/results/securityanalysis/security-analysis-copy-button.tsx --view expanded || true

printf '\n== Relevant file excerpt ==\n'
nl -ba src/components/results/securityanalysis/security-analysis-copy-button.tsx | sed -n '1,180p'

printf '\n== CSV-related dependencies ==\n'
if [ -f package.json ]; then
  python3 - <<'PY'
import json
from pathlib import Path
pkg = json.loads(Path('package.json').read_text())
for section in ('dependencies','devDependencies','peerDependencies'):
    deps = pkg.get(section, {})
    hits = {k:v for k,v in deps.items() if 'csv' in k.lower() or 'papaparse' in k.lower() or 'parse' in k.lower()}
    if hits:
        print(section, hits)
PY
fi

printf '\n== Search for papaparse / csv helpers ==\n'
rg -n "papaparse|PapaParse|csv-?parse|csv-?stringify|fromSeparator|convertDelimiter" -S . || true

Repository: gridsuite/gridstudy-app

Length of output: 864


🏁 Script executed:

sed -n '1,180p' src/components/results/securityanalysis/security-analysis-copy-button.tsx | nl -ba

Repository: gridsuite/gridstudy-app

Length of output: 201


convertDelimiter can corrupt quoted CSV fields. split('\n') and split(fromSeparator) ignore CSV quoting, so separators or line breaks inside quoted values will be rewritten incorrectly before copying. Use a CSV-aware parser/serializer here instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/results/securityanalysis/security-analysis-copy-button.tsx`
around lines 63 - 71, The convertDelimiter function must preserve CSV quoting,
embedded separators, and newlines instead of using plain split operations.
Replace its line and delimiter splitting with a CSV-aware parser and serializer,
while retaining the early return when separators match and ensuring equivalent
valid CSV output with the requested delimiter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant