Policy Delivery Panel
Right-dock panel listing policies / guardrails active for the route or run. Install Policy Delivery Panel from the VLLNT UI registry with the shadcn CLI.
Right-dock panel listing policies / guardrails active for the route or run. Part of the content family in VLLNT UI, it ships as a machine-readable registry entry — copy the source directly into your app with the shadcn CLI and own it, no runtime dependency on a component library.
Preview
Switch between light and dark to inspect the embedded Storybook preview.
Installation
Add Policy Delivery Panel to your project with the shadcn CLI. The source lands in your codebase, ready to adapt:
pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/policy-delivery-panel.jsonSource
"use client";
import type { ComponentPropsWithoutRef, ReactNode } from "react";
import { cn } from "../../lib/utils";
/**
* Enforcement status for a policy.
*
* @public
*/
export type PolicyStatus = "advisory" | "disabled" | "enforced";
const STATUS_LABEL: Record<PolicyStatus, string> = {
advisory: "Advisory",
disabled: "Disabled",
enforced: "Enforced",
};
const STATUS_TONE: Record<PolicyStatus, string> = {
advisory:
"border-amber-500/40 bg-amber-500/10 text-amber-700 dark:text-amber-300",
disabled: "border-border bg-muted/40 text-muted-foreground",
enforced:
"border-emerald-500/40 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
};
/**
* One policy row.
*
* @public
*/
export type PolicyEntry = {
/** Optional secondary line (rationale, owner, last-updated). */
description?: ReactNode;
/** Stable identifier — used as the React key. */
id: string;
/** Display name (e.g. `"PII redaction"`). */
name: ReactNode;
/** Optional toggle handler — when provided, the row becomes a button. */
onToggle?: () => void;
/** Enforcement status. */
status: PolicyStatus;
};
/**
* Localizable strings.
*
* @public
*/
export type PolicyDeliveryPanelLabels = {
/** Empty-state copy. Defaults to `"No policies"`. */
empty?: string;
/** Aria-label for the panel. Defaults to `"Policy delivery"`. */
region?: string;
};
const DEFAULT_LABELS = {
empty: "No policies",
region: "Policy delivery",
} as const satisfies Required<PolicyDeliveryPanelLabels>;
/**
* Props for {@link PolicyDeliveryPanel}.
*
* @public
*/
export type PolicyDeliveryPanelProps = {
/** Localizable strings. */
labels?: PolicyDeliveryPanelLabels;
/** Policy entries in render order. */
policies: PolicyEntry[];
/** Panel title. Defaults to `"Policies"`. */
title?: ReactNode;
} & ComponentPropsWithoutRef<"section">;
const RowBody = (props: { policy: PolicyEntry }): React.ReactElement => {
const { policy } = props;
return (
<span className="flex flex-1 flex-col gap-0.5 text-left">
<span className="flex items-center justify-between gap-2">
<span className="truncate text-xs font-medium text-foreground">
{policy.name}
</span>
<span
className={cn(
"rounded-full border px-1.5 py-0.5 text-[10px] uppercase tracking-wide",
STATUS_TONE[policy.status],
)}
>
{STATUS_LABEL[policy.status]}
</span>
</span>
{policy.description ? (
<span className="truncate text-[10px] text-muted-foreground">
{policy.description}
</span>
) : null}
</span>
);
};
const Row = (props: { policy: PolicyEntry }): React.ReactElement => {
const { policy } = props;
if (policy.onToggle) {
const handleTogglePolicy = (): void => {
policy.onToggle?.();
};
return (
<button
className="flex w-full items-center gap-2 rounded-md border border-transparent px-2 py-1.5 text-left transition-colors hover:border-border hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
data-policy-row={policy.id}
data-policy-status={policy.status}
onClick={handleTogglePolicy}
type="button"
>
<RowBody policy={policy} />
</button>
);
}
return (
<div
className="flex w-full items-center gap-2 rounded-md px-2 py-1.5"
data-policy-row={policy.id}
data-policy-status={policy.status}
>
<RowBody policy={policy} />
</div>
);
};
/**
* Right-dock panel listing the policies / guardrails that apply to the
* active route or run. Each row shows the policy name, enforcement
* status chip, and optional rationale. Pure presentation; the host
* computes the policy list from the live config and supplies an
* optional toggle handler for admin views.
*
* @example
* ```tsx
* <PolicyDeliveryPanel
* policies={[
* { id: "pii", name: "PII redaction", status: "enforced" },
* { id: "rate", name: "Rate limiting", status: "advisory", description: "60 / s soft cap" },
* { id: "exp", name: "Experiment B", status: "disabled" },
* ]}
* />
* ```
*
* @public
*/
export const PolicyDeliveryPanel = ({
ref,
...props
}: PolicyDeliveryPanelProps & { ref?: React.Ref<HTMLElement> }) => {
const { className, labels, policies, title = "Policies", ...rest } = props;
const resolvedLabels = { ...DEFAULT_LABELS, ...labels };
return (
<section
aria-label={resolvedLabels.region}
className={cn(
"flex w-full flex-col gap-2 rounded-lg border bg-background p-3 text-foreground",
className,
)}
data-policy-delivery-panel
ref={ref}
{...rest}
>
<header>
<h3 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
{title}
</h3>
</header>
{policies.length === 0 ? (
<p
className="px-2 py-3 text-center text-xs text-muted-foreground"
data-policy-state="empty"
>
{resolvedLabels.empty}
</p>
) : (
<ul className="space-y-0.5">
{policies.map((policy) => (
<li key={policy.id}>
<Row policy={policy} />
</li>
))}
</ul>
)}
</section>
);
};
PolicyDeliveryPanel.displayName = "PolicyDeliveryPanel";
Stories
Explore every variant and state in the interactive Storybook:
Preview
Switch between light and dark to inspect the embedded Storybook preview.