diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb
index b8bdc1c..1b4486b 100644
--- a/app/controllers/reviews_controller.rb
+++ b/app/controllers/reviews_controller.rb
@@ -3,6 +3,11 @@ def index
end
def create
+ unless Harness.configuration&.api_key.present?
+ return render json: { error: "OPENAI_API_KEY is not configured on the server." },
+ status: :service_unavailable
+ end
+
review = Review.create!(pr_url: params[:pr_url], status: Review::PENDING)
ReviewJob.perform_later(review.id)
render json: { id: review.id, status: review.status }
@@ -51,8 +56,8 @@ def review_json(review)
{
id: s.id, filename: s.filename, language: s.language,
priority: s.priority, walkthrough: s.walkthrough,
- findings: s.findings, human_comments: s.human_comments,
- status: s.status
+ patch_text: s.patch_text, findings: s.findings,
+ human_comments: s.human_comments, status: s.status
}
end
}
diff --git a/app/javascript/components/review/DiffPanel.jsx b/app/javascript/components/review/DiffPanel.jsx
index 909372e..0905d1e 100644
--- a/app/javascript/components/review/DiffPanel.jsx
+++ b/app/javascript/components/review/DiffPanel.jsx
@@ -1,6 +1,13 @@
import React, { useState, useRef, useEffect } from 'react'
-const DiffPanel = ({ sections, highlightFile, highlightRange }) => {
+const lineStyle = (line) => {
+ if (line.startsWith('+')) return 'bg-green-50 text-green-800'
+ if (line.startsWith('-')) return 'bg-red-50 text-red-800'
+ if (line.startsWith('@@')) return 'bg-blue-50 text-blue-600 font-medium'
+ return 'text-gray-700'
+}
+
+const DiffPanel = ({ sections, status, highlightFile, highlightRange }) => {
const [collapsed, setCollapsed] = useState({})
const fileRefs = useRef({})
@@ -15,30 +22,52 @@ const DiffPanel = ({ sections, highlightFile, highlightRange }) => {
}
if (!sections || sections.length === 0) {
- return
No diff data available
+ if (status === 'reviewing' || status === 'submitting') {
+ return (
+
+
+ Fetching diff...
+
+ )
+ }
+ return (
+
+ Submit a PR URL to see the diff here.
+
+ )
}
return (
-
+
{sections.map((section) => (
fileRefs.current[section.filename] = el}
- className="border border-gray-200 rounded"
+ className="border border-gray-200 rounded overflow-hidden"
>
- {!collapsed[section.filename] && section.findings && (
-
- {section.findings.length} finding{section.findings.length !== 1 ? 's' : ''}
- {section.findings.some(f => f.severity === 'red_flag') && (
-
contains red flags
+ {!collapsed[section.filename] && (
+
+ {section.patch_text ? (
+
+ {section.patch_text.split('\n').map((line, i) => (
+ {line || ' '}
+ ))}
+
+ ) : (
+
No diff content available
)}
)}
diff --git a/app/javascript/components/review/ReviewApp.jsx b/app/javascript/components/review/ReviewApp.jsx
index 8fbbf22..a7352f3 100644
--- a/app/javascript/components/review/ReviewApp.jsx
+++ b/app/javascript/components/review/ReviewApp.jsx
@@ -121,17 +121,30 @@ const ReviewApp = () => {
{error && (
-
+
{error}
)}
+ {status === 'failed' && !error && (
+
+ Review failed. This could be a GitHub API issue or an invalid PR URL. Try again.
+
+ )}
+
+ {!reviewId && status === 'idle' && !error && (
+
+ Paste a public GitHub PR URL above to start an AI-powered code review.
+
+ )}
+
{reviewId && (
-
Files
+
Diff
diff --git a/app/javascript/components/review/ReviewPanel.jsx b/app/javascript/components/review/ReviewPanel.jsx
index c280c30..58c3bd5 100644
--- a/app/javascript/components/review/ReviewPanel.jsx
+++ b/app/javascript/components/review/ReviewPanel.jsx
@@ -7,17 +7,30 @@ const ReviewPanel = ({ sections, synthesis, reviewId, status, onSynthesize, onFi
const canSynthesize = status === 'complete' && hasSections && !synthesis?.verdict
return (
-
+
{!hasSections && status === 'reviewing' && (
- Reviewing pull request...
+ Triaging files and starting review...
+
+ )}
+
+ {hasSections && status === 'reviewing' && (
+
+
+ Reviewing more files...
+
+ )}
+
+ {status === 'complete' && !hasSections && (
+
+ No files were flagged for review.
)}
{sections.map((section) => (