Files
whetstone_DSL/editor/src/ReviewComparisonView.h

119 lines
3.9 KiB
C++

#pragma once
#include "WorkflowTaskDetail.h"
#include <optional>
#include <string>
#include <vector>
struct ReviewDiffLine {
char kind = ' '; // ' ' unchanged, '-' removed, '+' added, '~' modified
std::string left;
std::string right;
std::string note;
};
struct ReviewComparisonModel {
std::string itemId;
std::string title;
std::string status;
std::string leftLabel;
std::string rightLabel;
std::vector<ReviewDiffLine> diff;
std::vector<std::string> changeNotes;
bool canApprove = false;
bool canReject = false;
std::string approveShortcut;
std::string rejectShortcut;
};
class ReviewComparisonView {
public:
static std::optional<ReviewComparisonModel> build(const WorkflowState& wf,
const std::string& itemId) {
auto detail = WorkflowTaskDetail::build(wf, itemId);
if (!detail.has_value()) return std::nullopt;
ReviewComparisonModel m;
m.itemId = detail->itemId;
m.title = detail->title;
m.status = detail->status;
m.leftLabel = "skeleton";
m.rightLabel = "generated";
m.diff = buildDiffLines(detail->skeletonCode, detail->generatedCode);
m.changeNotes = buildChangeNotes(*detail);
m.canApprove = (detail->status == WI_REVIEW);
m.canReject = (detail->status == WI_REVIEW);
m.approveShortcut = approveShortcut();
m.rejectShortcut = rejectShortcut();
return m;
}
static bool approve(WorkflowState& wf, const std::string& itemId,
const std::string& reviewer = "human") {
return WorkflowTaskDetail::approve(wf, itemId, reviewer);
}
static bool reject(WorkflowState& wf, const std::string& itemId,
const std::string& feedback,
const std::string& reviewer = "human") {
return WorkflowTaskDetail::reject(wf, itemId, feedback, reviewer);
}
static std::string approveShortcut() { return "Ctrl+Shift+A"; }
static std::string rejectShortcut() { return "Ctrl+Shift+R"; }
private:
static std::vector<std::string> splitLines(const std::string& text) {
std::vector<std::string> lines;
std::string cur;
for (char c : text) {
if (c == '\n') {
lines.push_back(cur);
cur.clear();
} else {
cur.push_back(c);
}
}
if (!cur.empty()) lines.push_back(cur);
return lines;
}
static std::vector<ReviewDiffLine> buildDiffLines(const std::string& left,
const std::string& right) {
auto l = splitLines(left);
auto r = splitLines(right);
size_t n = l.size() > r.size() ? l.size() : r.size();
std::vector<ReviewDiffLine> out;
for (size_t i = 0; i < n; ++i) {
std::string ls = i < l.size() ? l[i] : "";
std::string rs = i < r.size() ? r[i] : "";
if (i >= l.size()) {
out.push_back({'+', "", rs, "added"});
} else if (i >= r.size()) {
out.push_back({'-', ls, "", "removed"});
} else if (ls == rs) {
out.push_back({' ', ls, rs, "unchanged"});
} else {
out.push_back({'~', ls, rs, "modified"});
}
}
return out;
}
static std::vector<std::string> buildChangeNotes(const TaskDetailView& detail) {
std::vector<std::string> notes;
if (!detail.routingExplanation.empty()) {
notes.push_back("routing: " + detail.routingExplanation);
}
if (!detail.rejectionFeedback.empty()) {
notes.push_back("latest-feedback: " + detail.rejectionFeedback);
}
for (const auto& t : detail.annotationTags) {
notes.push_back("annotation: " + t);
}
return notes;
}
};