diff --git a/package.json b/package.json index a3036dd..4ac6835 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "read-excel-file": "9.2.0" }, "peerDependencies": { - "@govoplan/core-webui": "^0.1.8", + "@govoplan/core-webui": "^0.1.9", "lucide-react": "^1.23.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/webui/package.json b/webui/package.json index 14eb937..4615ea4 100644 --- a/webui/package.json +++ b/webui/package.json @@ -17,7 +17,7 @@ "read-excel-file": "9.2.0" }, "peerDependencies": { - "@govoplan/core-webui": "^0.1.8", + "@govoplan/core-webui": "^0.1.9", "lucide-react": "^1.23.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/webui/src/api/campaigns.ts b/webui/src/api/campaigns.ts index e7783cb..a5b982e 100644 --- a/webui/src/api/campaigns.ts +++ b/webui/src/api/campaigns.ts @@ -1,5 +1,11 @@ import type { ApiSettings, CampaignListItem, DeltaDeletedItem } from "../types"; import { apiDownload, apiFetch } from "./client"; +export { fetchResourceAccessExplanation } from "@govoplan/core-webui"; +export type { + AccessDecisionProvenanceItem, + ResourceAccessExplanationUser as AccessExplanationUser, + ResourceAccessExplanationResponse +} from "@govoplan/core-webui"; export type CampaignListResponse = CampaignListItem[] | @@ -22,27 +28,6 @@ export type CampaignShare = { export type CampaignShareTarget = {id: string;name: string;secondary?: string | null;}; export type CampaignShareTargets = {users: CampaignShareTarget[];groups: CampaignShareTarget[];}; -export type AccessExplanationUser = { - id: string; - account_id?: string | null; - email?: string | null; - display_name?: string | null; -}; -export type AccessDecisionProvenanceItem = { - kind: string; - id?: string | null; - label?: string | null; - tenant_id?: string | null; - source?: string | null; - details?: Record; -}; -export type ResourceAccessExplanationResponse = { - user: AccessExplanationUser; - resource_type: string; - resource_id: string; - action: string; - provenance: AccessDecisionProvenanceItem[]; -}; export type CampaignUpdatePayload = { external_id?: string | null; @@ -995,20 +980,6 @@ export async function getCampaignShareTargets(settings: ApiSettings, campaignId: return apiFetch(settings, `/api/v1/campaigns/${campaignId}/share-targets`); } -export function fetchResourceAccessExplanation( -settings: ApiSettings, -options: {userId: string;resourceType: string;resourceId: string;action: string;tenantId?: string | null;}) -: Promise { - const params = new URLSearchParams({ - user_id: options.userId, - resource_type: options.resourceType, - resource_id: options.resourceId, - action: options.action - }); - if (options.tenantId) params.set("tenant_id", options.tenantId); - return apiFetch(settings, `/api/v1/admin/access/resource-explanation?${params.toString()}`); -} - export async function getCampaignShares(settings: ApiSettings, campaignId: string): Promise { const response = await apiFetch<{shares: CampaignShare[];}>(settings, `/api/v1/campaigns/${campaignId}/shares`); return response.shares; diff --git a/webui/src/features/campaigns/components/CampaignAccessCard.tsx b/webui/src/features/campaigns/components/CampaignAccessCard.tsx index 74933cc..df1d541 100644 --- a/webui/src/features/campaigns/components/CampaignAccessCard.tsx +++ b/webui/src/features/campaigns/components/CampaignAccessCard.tsx @@ -12,7 +12,7 @@ import { type CampaignShareTargets, type ResourceAccessExplanationResponse } from "../../../api/campaigns"; -import { Button } from "@govoplan/core-webui"; +import { Button, ResourceAccessExplanation } from "@govoplan/core-webui"; import { Card } from "@govoplan/core-webui"; import { ConfirmDialog } from "@govoplan/core-webui"; import DataGrid, { type DataGridColumn } from "../../../components/table/DataGrid"; @@ -221,76 +221,11 @@ export default function CampaignAccessCard({ - { if (!accessExplanationLoading) { setAccessExplanationOpen(false); setAccessExplanation(null); } }} footer={}> - + { if (!accessExplanationLoading) { setAccessExplanationOpen(false); setAccessExplanation(null); } }} footer={}> + setRevokeTarget(null)} onConfirm={() => void revoke()} /> ); } - -function ResourceAccessExplanationContent({ - loading, - explanation, - fallbackResourceLabel -}: {loading: boolean;explanation: ResourceAccessExplanationResponse | null;fallbackResourceLabel: string;}) { - if (loading) return

i18n:govoplan-campaign.loading_access_explanation.04a7c934

; - if (!explanation) return null; - const userLabel = explanation.user.display_name || explanation.user.email || explanation.user.id; - const resourceLabel = explanation.provenance.find((item) => item.kind === "resource")?.label || fallbackResourceLabel || explanation.resource_id; - return ( - <> -
-
i18n:govoplan-campaign.user.9f8a2389

{userLabel}

-
i18n:govoplan-campaign.resource.d1c626a9

{resourceLabel}

-
i18n:govoplan-campaign.action.97c89a4d

{explanation.action}

-
i18n:govoplan-campaign.evidence.8487d192

{explanation.provenance.length}

-
- {explanation.provenance.length === 0 ? -

i18n:govoplan-campaign.no_access_evidence_was_returned.84a21e4e

: -
- {explanation.provenance.map((item, index) => -
- {provenanceKindLabel(item.kind)} -
- {item.source || "i18n:govoplan-campaign.no_source.6dcf9723"} - {item.id && <> ยท {item.id}} -
- {item.label &&

{item.label}

} - {Object.keys(item.details ?? {}).length > 0 &&

{formatProvenanceDetails(item.details ?? {})}

} -
- )} -
- } - ); -} - -function provenanceKindLabel(kind: string): string { - switch (kind) { - case "resource": - return "i18n:govoplan-campaign.resource.d1c626a9"; - case "owner": - return "i18n:govoplan-campaign.owner.89ff3122"; - case "share": - return "i18n:govoplan-campaign.share.09ca55ca"; - case "policy": - return "i18n:govoplan-campaign.policy.0b779a05"; - case "role": - return "i18n:govoplan-campaign.role.b5b4a5a2"; - case "right": - return "i18n:govoplan-campaign.permission.2f81a22d"; - default: - return kind; - } -} - -function formatProvenanceDetails(details: Record): string { - return Object.entries(details).map(([key, value]) => `${key}: ${formatProvenanceValue(value)}`).join("; "); -} - -function formatProvenanceValue(value: unknown): string { - if (value === null || value === undefined) return "i18n:govoplan-campaign.none.6eef6648"; - if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value); - return JSON.stringify(value); -}