@@ -254,9 +254,6 @@ function ShowRiskViewContent({
|
|||||||
const [organizationPoliciesData, setOrganizationPoliciesData] =
|
const [organizationPoliciesData, setOrganizationPoliciesData] =
|
||||||
useState<ShowRiskViewOrganizationPoliciesQuery$data | null>(null);
|
useState<ShowRiskViewOrganizationPoliciesQuery$data | null>(null);
|
||||||
const [policySearchQuery, setPolicySearchQuery] = useState("");
|
const [policySearchQuery, setPolicySearchQuery] = useState("");
|
||||||
const [policyCategoryFilter, setPolicyCategoryFilter] = useState<
|
|
||||||
string | null
|
|
||||||
>(null);
|
|
||||||
const [isLoadingPolicies, setIsLoadingPolicies] = useState(false);
|
const [isLoadingPolicies, setIsLoadingPolicies] = useState(false);
|
||||||
const [linkingPolicies, setLinkingPolicies] = useState<
|
const [linkingPolicies, setLinkingPolicies] = useState<
|
||||||
Record<string, boolean>
|
Record<string, boolean>
|
||||||
@@ -299,7 +296,6 @@ function ShowRiskViewContent({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isPolicyDialogOpen) {
|
if (!isPolicyDialogOpen) {
|
||||||
setPolicySearchQuery("");
|
setPolicySearchQuery("");
|
||||||
setPolicyCategoryFilter(null);
|
|
||||||
setLinkingPolicies({});
|
setLinkingPolicies({});
|
||||||
setUnlinkingPolicies({});
|
setUnlinkingPolicies({});
|
||||||
}
|
}
|
||||||
@@ -421,42 +417,17 @@ function ShowRiskViewContent({
|
|||||||
);
|
);
|
||||||
}, [organizationPoliciesData]);
|
}, [organizationPoliciesData]);
|
||||||
|
|
||||||
const getPolicyCategories = useCallback(() => {
|
|
||||||
const policies = getPolicies();
|
|
||||||
const categories = new Set<string>();
|
|
||||||
|
|
||||||
policies.forEach((policy) => {
|
|
||||||
if (policy.category) {
|
|
||||||
categories.add(policy.category);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Array.from(categories).sort();
|
|
||||||
}, [getPolicies]);
|
|
||||||
|
|
||||||
const filteredPolicies = useCallback(() => {
|
const filteredPolicies = useCallback(() => {
|
||||||
const policies = getPolicies();
|
const policies = getPolicies();
|
||||||
if (!policySearchQuery && !policyCategoryFilter) return policies;
|
if (!policySearchQuery) return policies;
|
||||||
|
|
||||||
return policies.filter((policy) => {
|
return policies.filter((policy) => {
|
||||||
// Filter by search query
|
return (
|
||||||
const matchesSearch =
|
|
||||||
!policySearchQuery ||
|
!policySearchQuery ||
|
||||||
policy.name.toLowerCase().includes(policySearchQuery.toLowerCase()) ||
|
policy.name.toLowerCase().includes(policySearchQuery.toLowerCase())
|
||||||
(policy.description &&
|
);
|
||||||
policy.description
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(policySearchQuery.toLowerCase()));
|
|
||||||
|
|
||||||
// Filter by category
|
|
||||||
const matchesCategory =
|
|
||||||
!policyCategoryFilter ||
|
|
||||||
policyCategoryFilter === "all" ||
|
|
||||||
policy.category === policyCategoryFilter;
|
|
||||||
|
|
||||||
return matchesSearch && matchesCategory;
|
|
||||||
});
|
});
|
||||||
}, [getPolicies, policySearchQuery, policyCategoryFilter]);
|
}, [getPolicies, policySearchQuery]);
|
||||||
|
|
||||||
// Handle linking a mitigation to this risk
|
// Handle linking a mitigation to this risk
|
||||||
const handleLinkMitigation = useCallback(
|
const handleLinkMitigation = useCallback(
|
||||||
@@ -875,33 +846,31 @@ function ShowRiskViewContent({
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{risk.mitigations?.edges.map(
|
{risk.mitigations?.edges.map(({ node: mitigation }) => (
|
||||||
({ node: mitigation }: { node: any }) => (
|
<TableRow key={mitigation.id}>
|
||||||
<TableRow key={mitigation.id}>
|
<TableCell>
|
||||||
<TableCell>
|
<Link
|
||||||
<Link
|
to={`/organizations/${organizationId}/mitigations/${mitigation.id}`}
|
||||||
to={`/organizations/${organizationId}/mitigations/${mitigation.id}`}
|
className="font-medium text-blue-600 hover:underline"
|
||||||
className="font-medium text-blue-600 hover:underline"
|
>
|
||||||
>
|
{mitigation.name}
|
||||||
{mitigation.name}
|
</Link>
|
||||||
</Link>
|
</TableCell>
|
||||||
</TableCell>
|
<TableCell>
|
||||||
<TableCell>
|
<Button
|
||||||
<Button
|
variant="ghost"
|
||||||
variant="ghost"
|
size="icon"
|
||||||
size="icon"
|
onClick={() => handleUnlinkMitigation(mitigation)}
|
||||||
onClick={() => handleUnlinkMitigation(mitigation)}
|
disabled={
|
||||||
disabled={
|
unlinkingMitigations[mitigation.id] || false
|
||||||
unlinkingMitigations[mitigation.id] || false
|
}
|
||||||
}
|
title="Unlink mitigation"
|
||||||
title="Unlink mitigation"
|
>
|
||||||
>
|
<Trash2 className="h-4 w-4 text-danger" />
|
||||||
<Trash2 className="h-4 w-4 text-danger" />
|
</Button>
|
||||||
</Button>
|
</TableCell>
|
||||||
</TableCell>
|
</TableRow>
|
||||||
</TableRow>
|
))}
|
||||||
)
|
|
||||||
)}
|
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
@@ -1065,7 +1034,7 @@ function ShowRiskViewContent({
|
|||||||
{filteredMitigations().map((mitigation) => {
|
{filteredMitigations().map((mitigation) => {
|
||||||
// For each render, recalculate linked status directly against the current risk data
|
// For each render, recalculate linked status directly against the current risk data
|
||||||
const isLinked = risk.mitigations?.edges?.some(
|
const isLinked = risk.mitigations?.edges?.some(
|
||||||
(edge: any) => edge.node.id === mitigation.id
|
(edge) => edge.node.id === mitigation.id
|
||||||
);
|
);
|
||||||
const isLinking =
|
const isLinking =
|
||||||
linkingMitigations[mitigation.id] || false;
|
linkingMitigations[mitigation.id] || false;
|
||||||
@@ -1158,24 +1127,6 @@ function ShowRiskViewContent({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Select
|
|
||||||
value={policyCategoryFilter || "all"}
|
|
||||||
onValueChange={(value) =>
|
|
||||||
setPolicyCategoryFilter(value === "all" ? null : value)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-[180px]">
|
|
||||||
<SelectValue placeholder="Filter by category" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="all">All Categories</SelectItem>
|
|
||||||
{getPolicyCategories().map((category) => (
|
|
||||||
<SelectItem key={category} value={category}>
|
|
||||||
{category}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border rounded-md max-h-96 overflow-y-auto">
|
<div className="border rounded-md max-h-96 overflow-y-auto">
|
||||||
@@ -1201,15 +1152,6 @@ function ShowRiskViewContent({
|
|||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<h3 className="font-medium">{policy.name}</h3>
|
<h3 className="font-medium">{policy.name}</h3>
|
||||||
{policy.category && (
|
|
||||||
<Badge
|
|
||||||
variant="outline"
|
|
||||||
className="text-xs font-normal"
|
|
||||||
>
|
|
||||||
<Tag className="h-3 w-3 mr-1" />
|
|
||||||
{policy.category}
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{isLinked ? (
|
{isLinked ? (
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Reference in New Issue
Block a user