Skip to content

Commit 02ae619

Browse files
committed
feat: add proposal auto rejection explainer
1 parent 7046b96 commit 02ae619

2 files changed

Lines changed: 63 additions & 10 deletions

File tree

  • src/app/app/projects/[projectId]/configs/[name]

‎src/app/app/projects/[projectId]/configs/[name]/page.tsx‎

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import {Button} from '@/components/ui/button';
2525
import {
2626
Dialog,
2727
DialogContent,
28-
DialogDescription,
2928
DialogFooter,
3029
DialogHeader,
3130
DialogTitle,
@@ -39,7 +38,7 @@ import type {ConfigUserRole} from '@/engine/core/db';
3938
import {useTRPC} from '@/trpc/client';
4039
import {useMutation, useSuspenseQuery} from '@tanstack/react-query';
4140
import {formatDistanceToNow} from 'date-fns';
42-
import {GitBranch} from 'lucide-react';
41+
import {AlertTriangle, GitBranch, Info} from 'lucide-react';
4342
import Link from 'next/link';
4443
import {useParams, useRouter} from 'next/navigation';
4544
import {Fragment, useMemo, useState} from 'react';
@@ -403,15 +402,59 @@ export default function ConfigByNamePage() {
403402
<DialogContent className="sm:max-w-[525px]">
404403
<DialogHeader>
405404
<DialogTitle>Create Proposal</DialogTitle>
406-
<DialogDescription>
407-
Add an optional message to explain the changes you&apos;re proposing.
408-
</DialogDescription>
409405
</DialogHeader>
406+
407+
{/* Warning/Info about proposal rejection */}
408+
<div className="pt-2">
409+
{config && config.pendingProposals.length > 0 ? (
410+
<div className="rounded-lg border border-yellow-200/50 bg-yellow-50/50 dark:border-yellow-900/30 dark:bg-yellow-950/20 p-3">
411+
<div className="flex items-start gap-2.5">
412+
<AlertTriangle className="h-4 w-4 text-yellow-600 dark:text-yellow-400 mt-0.5 shrink-0" />
413+
<div className="flex-1 text-sm space-y-2">
414+
<div>
415+
<p className="font-semibold text-foreground">
416+
{config.pendingProposals.length === 1
417+
? '1 other proposal is pending'
418+
: `${config.pendingProposals.length} other proposals are pending`}
419+
</p>
420+
<p className="text-foreground/80 dark:text-foreground/70 mt-1">
421+
If another proposal gets approved before this one, your proposal will be
422+
automatically rejected since only one proposal can be applied at a time.
423+
</p>
424+
</div>
425+
<Link
426+
href={`/app/projects/${project.id}/configs/${encodeURIComponent(name)}/proposals`}
427+
className="inline-flex items-center text-sm font-medium text-yellow-700 dark:text-yellow-300 hover:underline"
428+
target="_blank"
429+
rel="noopener noreferrer"
430+
>
431+
View pending proposals →
432+
</Link>
433+
</div>
434+
</div>
435+
</div>
436+
) : (
437+
<div className="rounded-lg border border-blue-200/50 bg-blue-50/50 dark:border-blue-900/30 dark:bg-blue-950/20 p-3">
438+
<div className="flex items-start gap-2.5">
439+
<Info className="h-4 w-4 text-blue-600 dark:text-blue-400 mt-0.5 shrink-0" />
440+
<div className="flex-1 text-sm space-y-2">
441+
<p className="text-foreground/80 dark:text-foreground/70">
442+
This proposal will be automatically rejected if{' '}
443+
{org.requireProposals
444+
? 'another proposal gets approved'
445+
: 'another proposal gets approved or the config is edited directly'}
446+
. Only one change can be applied to a config at a time.
447+
</p>
448+
</div>
449+
</div>
450+
</div>
451+
)}
452+
</div>
453+
410454
<div className="space-y-4 py-4">
411455
<div className="space-y-2">
412456
<Label htmlFor="proposal-message">
413-
Proposal description{' '}
414-
<span className="text-muted-foreground text-xs">(optional)</span>
457+
Message <span className="text-muted-foreground text-xs">(optional)</span>
415458
</Label>
416459
<Textarea
417460
id="proposal-message"

‎src/app/app/projects/[projectId]/configs/[name]/proposals/[proposalId]/page.tsx‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,16 +277,26 @@ export default function ReviewConfigProposalPage() {
277277
} else if (reason === 'config_edited') {
278278
return 'This proposal was automatically rejected because the config was edited directly, making this proposal outdated. Proposals must be based on the current config version.';
279279
} else if (reason === 'rejected_explicitly') {
280-
return 'This proposal was explicitly rejected by a reviewer and will not be applied to the config.';
280+
return 'This proposal was rejected by a reviewer and will not be applied to the config.';
281281
} else {
282282
assertNever(reason, 'Unhandled rejection reason');
283283
}
284284
})()}
285285
</p>
286286
{proposal.rejectionReason !== 'config_deleted' && (
287287
<p className="text-sm text-foreground/70 dark:text-foreground/60 italic">
288-
You can create a new proposal based on the current config version if
289-
you&apos;d like to propose similar changes.
288+
{proposal.rejectionReason === 'rejected_explicitly' ? (
289+
<>
290+
Consider discussing the feedback with{' '}
291+
{proposal.reviewerEmail ? proposal.reviewerEmail : 'the reviewer'} before
292+
creating a new proposal.
293+
</>
294+
) : (
295+
<>
296+
You can create a new proposal based on the current config version if
297+
you&apos;d like to propose similar changes.
298+
</>
299+
)}
290300
</p>
291301
)}
292302
{proposal.rejectionReason === 'another_proposal_approved' &&

0 commit comments

Comments
 (0)