Main - #33
Conversation
…ed toast feedback while centralizing contest session status logic
… for audience and contest deletion
…dpoints to results endpoints
…contest question score endpoint
…nd add explanatory note
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThis PR adds SQLite question authoring, execution, preview, and contest rendering. It also updates contest-session status handling, API error normalization, deletion confirmations, registration cancellation, contest form errors, and submission score editing. ChangesQuestion authoring and SQL execution
Session and contest workflows
Formatting and configuration
Estimated code review effort: 5 (Critical) | ~120 minutes Merge Risk: ⚪ Minimal · up to No actionable merge-blocking risk remains; the PR is merge-ready after normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (7)
src/components/audiences/audiences-client.tsx (1)
442-446: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse the shared API error helper.
This handler reads
err.response.data.messagedirectly. The repository already hashandleApiErrorinsrc/lib/handle-api-error.ts, andtoApiErrorinsrc/lib/api/error.ts. Both normalize Axios errors, network failures, and non-standard bodies. Use one of them here to keep error messages consistent across the app.♻️ Proposed refactor
onError: (err: unknown) => { - const msg = (err as { response?: { data?: { message?: string } } })?.response - ?.data?.message; - toast.error(msg || "Failed to delete audience"); + toast.error(handleApiError(err).message || "Failed to delete audience"); },Add the import:
import { handleApiError } from "`@/lib/handle-api-error`";🤖 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/audiences/audiences-client.tsx` around lines 442 - 446, Update the delete audience onError handler in the audience client to use the shared handleApiError helper instead of directly reading err.response.data.message, and add the corresponding import from "`@/lib/handle-api-error`". Preserve the existing fallback message and toast.error behavior while delegating API error normalization to the shared helper.src/components/student/contest/contest-team-cards.tsx (1)
372-375: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDefine the cancellation rule through the shared session-status helpers.
src/lib/contest-session-status.tsalready owns this domain logic, socanCancelRegistrationshould be a helper that handlescompletion_statusand thealready_startedfallback. The generated status is already exposed asContestSessionCompletionStatus, so centralizing the rule avoids a separate"NOT_STARTED"literal in this UI branch.🤖 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/student/contest/contest-team-cards.tsx` around lines 372 - 375, Update the cancellation logic in the component around canCancelRegistration to use a shared helper from contest-session-status.ts that accepts completion_status and the already_started fallback, rather than comparing the "NOT_STARTED" literal in the UI. Reuse the existing ContestSessionCompletionStatus type and preserve the current behavior for both explicit completion statuses and sessions without one.src/components/questions/sql-code-editor.tsx (2)
27-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
STEP_COPYis typed asRecord<string, …>, which removes the exhaustiveness check.Line 67 reads
STEP_COPY[step]and Lines 138-141 dereference the result. The index signature makescopynon-optional for any string key, so a futurestepvalue without an entry throws at runtime instead of failing the build. Key the record by the prop union.
STEP_COPY.starteris also unused: the editor shell never rendersSqlCodeEditorwithstep="starter". See the related finding onALL_STEPS_SQLinsrc/components/contest/question-editor-shell.tsx.♻️ Key STEP_COPY by the step union
-const STEP_COPY: Record<string, { label: string; hint: string }> = { +type SqlEditorStep = "schema" | "seed" | "starter" | "solution"; + +const STEP_COPY: Record<SqlEditorStep, { label: string; hint: string }> = {interface SqlCodeEditorProps { - step: "schema" | "seed" | "starter" | "solution"; + step: SqlEditorStep;🤖 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/questions/sql-code-editor.tsx` around lines 27 - 44, Update STEP_COPY to use the existing step prop union as its key type instead of Record<string, …>, so missing step entries are caught at build time and STEP_COPY[step] remains safely typed. Remove the unused starter entry, since SqlCodeEditor is not rendered with step="starter", while preserving the existing schema, seed, and solution copy.
204-222: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReplace the hard-coded palette colors with semantic status tokens.
Lines 208-209 use
bg-emerald-500/10 text-emerald-500andbg-amber-500/10 text-amber-500. Line 218 usesborder-red-500/20 bg-red-500/10 text-red-400. The coding guidelines forbid hard-coded palette colors in components and define semantic pairs for status UI. Thetext-red-400value also gives weak contrast on the light-theme tint.Use
success,warning, anddestructivetokens instead. The same substitution applies to Lines 244-245, 266, and 279-284.♻️ Use semantic status tokens
"rounded-full px-2 py-0.5 text-[9px] font-bold", passedCount === totalCount - ? "bg-emerald-500/10 text-emerald-500" - : "bg-amber-500/10 text-amber-500", + ? "bg-success/10 text-success" + : "bg-warning/10 text-warning", )}- <div className="flex items-start gap-2.5 rounded-lg border border-red-500/20 bg-red-500/10 p-3 text-xs text-red-400"> + <div className="flex items-start gap-2.5 rounded-lg border border-destructive/30 bg-destructive/5 p-3 text-xs text-destructive">As per coding guidelines: "Do not hard-code palette colors in components unless there is a narrow external-branding requirement" and "Use semantic status UI pairs:
bg-destructive text-destructive-foreground,bg-success text-success-foreground,bg-warning text-warning-foreground, andbg-info text-info-foreground".🤖 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/questions/sql-code-editor.tsx` around lines 204 - 222, Replace the hard-coded emerald, amber, and red classes in the status UI with the semantic success, warning, and destructive token pairs, including the corresponding usages around the passed-count badge and execution-error sections at the other referenced locations. Use bg-success/text-success-foreground, bg-warning/text-warning-foreground, and bg-destructive/text-destructive-foreground as appropriate, preserving the existing conditional status behavior.Source: Coding guidelines
src/components/contest/question-editor-shell.tsx (1)
431-462: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThe
stepprop uses a type assertion instead of narrowing.
activeStep as "schema" | "seed" | "solution"disables the compiler check. If a step is later added to the SQL editor branch without updating the assertion, the mismatch stays silent. The nested ternary forvalueand the if/else chain foronChangealso duplicate the same step-to-field mapping in two places.Consider a single lookup table keyed by step, which removes the assertion and the duplication.
♻️ Map each SQL step to its field once
+ {/* Defined near the component top: */} + {/* const SQL_FIELDS = { + schema: [code.sqlSchema, code.setSqlSchema], + seed: [code.sqlSeed, code.setSqlSeed], + solution: [code.sqlSolution, code.setSqlSolution], + } as const; */}🤖 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/contest/question-editor-shell.tsx` around lines 431 - 462, Replace the `activeStep as "schema" | "seed" | "solution"` assertion and duplicated `value`/`onChange` mappings in the `SqlCodeEditor` block with a single typed lookup keyed by the supported SQL steps. Narrow `activeStep` through that lookup before rendering, and use the selected entry’s value and setter while preserving the existing `showExecution`, schema, and seed behavior.src/hooks/use-question-payload.ts (1)
40-65: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExtract the shared payload fields to remove the duplicated return shape.
The SQL branch and the standard branch repeat ten identical fields. A future field addition must be applied twice.
♻️ Share a base payload between both branches
+ const base = { + title: metadata.title, + difficulty: metadata.difficulty, + question_text, + time_limit_ms: metadata.timeLimit, + memory_limit_mb: metadata.memoryLimit, + tag_ids: metadata.tags.filter(Boolean), + testcases: formattedTestCases, + score: metadata.score, + duration: metadata.duration ? Number(metadata.duration) : null, + max_submission: metadata.maxSubmission ? Number(metadata.maxSubmission) : null, + }; + if (isSql) { // SQL is single-language (SQLite): one implicit language, one template. const templates: QuestionTemplateCreate[] = [ { language_id: SQL_LANGUAGE_ID, starter_code: code.sqlStarter || "", solution_code: code.sqlSolution || "", driver_code: "", }, ]; return { - title: metadata.title, + ...base, question_type: QuestionType.SQL, - difficulty: metadata.difficulty, - question_text, - time_limit_ms: metadata.timeLimit, - memory_limit_mb: metadata.memoryLimit, allowed_languages: [SQL_LANGUAGE_ID], - tag_ids: metadata.tags.filter(Boolean), - testcases: formattedTestCases, templates, - score: metadata.score, - duration: metadata.duration ? Number(metadata.duration) : null, - max_submission: metadata.maxSubmission ? Number(metadata.maxSubmission) : null, }; }🤖 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/hooks/use-question-payload.ts` around lines 40 - 65, Refactor the payload construction in the hook so the fields shared by the SQL and standard branches are assembled once in a common base payload before the branch. Keep SQL-specific values such as question_type, allowed_languages, and templates in the SQL branch, while preserving the existing standard-branch overrides and returned behavior.src/components/shared/sql-result-table.tsx (1)
60-64: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse semantic theme tokens for the fallback output.
The
dark:border-white,dark:bg-slate-950, anddark:text-slate-100classes hard-code palette colors. Remove these overrides and retain the existing semanticborder-border,bg-muted, andtext-foregroundtokens.As per coding guidelines, “Do not hard-code palette colors in components unless there is a narrow external-branding requirement.”
🤖 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/shared/sql-result-table.tsx` around lines 60 - 64, Update the fallback output `<pre>` styling in the SQL result table to remove the hard-coded dark-mode palette overrides (`dark:border-white/10`, `dark:bg-slate-950/70`, and `dark:text-slate-100`), retaining the existing semantic `border-border`, `bg-muted`, and `text-foreground` tokens.Source: Coding guidelines
🤖 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 @.github/workflows/deploy.yml:
- Around line 14-15: Update the checkout step using actions/checkout@v4 to set
persist-credentials to false, ensuring the GITHUB_TOKEN is not retained in
.git/config for subsequent Docker build steps.
In `@src/components/contest/contest-form.tsx`:
- Around line 406-426: Separate the instructor assignment call in the contest
submission flow from the contest-creation error handling: after
createContestMutation.mutateAsync succeeds, catch assignment errors
independently, report them as assignment failures, and still execute
router.push("/contest") and router.refresh() for the successfully created
contest. Keep contest creation failures on the existing "Could not create
contest" path, using createdContestId and assignInstructorsMutation as the
implementation anchors.
In `@src/components/contest/contest-question-editor-client.tsx`:
- Around line 84-95: Update the score field in the contest question editor to
make its non-persisted state clear when editing an existing contest-linked
question: disable the input in update mode or add a concise adjacent hint, while
preserving normal score editing for create mode.
In `@src/components/contest/question-editor-shell.tsx`:
- Line 38: Make the SQL question flow include the editable starter step: add
"starter" to ALL_STEPS_SQL and STEP_GROUPS_SQL, add its sidebar entry, and
update the SQL editor branch and value/onChange mapping to read and write
code.sqlStarter. Preserve the existing starter handling for non-SQL questions.
In `@src/components/contest/team-member-analytics/member-question-review.tsx`:
- Around line 421-431: Update the wrapper’s onKeyDown handler to process Enter
and Space only when event.target is the wrapper element itself, allowing key
events from SubmissionScoreEditor’s input and buttons to work normally. Preserve
the existing onToggle behavior for direct wrapper keyboard interaction; consider
removing role="button" and moving the toggle affordance to a dedicated chevron
button if implementing the ARIA follow-up.
In `@src/components/questions/question-metadata-card.tsx`:
- Around line 208-222: Update the question-type buttons in the question metadata
card to replace the ineffective outline suppression with the required visible
focus style using focus-visible:ring-ring, while preserving existing styling.
Add aria-pressed based on isActive so assistive technology can identify the
selected question type.
In `@src/components/questions/sql-code-editor.tsx`:
- Around line 104-108: Centralize schema-and-seed fixture construction by
exporting a compileSqlFixture(schema, seed) helper from question-template.ts,
then replace the inline `${schema}\n${seed}` expressions in this component,
use-question-payload, and handleGenerateExpectedOutput with that helper.
Preserve the current fixture output while ensuring all authoring, persistence,
and expected-output paths share one implementation.
In `@src/components/shared/sql-result-table.tsx`:
- Around line 24-28: Update the text-to-lines handling in the SQL result table
to preserve blank rows and trailing spaces: normalize CRLF line endings, remove
only one final record newline, and split without trimming or filtering lines so
values such as SELECT '' remain rendered.
In `@src/hooks/use-question-form.ts`:
- Around line 73-78: The SQL state handling around useQuestionPayload must not
fall back to any testcase.input value. When parsedText.sql is missing or
invalid, clear sqlSchema and sqlSeed, and preserve testcase.input unchanged;
require explicit author confirmation before allowing the payload to save.
In `@src/lib/providers/tanstack-query-provider.tsx`:
- Around line 45-51: Deduplicate the mapped detail messages in the apiError
toast construction before limiting them to three entries. Update the
detailMessages pipeline near toast.error so repeated messages are removed after
excluding apiError.message, while preserving the existing ordering and separator
formatting.
---
Nitpick comments:
In `@src/components/audiences/audiences-client.tsx`:
- Around line 442-446: Update the delete audience onError handler in the
audience client to use the shared handleApiError helper instead of directly
reading err.response.data.message, and add the corresponding import from
"`@/lib/handle-api-error`". Preserve the existing fallback message and toast.error
behavior while delegating API error normalization to the shared helper.
In `@src/components/contest/question-editor-shell.tsx`:
- Around line 431-462: Replace the `activeStep as "schema" | "seed" |
"solution"` assertion and duplicated `value`/`onChange` mappings in the
`SqlCodeEditor` block with a single typed lookup keyed by the supported SQL
steps. Narrow `activeStep` through that lookup before rendering, and use the
selected entry’s value and setter while preserving the existing `showExecution`,
schema, and seed behavior.
In `@src/components/questions/sql-code-editor.tsx`:
- Around line 27-44: Update STEP_COPY to use the existing step prop union as its
key type instead of Record<string, …>, so missing step entries are caught at
build time and STEP_COPY[step] remains safely typed. Remove the unused starter
entry, since SqlCodeEditor is not rendered with step="starter", while preserving
the existing schema, seed, and solution copy.
- Around line 204-222: Replace the hard-coded emerald, amber, and red classes in
the status UI with the semantic success, warning, and destructive token pairs,
including the corresponding usages around the passed-count badge and
execution-error sections at the other referenced locations. Use
bg-success/text-success-foreground, bg-warning/text-warning-foreground, and
bg-destructive/text-destructive-foreground as appropriate, preserving the
existing conditional status behavior.
In `@src/components/shared/sql-result-table.tsx`:
- Around line 60-64: Update the fallback output `<pre>` styling in the SQL
result table to remove the hard-coded dark-mode palette overrides
(`dark:border-white/10`, `dark:bg-slate-950/70`, and `dark:text-slate-100`),
retaining the existing semantic `border-border`, `bg-muted`, and
`text-foreground` tokens.
In `@src/components/student/contest/contest-team-cards.tsx`:
- Around line 372-375: Update the cancellation logic in the component around
canCancelRegistration to use a shared helper from contest-session-status.ts that
accepts completion_status and the already_started fallback, rather than
comparing the "NOT_STARTED" literal in the UI. Reuse the existing
ContestSessionCompletionStatus type and preserve the current behavior for both
explicit completion statuses and sessions without one.
In `@src/hooks/use-question-payload.ts`:
- Around line 40-65: Refactor the payload construction in the hook so the fields
shared by the SQL and standard branches are assembled once in a common base
payload before the branch. Keep SQL-specific values such as question_type,
allowed_languages, and templates in the SQL branch, while preserving the
existing standard-branch overrides and returned behavior.
🪄 Autofix
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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e619d8f6-ad58-407e-bf21-55d5f83be40a
⛔ Files ignored due to path filters (26)
src/api/generated/contests/contests.tsis excluded by!**/generated/**src/api/generated/images/images.tsis excluded by!**/generated/**src/api/generated/model/contestCreate.tsis excluded by!**/generated/**src/api/generated/model/contestDetailResponse.tsis excluded by!**/generated/**src/api/generated/model/contestSessionCompletionStatus.tsis excluded by!**/generated/**src/api/generated/model/contestSummaryResponse.tsis excluded by!**/generated/**src/api/generated/model/contestUpdate.tsis excluded by!**/generated/**src/api/generated/model/draftTestCase.tsis excluded by!**/generated/**src/api/generated/model/index.tsis excluded by!**/generated/**src/api/generated/model/instructorDashboardContest.tsis excluded by!**/generated/**src/api/generated/model/questionCreate.tsis excluded by!**/generated/**src/api/generated/model/questionResponse.tsis excluded by!**/generated/**src/api/generated/model/questionTestCaseCreate.tsis excluded by!**/generated/**src/api/generated/model/questionTestCaseResponse.tsis excluded by!**/generated/**src/api/generated/model/questionType.tsis excluded by!**/generated/**src/api/generated/model/studentContestSessionStatus.tsis excluded by!**/generated/**src/api/generated/model/updateSubmissionScoreRequest.tsis excluded by!**/generated/**src/api/generated/students/students.tsis excluded by!**/generated/**src/api/generated/submissions/submissions.tsis excluded by!**/generated/**src/api/generated/zod/bank-questions/bank-questions.tsis excluded by!**/generated/**src/api/generated/zod/contests/contests.tsis excluded by!**/generated/**src/api/generated/zod/images/images.tsis excluded by!**/generated/**src/api/generated/zod/instructors/instructors.tsis excluded by!**/generated/**src/api/generated/zod/questions/questions.tsis excluded by!**/generated/**src/api/generated/zod/students/students.tsis excluded by!**/generated/**src/api/generated/zod/submissions/submissions.tsis excluded by!**/generated/**
📒 Files selected for processing (38)
.github/workflows/deploy.ymlcomponents.jsoneslint.config.mjspostcss.config.mjssrc/app/(app)/student/contest/[id]/session/layout.tsxsrc/app/not-found.tsxsrc/components/audiences/audiences-client.tsxsrc/components/banks/bank-question-editor-client.tsxsrc/components/banks/question-import-client.tsxsrc/components/contest/contest-detail-client.tsxsrc/components/contest/contest-form.tsxsrc/components/contest/contest-question-editor-client.tsxsrc/components/contest/question-editor-shell.tsxsrc/components/contest/shared/submission-viewers.tsxsrc/components/contest/team-member-analytics/member-question-review.tsxsrc/components/questions/question-code-editor.tsxsrc/components/questions/question-metadata-card.tsxsrc/components/questions/question-preview.tsxsrc/components/questions/question-wizard.tsxsrc/components/questions/sql-code-editor.tsxsrc/components/questions/test-case-manager.tsxsrc/components/shared/sql-result-table.tsxsrc/components/student/contest/contest-team-cards.tsxsrc/components/student/contest/results/member-question-review.tsxsrc/components/student/contest/session/editor-panel.tsxsrc/components/student/contest/session/session-client.tsxsrc/components/student/contest/student-contest-detail-client.tsxsrc/components/student/contest/your-team-card.tsxsrc/components/ui/input.tsxsrc/components/ui/textarea.tsxsrc/constant/question-template.tssrc/hooks/use-question-form.tssrc/hooks/use-question-payload.tssrc/lib/api/error.tssrc/lib/contest-session-status.tssrc/lib/handle-api-error.tssrc/lib/providers/tanstack-query-provider.tsxsrc/query/contest-query.ts
💤 Files with no reviewable changes (1)
- src/query/contest-query.ts
| - name: Checkout code | ||
| uses: actions/checkout@v4 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow deploy.yml excerpt =="
if [ -f .github/workflows/deploy.yml ]; then
nl -ba .github/workflows/deploy.yml | sed -n '1,120p'
else
echo "missing .github/workflows/deploy.yml"
fi
echo
echo "== files likely relevant to Docker context =="
git ls-files | { grep -E '(^|/)Dockerfile(|\..*)$|^\.dockerignore$|workflow|docker' -i || true; }
echo
echo "== docker ignore and checkout persistence mentions =="
rg -n --hidden -S "persist-credentials|docker build|\.\s*$|\.git|GITHUB_TOKEN|actions/checkout" .github/workflows/deploy.yml .dockerignore Dockerfile .dockerignore 2>/dev/null || true
echo
echo "== deterministic diff check with git =="
git diff -- .github/workflows/deploy.yml .dockerignore Dockerfile 2>/dev/null | sed -n '1,200p' || trueRepository: Amrita-ICPC/Amrita-ICPC-Frontend
Length of output: 244
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/deploy.yml')
text = p.read_text() if p.exists() else ''
checks = {
'has_checkout_v4': 'actions/checkout@v4' in text,
'has_persist_false': 'persist-credentials: false' in text or 'persist-credentials: false' in text,
'has_docker_build': 'docker build' in text or 'docker/build-action' in text,
'has_dot_context': 'context: .' in text or 'context: "."' in text or '.gitignore' in text,
}
for k, v in checks.items():
print(f'{k}={v}')
PYRepository: Amrita-ICPC/Amrita-ICPC-Frontend
Length of output: 259
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow deploy.yml excerpt =="
python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/deploy.yml')
for i, line in enumerate(p.read_text().splitlines(), 1):
if i <= 120:
print(f"{i:4}: {line}")
PY
echo
echo "== relevant files =="
git ls-files | grep -E '(^|/)Dockerfile(|\..*)$|^\.dockerignore$|\.github/workflows/deploy.yml' || true
echo
echo "== targeted repository content search =="
python3 - <<'PY'
from pathlib import Path
import re
paths = [Path('.github/workflows/deploy.yml')]
for root in Path('.').rglob('*'):
name = root.name
if root.is_file() and (name == 'Dockerfile' or name == '.dockerignore'):
paths.append(root)
for path in paths:
print(f"\n--- {path} ---")
try:
text = path.read_text(errors='replace')
except Exception as e:
print(e); continue
for i, line in enumerate(text.splitlines(), 1):
if any(k in line for k in ['actions/checkout', 'persist-credentials', 'docker build', 'docker/', 'context:', '.', '.git', 'GITHUB_TOKEN', 'cat', 'cp', 'ADD', 'COPY', 'RUN']):
print(f"{i:4}: {line}")
print("\n--- config indicators ---")
text = Path('.github/workflows/deploy.yml').read_text()
checks = {
'checkout_v4': bool(re.search(r'actions/checkout@v[0-9]', text)),
'persist_false': 'persist-credentials: false' in text,
'docker_build': 'docker build' in text or 'docker/build-action' in text,
'docker_context_dot': bool(re.search(r'context:\s*["'']?\.,?\s*["'']?|context:\s*["'']?[.]?["'']?\n', text, re.S)),
'gitignore_git': '.git' in Path('.gitignore').read_text(errors='replace') if Path('.gitignore').exists() else False,
'dockerignore_git': '.git' in Path('.dockerignore').read_text(errors='replace') if Path('.dockerignore').exists() else False,
}
for k, v in checks.items():
print(f"{k}={v}")
PYRepository: Amrita-ICPC/Amrita-ICPC-Frontend
Length of output: 3120
🌐 Web query:
actions/checkout v4 persist-credentials default true
💡 Result:
In the GitHub actions/checkout v4 action, the persist-credentials input parameter defaults to true [1][2][3]. When set to true (the default), the action configures the Git authentication token or SSH key into the local Git configuration [1][4]. This allows subsequent steps in the same job to execute authenticated Git commands without requiring further configuration [1][5]. The token or key is removed during the action's post-job cleanup [1][4]. To disable this behavior, you must explicitly set persist-credentials to false in your workflow file [1][4]: - uses: actions/checkout@v4 with: persist-credentials: false While the default remains true [6], users should be aware that this configuration grants any subsequent step in the job the ability to use the credentials [4][7]. If your workflow does not require authenticated Git operations after the checkout step, setting this to false is a recommended security practice [6][7].
Citations:
- 1: https://github.com/actions/checkout/blob/v4/README.md
- 2: https://github.com/actions/checkout/blob/v4/action.yml
- 3: https://github.com/actions/checkout/blob/v4.1.1/action.yml
- 4: https://github.com/actions/checkout
- 5: https://github.com/marketplace/actions/checkout
- 6: [security] Escalate concerning default
persist-credentials=trueplease actions/checkout#2312 - 7: Remove
persist-credentialsor change the default tofalseactions/checkout#485
Sensitive Data Exposure (CWE-522): Insufficiently Protected Credentials
Reachability: External · Exploitability: Moderate
Disable checkout credential persistence.
actions/checkout@v4 persists GITHUB_TOKEN in .git/config by default, and the following Docker build uses the repository context with local secrets in build args. Set persist-credentials: false for checkout so the token is not available to later build steps.
Proposed checkout change
- name: Checkout code
uses: actions/checkout@v4
+ with:
+ persist-credentials: false📝 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.
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| persist-credentials: false |
🧰 Tools
🪛 zizmor (1.29.0)
[warning] 14-15: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 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 @.github/workflows/deploy.yml around lines 14 - 15, Update the checkout step
using actions/checkout@v4 to set persist-credentials to false, ensuring the
GITHUB_TOKEN is not retained in .git/config for subsequent Docker build steps.
Source: Linters/SAST tools
| const createdContest = await createContestMutation.mutateAsync({ | ||
| data: payload, | ||
| }); | ||
| const createdData = createdContest.data; | ||
| const createdContestId = | ||
| createdData && | ||
| typeof createdData === "object" && | ||
| "id" in createdData && | ||
| typeof createdData.id === "string" | ||
| ? createdData.id | ||
| : null; | ||
| if (createdContestId && values.instructor_ids?.length) { | ||
| await assignInstructorsMutation.mutateAsync({ | ||
| contestId: createdContestId, | ||
| data: { instructor_ids: values.instructor_ids }, | ||
| }); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| router.push("/contest"); | ||
| router.refresh(); | ||
| router.push("/contest"); | ||
| router.refresh(); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Report instructor assignment failures separately from contest creation.
assignInstructorsMutation.mutateAsync runs inside the same try block. If contest creation succeeds and instructor assignment fails, the catch block shows "Could not create contest" and skips router.push("/contest"). The contest already exists. The user sees a create failure and can submit the form again, which creates a duplicate contest.
Handle the instructor assignment failure separately, and still navigate after a successful create.
🐛 Proposed fix
if (createdContestId && values.instructor_ids?.length) {
- await assignInstructorsMutation.mutateAsync({
- contestId: createdContestId,
- data: { instructor_ids: values.instructor_ids },
- });
+ try {
+ await assignInstructorsMutation.mutateAsync({
+ contestId: createdContestId,
+ data: { instructor_ids: values.instructor_ids },
+ });
+ } catch (instructorError) {
+ toast.error("Contest created, but instructors were not assigned", {
+ description: handleApiError(instructorError).message,
+ });
+ }
}📝 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.
| const createdContest = await createContestMutation.mutateAsync({ | |
| data: payload, | |
| }); | |
| const createdData = createdContest.data; | |
| const createdContestId = | |
| createdData && | |
| typeof createdData === "object" && | |
| "id" in createdData && | |
| typeof createdData.id === "string" | |
| ? createdData.id | |
| : null; | |
| if (createdContestId && values.instructor_ids?.length) { | |
| await assignInstructorsMutation.mutateAsync({ | |
| contestId: createdContestId, | |
| data: { instructor_ids: values.instructor_ids }, | |
| }); | |
| } | |
| } | |
| } | |
| router.push("/contest"); | |
| router.refresh(); | |
| router.push("/contest"); | |
| router.refresh(); | |
| const createdContest = await createContestMutation.mutateAsync({ | |
| data: payload, | |
| }); | |
| const createdData = createdContest.data; | |
| const createdContestId = | |
| createdData && | |
| typeof createdData === "object" && | |
| "id" in createdData && | |
| typeof createdData.id === "string" | |
| ? createdData.id | |
| : null; | |
| if (createdContestId && values.instructor_ids?.length) { | |
| try { | |
| await assignInstructorsMutation.mutateAsync({ | |
| contestId: createdContestId, | |
| data: { instructor_ids: values.instructor_ids }, | |
| }); | |
| } catch (instructorError) { | |
| toast.error("Contest created, but instructors were not assigned", { | |
| description: handleApiError(instructorError).message, | |
| }); | |
| } | |
| } | |
| } | |
| router.push("/contest"); | |
| router.refresh(); |
🤖 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/contest/contest-form.tsx` around lines 406 - 426, Separate the
instructor assignment call in the contest submission flow from the
contest-creation error handling: after createContestMutation.mutateAsync
succeeds, catch assignment errors independently, report them as assignment
failures, and still execute router.push("/contest") and router.refresh() for the
successfully created contest. Keep contest creation failures on the existing
"Could not create contest" path, using createdContestId and
assignInstructorsMutation as the implementation anchors.
| // Note: the backend currently has no endpoint to update a question's score | ||
| // once it's linked to a contest (nor one that returns its current | ||
| // order/duration/max_submission, which would be needed to safely re-link | ||
| // it). The score field stays editable in the UI, but changes made here | ||
| // are not persisted until that capability exists on the backend. | ||
| const onUpdate = async () => { | ||
| await updateMutation.mutateAsync({ | ||
| contestId, | ||
| questionId: questionId!, | ||
| data: payload, | ||
| }); | ||
| await updateScoreMutation.mutateAsync({ | ||
| contestId, | ||
| questionId: questionId!, | ||
| data: { score: payload.score }, | ||
| }); | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Make the score field reflect that edits are discarded.
The comment states that score changes are not persisted for a contest-linked question. The field stays editable, so a user can change the score, see a "Question updated successfully!" toast, and assume the score was saved. Disable the score input in update mode, or show a short hint next to it, until the backend endpoint exists.
I can open a tracking issue for the missing backend capability and prepare the UI change. Do you want me to do that?
🤖 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/contest/contest-question-editor-client.tsx` around lines 84 -
95, Update the score field in the contest question editor to make its
non-persisted state clear when editing an existing contest-linked question:
disable the input in update mode or add a concise adjacent hint, while
preserving normal score editing for create mode.
| "driver", | ||
| "testcases", | ||
| ] as const; | ||
| const ALL_STEPS_SQL = ["details", "statement", "schema", "seed", "solution", "testcases"] as const; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
ALL_STEPS_SQL omits the starter step, so the SQL starter query is never editable.
STEP_GROUPS_SQL also omits it. The author therefore cannot change code.sqlStarter, and useQuestionPayload persists the untouched DEFAULT_SQL_STARTER value (-- Write your query here) as starter_code for every new SQL question. Students then receive that placeholder as their initial query.
Two signals indicate the omission is unintentional: the starter case at Lines 220-223 contains an isSql branch that cannot be reached, and STEP_COPY in src/components/questions/sql-code-editor.tsx defines copy for a starter step that is never rendered.
If a fixed placeholder is intended, remove the unreachable isSql branch and the unused STEP_COPY.starter entry. Otherwise add the step.
🐛 Add the starter step to the SQL flow
-const ALL_STEPS_SQL = ["details", "statement", "schema", "seed", "solution", "testcases"] as const;
+const ALL_STEPS_SQL = [
+ "details",
+ "statement",
+ "schema",
+ "seed",
+ "starter",
+ "solution",
+ "testcases",
+] as const;Also add the sidebar entry:
title: "Judge Configuration",
steps: [
{ id: "schema", label: "Schema" },
{ id: "seed", label: "Seed Data" },
+ { id: "starter", label: "Starter Query" },
{ id: "solution", label: "Solution Query" },
{ id: "testcases", label: "Test Cases" },
],And include starter in the SQL editor branch:
- {isSql &&
- ["schema", "seed", "solution"].includes(activeStep) && (
+ {isSql &&
+ ["schema", "seed", "starter", "solution"].includes(
+ activeStep,
+ ) && (The value/onChange mapping needs a matching starter case that reads and writes code.sqlStarter.
🤖 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/contest/question-editor-shell.tsx` at line 38, Make the SQL
question flow include the editable starter step: add "starter" to ALL_STEPS_SQL
and STEP_GROUPS_SQL, add its sidebar entry, and update the SQL editor branch and
value/onChange mapping to read and write code.sqlStarter. Preserve the existing
starter handling for non-SQL questions.
| <div | ||
| role="button" | ||
| tabIndex={0} | ||
| onClick={onToggle} | ||
| className="flex w-full flex-col gap-3 p-4 text-left transition-colors hover:bg-muted/30 sm:flex-row sm:items-center sm:justify-between" | ||
| onKeyDown={(event) => { | ||
| if (event.key === "Enter" || event.key === " ") { | ||
| event.preventDefault(); | ||
| onToggle(); | ||
| } | ||
| }} | ||
| className="flex w-full cursor-pointer flex-col gap-3 p-4 text-left transition-colors hover:bg-muted/30 sm:flex-row sm:items-center sm:justify-between" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
The wrapper key handler intercepts keys from the nested score controls.
onKeyDown is attached to the wrapper, so it also receives events that bubble from the descendants. The wrapper now contains SubmissionScoreEditor, which renders a number input and submit/cancel buttons.
Two results follow:
- A user presses Enter in the score input. The wrapper calls
event.preventDefault()andonToggle(). This blocks the implicit form submit and toggles the card. - A user presses Space on the save or cancel button. The wrapper toggles the card.
onClick is already isolated with stopPropagation in the editor, but keydown is not. Restrict the wrapper handler to events that originate on the wrapper itself.
Also note that role="button" with focusable descendants is invalid ARIA. Consider moving the toggle affordance to a dedicated chevron button so the header is not a button role.
🐛 Proposed fix
onKeyDown={(event) => {
+ if (event.target !== event.currentTarget) return;
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
onToggle();
}
}}📝 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.
| <div | |
| role="button" | |
| tabIndex={0} | |
| onClick={onToggle} | |
| className="flex w-full flex-col gap-3 p-4 text-left transition-colors hover:bg-muted/30 sm:flex-row sm:items-center sm:justify-between" | |
| onKeyDown={(event) => { | |
| if (event.key === "Enter" || event.key === " ") { | |
| event.preventDefault(); | |
| onToggle(); | |
| } | |
| }} | |
| className="flex w-full cursor-pointer flex-col gap-3 p-4 text-left transition-colors hover:bg-muted/30 sm:flex-row sm:items-center sm:justify-between" | |
| <div | |
| role="button" | |
| tabIndex={0} | |
| onClick={onToggle} | |
| onKeyDown={(event) => { | |
| if (event.target !== event.currentTarget) return; | |
| if (event.key === "Enter" || event.key === " ") { | |
| event.preventDefault(); | |
| onToggle(); | |
| } | |
| }} | |
| className="flex w-full cursor-pointer flex-col gap-3 p-4 text-left transition-colors hover:bg-muted/30 sm:flex-row sm:items-center sm:justify-between" |
🤖 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/contest/team-member-analytics/member-question-review.tsx`
around lines 421 - 431, Update the wrapper’s onKeyDown handler to process Enter
and Space only when event.target is the wrapper element itself, allowing key
events from SubmissionScoreEditor’s input and buttons to work normally. Preserve
the existing onToggle behavior for direct wrapper keyboard interaction; consider
removing role="button" and moving the toggle affordance to a dedicated chevron
button if implementing the ARIA follow-up.
| <button | ||
| key={opt.value} | ||
| type="button" | ||
| disabled={typeLocked} | ||
| onClick={() => setQuestionType(opt.value)} | ||
| className={cn( | ||
| "flex-1 py-2.5 px-4 rounded-lg border text-left transition-all duration-200 outline-none", | ||
| typeLocked | ||
| ? "cursor-not-allowed opacity-70" | ||
| : "cursor-pointer", | ||
| isActive | ||
| ? "border-primary text-primary bg-primary/10 dark:bg-primary/20 dark:border-primary/50" | ||
| : "border-border/60 hover:border-primary/40 bg-card hover:bg-muted/40 text-muted-foreground", | ||
| )} | ||
| > |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add a visible focus indicator to the question-type buttons.
The buttons set outline-none and define no replacement focus style. A keyboard user cannot see which option has focus. The coding guidelines require focus-visible:ring-ring for focus rings.
Consider also exposing the selected state to assistive technology with aria-pressed.
🛡️ Add focus-visible ring and pressed state
<button
key={opt.value}
type="button"
disabled={typeLocked}
+ aria-pressed={isActive}
onClick={() => setQuestionType(opt.value)}
className={cn(
- "flex-1 py-2.5 px-4 rounded-lg border text-left transition-all duration-200 outline-none",
+ "flex-1 py-2.5 px-4 rounded-lg border text-left transition-all duration-200 outline-none focus-visible:ring-2 focus-visible:ring-ring",
typeLocked
? "cursor-not-allowed opacity-70"
: "cursor-pointer",As per coding guidelines: "Use border-border, border-input, and ring-ring/focus-visible:ring-ring for borders, inputs, and focus rings".
📝 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.
| <button | |
| key={opt.value} | |
| type="button" | |
| disabled={typeLocked} | |
| onClick={() => setQuestionType(opt.value)} | |
| className={cn( | |
| "flex-1 py-2.5 px-4 rounded-lg border text-left transition-all duration-200 outline-none", | |
| typeLocked | |
| ? "cursor-not-allowed opacity-70" | |
| : "cursor-pointer", | |
| isActive | |
| ? "border-primary text-primary bg-primary/10 dark:bg-primary/20 dark:border-primary/50" | |
| : "border-border/60 hover:border-primary/40 bg-card hover:bg-muted/40 text-muted-foreground", | |
| )} | |
| > | |
| <button | |
| key={opt.value} | |
| type="button" | |
| disabled={typeLocked} | |
| aria-pressed={isActive} | |
| onClick={() => setQuestionType(opt.value)} | |
| className={cn( | |
| "flex-1 py-2.5 px-4 rounded-lg border text-left transition-all duration-200 outline-none focus-visible:ring-2 focus-visible:ring-ring", | |
| typeLocked | |
| ? "cursor-not-allowed opacity-70" | |
| : "cursor-pointer", | |
| isActive | |
| ? "border-primary text-primary bg-primary/10 dark:bg-primary/20 dark:border-primary/50" | |
| : "border-border/60 hover:border-primary/40 bg-card hover:bg-muted/40 text-muted-foreground", | |
| )} | |
| > |
🤖 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/questions/question-metadata-card.tsx` around lines 208 - 222,
Update the question-type buttons in the question metadata card to replace the
ineffective outline suppression with the required visible focus style using
focus-visible:ring-ring, while preserving existing styling. Add aria-pressed
based on isActive so assistive technology can identify the selected question
type.
Source: Coding guidelines
| test_cases: testCases.map((tc) => ({ | ||
| input: `${schema}\n${seed}`, | ||
| expected_output: tc.output, | ||
| is_ordered: tc.is_ordered ?? true, | ||
| })), |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
The schema-plus-seed fixture rule is duplicated in three places.
This component builds `${schema}\n${seed}`. src/hooks/use-question-payload.ts Line 28 builds the same string for the saved testcase input, and handleGenerateExpectedOutput in src/components/questions/test-case-manager.tsx builds it a third time. If one site changes the separator or adds a statement terminator, the authoring run stops matching the persisted fixture and expected results silently drift.
Export a single helper, for example compileSqlFixture(schema, seed), from src/constant/question-template.ts and call it from all three sites.
🤖 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/questions/sql-code-editor.tsx` around lines 104 - 108,
Centralize schema-and-seed fixture construction by exporting a
compileSqlFixture(schema, seed) helper from question-template.ts, then replace
the inline `${schema}\n${seed}` expressions in this component,
use-question-payload, and handleGenerateExpectedOutput with that helper.
Preserve the current fixture output while ensuring all authoring, persistence,
and expected-output paths share one implementation.
| const lines = text | ||
| .replace(/\r\n/g, "\n") | ||
| .split("\n") | ||
| .map((l) => l.trimEnd()) | ||
| .filter((l) => l.length > 0); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Preserve empty and trailing-space SQL values.
filter((l) => l.length > 0) drops blank data rows. trimEnd() removes trailing spaces from values. A result such as SELECT '' can render with a missing row.
Normalize line endings, then remove only one final record newline.
Proposed fix
- const lines = text
- .replace(/\r\n/g, "\n")
- .split("\n")
- .map((l) => l.trimEnd())
- .filter((l) => l.length > 0);
+ const normalized = text.replace(/\r\n/g, "\n");
+ const lines = (normalized.endsWith("\n") ? normalized.slice(0, -1) : normalized).split("\n");📝 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.
| const lines = text | |
| .replace(/\r\n/g, "\n") | |
| .split("\n") | |
| .map((l) => l.trimEnd()) | |
| .filter((l) => l.length > 0); | |
| const normalized = text.replace(/\r\n/g, "\n"); | |
| const lines = (normalized.endsWith("\n") ? normalized.slice(0, -1) : normalized).split("\n"); |
🤖 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/shared/sql-result-table.tsx` around lines 24 - 28, Update the
text-to-lines handling in the SQL result table to preserve blank rows and
trailing spaces: normalize CRLF line endings, remove only one final record
newline, and split without trimming or filtering lines so values such as SELECT
'' remain rendered.
| // Shared SQL schema/seed live in a namespaced sub-object; the | ||
| // compiled testcase.input is a derived artifact and ignored here. | ||
| if (parsedText.sql) { | ||
| setSqlSchema(parsedText.sql.schema ?? ""); | ||
| setSqlSeed(parsedText.sql.seed ?? ""); | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether persisted SQL questions carry the `sql` blob and how testcase.input is consumed.
set -euo pipefail
# Find every producer/consumer of the namespaced sql blob.
rg -n -C4 'parsedText\.sql|sql:\s*\{\s*schema' --type=ts --type=tsx
# Inspect the generated testcase response contract for an input field usable as fallback.
fd -t f 'questionTestCaseResponse.ts' src/api/generated --exec cat -nRepository: Amrita-ICPC/Amrita-ICPC-Frontend
Length of output: 202
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files matching use-question-form and use-question-payload and generated testcase response =="
fd -i 'use-question-form\.(ts|tsx)\|use-question-payload\.(ts|tsx)\|questionTestCaseResponse\.(ts|tsx)' .
echo
echo "== search SQL blob references =="
rg -n -C4 'parsedText\.sql|sql:\s*\{\s*schema|DEFAULT_SQL_SCHEMA|DEFAULT_SQL_SEED|recompile|useQuestionPayload' --glob '*.{ts,tsx}' .
echo
echo "== generated testcase response contracts =="
fd -i 'questionTestCaseResponse\.(ts|tsx)' . --exec cat -n \;Repository: Amrita-ICPC/Amrita-ICPC-Frontend
Length of output: 9481
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== src/hooks/use-question-form.ts =="
cat -n src/hooks/use-question-form.ts
echo
echo "== src/hooks/use-question-payload.ts =="
cat -n src/hooks/use-question-payload.ts
echo
echo "== question template SQL defaults =="
cat -n src/constant/question-template.ts
echo
echo "== question-related API responses/models =="
fd -i 'questionResponse|testCase|question' src/api/generated -e ts -e tsx -e json | sort | xargs -r -n 1 sh -c 'echo "--- $0"; sed -n "1,220p" "$0"'Repository: Amrita-ICPC/Amrita-ICPC-Frontend
Length of output: 50389
Do not reuse testcase input as the SQL schema/seed fallback.
useQuestionPayload builds SQL testcase input from code.sqlSchema and code.sqlSeed, while test cases are loaded with the stored input values. Deriving the fallback from the first testcase input would replace testcase.input with schema/seed content instead of preserving it. When the sql blob is missing or invalid, clear sqlSchema/sqlSeed and require explicit author confirmation before saving.
🤖 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/hooks/use-question-form.ts` around lines 73 - 78, The SQL state handling
around useQuestionPayload must not fall back to any testcase.input value. When
parsedText.sql is missing or invalid, clear sqlSchema and sqlSeed, and preserve
testcase.input unchanged; require explicit author confirmation before allowing
the payload to save.
| const detailMessages = apiError.errors | ||
| .map((detail) => detail.message) | ||
| .filter((message) => message !== apiError.message); | ||
| toast.error(apiError.message, { | ||
| description: detailMessages.length | ||
| ? detailMessages.slice(0, 3).join(" • ") | ||
| : undefined, |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Deduplicate detail messages before truncation.
The current filter removes only the primary message. Repeated detail messages can fill all three slots and hide a distinct validation error. Deduplicate detailMessages before slice(0, 3).
Proposed fix
- const detailMessages = apiError.errors
- .map((detail) => detail.message)
- .filter((message) => message !== apiError.message);
+ const detailMessages = [
+ ...new Set(
+ apiError.errors
+ .map((detail) => detail.message)
+ .filter((message) => message !== apiError.message),
+ ),
+ ];📝 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.
| const detailMessages = apiError.errors | |
| .map((detail) => detail.message) | |
| .filter((message) => message !== apiError.message); | |
| toast.error(apiError.message, { | |
| description: detailMessages.length | |
| ? detailMessages.slice(0, 3).join(" • ") | |
| : undefined, | |
| const detailMessages = [ | |
| ...new Set( | |
| apiError.errors | |
| .map((detail) => detail.message) | |
| .filter((message) => message !== apiError.message), | |
| ), | |
| ]; | |
| toast.error(apiError.message, { | |
| description: detailMessages.length | |
| ? detailMessages.slice(0, 3).join(" • ") | |
| : undefined, |
🤖 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/lib/providers/tanstack-query-provider.tsx` around lines 45 - 51,
Deduplicate the mapped detail messages in the apiError toast construction before
limiting them to three entries. Update the detailMessages pipeline near
toast.error so repeated messages are removed after excluding apiError.message,
while preserving the existing ordering and separator formatting.
Summary by CodeRabbit