feat(platform): add ability to reject approved agents in admin dashboard

- Modified backend review_store_submission to handle rejecting approved agents
- Added logic to update StoreListing when rejecting approved agents
- Updated UI to show "Revoke" button for approved agents
- Only shows approve button for pending agents
- Updates dialog text appropriately for revoking vs rejecting

Fixes SECRT-1218

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Nicholas Tindle
2025-08-18 10:35:25 -05:00
parent af7d56612d
commit 92515b3683
3 changed files with 65 additions and 19 deletions

View File

@@ -1096,6 +1096,13 @@ async def review_store_submission(
detail=f"Store listing version {store_listing_version_id} not found",
)
# Check if we're rejecting an already approved agent
is_rejecting_approved = (
not is_approved
and store_listing_version.submissionStatus
== prisma.enums.SubmissionStatus.APPROVED
)
# If approving, update the listing to indicate it has an approved version
if is_approved and store_listing_version.AgentGraph:
heading = f"Sub-graph of {store_listing_version.name}v{store_listing_version.agentGraphVersion}"
@@ -1126,6 +1133,37 @@ async def review_store_submission(
},
)
# If rejecting an approved agent, update the StoreListing accordingly
if is_rejecting_approved:
# Check if there are other approved versions
other_approved = (
await prisma.models.StoreListingVersion.prisma().find_first(
where={
"storeListingId": store_listing_version.StoreListing.id,
"id": {"not": store_listing_version_id},
"submissionStatus": prisma.enums.SubmissionStatus.APPROVED,
}
)
)
if not other_approved:
# No other approved versions, update hasApprovedVersion to False
await prisma.models.StoreListing.prisma().update(
where={"id": store_listing_version.StoreListing.id},
data={
"hasApprovedVersion": False,
"ActiveVersion": {"disconnect": True},
},
)
else:
# Set the most recent other approved version as active
await prisma.models.StoreListing.prisma().update(
where={"id": store_listing_version.StoreListing.id},
data={
"ActiveVersion": {"connect": {"id": other_approved.id}},
},
)
submission_status = (
prisma.enums.SubmissionStatus.APPROVED
if is_approved

View File

@@ -13,7 +13,7 @@ import {
} from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import type { StoreSubmission } from "@/lib/autogpt-server-api/types";
import type { StoreSubmission, SubmissionStatus } from "@/lib/autogpt-server-api/types";
import { useRouter } from "next/navigation";
import {
approveAgent,
@@ -28,6 +28,8 @@ export function ApproveRejectButtons({
const router = useRouter();
const [isApproveDialogOpen, setIsApproveDialogOpen] = useState(false);
const [isRejectDialogOpen, setIsRejectDialogOpen] = useState(false);
const isApproved = version.status === "APPROVED";
const handleApproveSubmit = async (formData: FormData) => {
setIsApproveDialogOpen(false);
@@ -51,18 +53,20 @@ export function ApproveRejectButtons({
return (
<>
<Button
size="sm"
variant="outline"
className="text-green-600 hover:bg-green-50 hover:text-green-700"
onClick={(e) => {
e.stopPropagation();
setIsApproveDialogOpen(true);
}}
>
<CheckCircle className="mr-2 h-4 w-4" />
Approve
</Button>
{!isApproved && (
<Button
size="sm"
variant="outline"
className="text-green-600 hover:bg-green-50 hover:text-green-700"
onClick={(e) => {
e.stopPropagation();
setIsApproveDialogOpen(true);
}}
>
<CheckCircle className="mr-2 h-4 w-4" />
Approve
</Button>
)}
<Button
size="sm"
variant="outline"
@@ -73,7 +77,7 @@ export function ApproveRejectButtons({
}}
>
<XCircle className="mr-2 h-4 w-4" />
Reject
{isApproved ? "Revoke" : "Reject"}
</Button>
{/* Approve Dialog */}
@@ -124,9 +128,11 @@ export function ApproveRejectButtons({
<Dialog open={isRejectDialogOpen} onOpenChange={setIsRejectDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Reject Agent</DialogTitle>
<DialogTitle>{isApproved ? "Revoke Approved Agent" : "Reject Agent"}</DialogTitle>
<DialogDescription>
Please provide feedback on why this agent is being rejected.
{isApproved
? "Are you sure you want to revoke approval for this agent? This will remove it from the marketplace."
: "Please provide feedback on why this agent is being rejected."}
</DialogDescription>
</DialogHeader>
@@ -167,7 +173,7 @@ export function ApproveRejectButtons({
Cancel
</Button>
<Button type="submit" variant="destructive">
Reject
{isApproved ? "Revoke" : "Reject"}
</Button>
</DialogFooter>
</form>

View File

@@ -83,7 +83,8 @@ export function ExpandableRow({
/>
)}
{latestVersion?.status === SubmissionStatus.PENDING && (
{(latestVersion?.status === SubmissionStatus.PENDING ||
latestVersion?.status === SubmissionStatus.APPROVED) && (
<ApproveRejectButtons version={latestVersion} />
)}
</div>
@@ -188,7 +189,8 @@ export function ExpandableRow({
}
/>
)}
{version.status === SubmissionStatus.PENDING && (
{(version.status === SubmissionStatus.PENDING ||
version.status === SubmissionStatus.APPROVED) && (
<ApproveRejectButtons version={version} />
)}
</div>