Implemented rbac
This commit is contained in:
@@ -57,6 +57,7 @@ import { useToast } from '../ui/Toast';
|
||||
import { HelpTooltip } from '../ui/HelpTooltip';
|
||||
import { ExportButton } from '../ui/ExportButton';
|
||||
import { ExportColumn } from '../../utils/exportUtils';
|
||||
import { useRbac } from '../../auth/rbac';
|
||||
|
||||
export interface EvidenceReviewQueueProps {
|
||||
initialProjectId?: string | number | 'all';
|
||||
@@ -86,6 +87,7 @@ export const EvidenceReviewQueue: React.FC<EvidenceReviewQueueProps> = ({
|
||||
}) => {
|
||||
const queryClient = useQueryClient();
|
||||
const { success, error: toastError } = useToast();
|
||||
const { canAdd, canApprove, canExport } = useRbac();
|
||||
|
||||
// Filter States: default to initialProjectId if given, otherwise when projects load default to first project
|
||||
const [selectedProjectId, setSelectedProjectId] = useState<string | number | 'all'>(initialProjectId);
|
||||
@@ -454,6 +456,7 @@ export const EvidenceReviewQueue: React.FC<EvidenceReviewQueueProps> = ({
|
||||
</button>
|
||||
|
||||
<ExportButton
|
||||
claim="evidence_risks"
|
||||
title="Deliverable Evidence & Verification Ledger"
|
||||
subtitle="Audited records of submitted milestone deliverables and verification decisions"
|
||||
filename={`pfm-evidence-review-${new Date().toISOString().split('T')[0]}`}
|
||||
@@ -461,15 +464,17 @@ export const EvidenceReviewQueue: React.FC<EvidenceReviewQueueProps> = ({
|
||||
data={filteredEvidence}
|
||||
/>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsManualIngestModalOpen(true)}
|
||||
className="inline-flex items-center gap-1.5 text-xs font-semibold text-white bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-500 hover:to-indigo-500 border border-transparent px-3.5 py-2 rounded-xl transition shadow-md shadow-blue-500/20 cursor-pointer"
|
||||
title="Upload document on behalf of awardee"
|
||||
>
|
||||
<Upload className="w-3.5 h-3.5" />
|
||||
<span>Ingest Evidence</span>
|
||||
</button>
|
||||
{canAdd('evidence_risks') && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsManualIngestModalOpen(true)}
|
||||
className="inline-flex items-center gap-1.5 text-xs font-semibold text-white bg-gradient-to-r from-blue-600 to-indigo-600 hover:from-blue-500 hover:to-indigo-500 border border-transparent px-3.5 py-2 rounded-xl transition shadow-md shadow-blue-500/20 cursor-pointer"
|
||||
title="Upload document on behalf of awardee"
|
||||
>
|
||||
<Upload className="w-3.5 h-3.5" />
|
||||
<span>Ingest Evidence</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -795,49 +800,53 @@ export const EvidenceReviewQueue: React.FC<EvidenceReviewQueueProps> = ({
|
||||
<span>Inspect</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
reviewMutation.mutate({
|
||||
id: ev.id,
|
||||
status: ApprovalStatus.Rejected,
|
||||
version: ev.version,
|
||||
evidenceType: ev.type,
|
||||
})
|
||||
}
|
||||
disabled={reviewMutation.isPending && String(reviewMutation.variables?.id) === String(ev.id)}
|
||||
className={`inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1.5 rounded-xl border transition cursor-pointer ${
|
||||
ev.status === ApprovalStatus.Rejected
|
||||
? 'bg-rose-500/20 text-rose-300 border-rose-500/30 opacity-75'
|
||||
: 'text-rose-400 hover:text-white bg-rose-500/10 hover:bg-rose-600 border border-rose-500/25'
|
||||
}`}
|
||||
title="Reject evidence submission"
|
||||
>
|
||||
<XCircle className="w-3.5 h-3.5" />
|
||||
<span>{ev.status === ApprovalStatus.Rejected ? 'Rejected' : 'Reject'}</span>
|
||||
</button>
|
||||
{canAdd('evidence_risks') && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
reviewMutation.mutate({
|
||||
id: ev.id,
|
||||
status: ApprovalStatus.Rejected,
|
||||
version: ev.version,
|
||||
evidenceType: ev.type,
|
||||
})
|
||||
}
|
||||
disabled={reviewMutation.isPending && String(reviewMutation.variables?.id) === String(ev.id)}
|
||||
className={`inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1.5 rounded-xl border transition cursor-pointer ${
|
||||
ev.status === ApprovalStatus.Rejected
|
||||
? 'bg-rose-500/20 text-rose-300 border-rose-500/30 opacity-75'
|
||||
: 'text-rose-400 hover:text-white bg-rose-500/10 hover:bg-rose-600 border border-rose-500/25'
|
||||
}`}
|
||||
title="Reject evidence submission"
|
||||
>
|
||||
<XCircle className="w-3.5 h-3.5" />
|
||||
<span>{ev.status === ApprovalStatus.Rejected ? 'Rejected' : 'Reject'}</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
reviewMutation.mutate({
|
||||
id: ev.id,
|
||||
status: ApprovalStatus.Approved,
|
||||
version: ev.version,
|
||||
evidenceType: ev.type,
|
||||
})
|
||||
}
|
||||
disabled={reviewMutation.isPending && String(reviewMutation.variables?.id) === String(ev.id)}
|
||||
className={`inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1.5 rounded-xl border transition cursor-pointer ${
|
||||
ev.status === ApprovalStatus.Approved
|
||||
? 'bg-emerald-500/20 text-emerald-300 border-emerald-500/30 opacity-75'
|
||||
: 'text-emerald-400 hover:text-white bg-emerald-500/10 hover:bg-emerald-600 border border-emerald-500/25'
|
||||
}`}
|
||||
title="Approve evidence submission"
|
||||
>
|
||||
<CheckCircle2 className="w-3.5 h-3.5" />
|
||||
<span>{ev.status === ApprovalStatus.Approved ? 'Approved' : 'Approve'}</span>
|
||||
</button>
|
||||
{canApprove('evidence_risks') && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
reviewMutation.mutate({
|
||||
id: ev.id,
|
||||
status: ApprovalStatus.Approved,
|
||||
version: ev.version,
|
||||
evidenceType: ev.type,
|
||||
})
|
||||
}
|
||||
disabled={reviewMutation.isPending && String(reviewMutation.variables?.id) === String(ev.id)}
|
||||
className={`inline-flex items-center gap-1 text-xs font-semibold px-2.5 py-1.5 rounded-xl border transition cursor-pointer ${
|
||||
ev.status === ApprovalStatus.Approved
|
||||
? 'bg-emerald-500/20 text-emerald-300 border-emerald-500/30 opacity-75'
|
||||
: 'text-emerald-400 hover:text-white bg-emerald-500/10 hover:bg-emerald-600 border border-emerald-500/25'
|
||||
}`}
|
||||
title="Approve evidence submission"
|
||||
>
|
||||
<CheckCircle2 className="w-3.5 h-3.5" />
|
||||
<span>{ev.status === ApprovalStatus.Approved ? 'Approved' : 'Approve'}</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
@@ -989,49 +998,53 @@ export const EvidenceReviewQueue: React.FC<EvidenceReviewQueueProps> = ({
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2.5 shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
reviewMutation.mutate({
|
||||
id: inspectEvidence.id,
|
||||
status: ApprovalStatus.Rejected,
|
||||
version: inspectEvidence.version,
|
||||
evidenceType: inspectEvidence.type,
|
||||
})
|
||||
}
|
||||
disabled={reviewMutation.isPending}
|
||||
className={`px-4 py-2 text-xs font-semibold rounded-xl transition cursor-pointer flex items-center gap-1.5 ${
|
||||
inspectEvidence.status === ApprovalStatus.Rejected
|
||||
? 'bg-rose-600/30 text-rose-300 border border-rose-500/40'
|
||||
: 'text-white bg-rose-600 hover:bg-rose-500 shadow-md shadow-rose-600/20'
|
||||
}`}
|
||||
title="Reject evidence submission via API"
|
||||
>
|
||||
<XCircle className="w-3.5 h-3.5" />
|
||||
<span>{reviewMutation.isPending && reviewMutation.variables?.status === ApprovalStatus.Rejected ? 'Rejecting...' : 'Reject Evidence'}</span>
|
||||
</button>
|
||||
{canAdd('evidence_risks') && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
reviewMutation.mutate({
|
||||
id: inspectEvidence.id,
|
||||
status: ApprovalStatus.Rejected,
|
||||
version: inspectEvidence.version,
|
||||
evidenceType: inspectEvidence.type,
|
||||
})
|
||||
}
|
||||
disabled={reviewMutation.isPending}
|
||||
className={`px-4 py-2 text-xs font-semibold rounded-xl transition cursor-pointer flex items-center gap-1.5 ${
|
||||
inspectEvidence.status === ApprovalStatus.Rejected
|
||||
? 'bg-rose-600/30 text-rose-300 border border-rose-500/40'
|
||||
: 'text-white bg-rose-600 hover:bg-rose-500 shadow-md shadow-rose-600/20'
|
||||
}`}
|
||||
title="Reject evidence submission via API"
|
||||
>
|
||||
<XCircle className="w-3.5 h-3.5" />
|
||||
<span>{reviewMutation.isPending && reviewMutation.variables?.status === ApprovalStatus.Rejected ? 'Rejecting...' : 'Reject Evidence'}</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
reviewMutation.mutate({
|
||||
id: inspectEvidence.id,
|
||||
status: ApprovalStatus.Approved,
|
||||
version: inspectEvidence.version,
|
||||
evidenceType: inspectEvidence.type,
|
||||
})
|
||||
}
|
||||
disabled={reviewMutation.isPending}
|
||||
className={`px-4 py-2 text-xs font-semibold rounded-xl transition cursor-pointer flex items-center gap-1.5 ${
|
||||
inspectEvidence.status === ApprovalStatus.Approved
|
||||
? 'bg-emerald-600/30 text-emerald-300 border border-emerald-500/40'
|
||||
: 'text-white bg-emerald-600 hover:bg-emerald-500 shadow-md shadow-emerald-600/20'
|
||||
}`}
|
||||
title="Approve evidence submission via API"
|
||||
>
|
||||
<CheckCircle2 className="w-3.5 h-3.5" />
|
||||
<span>{reviewMutation.isPending && reviewMutation.variables?.status === ApprovalStatus.Approved ? 'Approving...' : 'Approve Evidence'}</span>
|
||||
</button>
|
||||
{canApprove('evidence_risks') && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
reviewMutation.mutate({
|
||||
id: inspectEvidence.id,
|
||||
status: ApprovalStatus.Approved,
|
||||
version: inspectEvidence.version,
|
||||
evidenceType: inspectEvidence.type,
|
||||
})
|
||||
}
|
||||
disabled={reviewMutation.isPending}
|
||||
className={`px-4 py-2 text-xs font-semibold rounded-xl transition cursor-pointer flex items-center gap-1.5 ${
|
||||
inspectEvidence.status === ApprovalStatus.Approved
|
||||
? 'bg-emerald-600/30 text-emerald-300 border border-emerald-500/40'
|
||||
: 'text-white bg-emerald-600 hover:bg-emerald-500 shadow-md shadow-emerald-600/20'
|
||||
}`}
|
||||
title="Approve evidence submission via API"
|
||||
>
|
||||
<CheckCircle2 className="w-3.5 h-3.5" />
|
||||
<span>{reviewMutation.isPending && reviewMutation.variables?.status === ApprovalStatus.Approved ? 'Approving...' : 'Approve Evidence'}</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user