import { useState, useEffect } from 'react'; import { Plus, X, Code } from 'lucide-react'; import { Button } from './ui/Button'; import { Input } from './ui/Input'; import { NativeSelect } from './ui/NativeSelect'; import { Card } from './ui/Card'; import { Badge } from './ui/Badge'; import { Alert } from './ui/Alert'; interface PermissionsPolicyItem { feature: string; allowlist: string[]; } interface PermissionsPolicyBuilderProps { value: string; // JSON string of PermissionsPolicyItem[] onChange: (value: string) => void; } const FEATURES = [ 'accelerometer', 'ambient-light-sensor', 'autoplay', 'battery', 'camera', 'display-capture', 'document-domain', 'encrypted-media', 'fullscreen', 'geolocation', 'gyroscope', 'magnetometer', 'microphone', 'midi', 'payment', 'picture-in-picture', 'publickey-credentials-get', 'screen-wake-lock', 'sync-xhr', 'usb', 'web-share', 'xr-spatial-tracking', ]; const ALLOWLIST_PRESETS = [ { label: 'None (disable)', value: '' }, { label: 'Self', value: 'self' }, { label: 'All (*)', value: '*' }, ]; export function PermissionsPolicyBuilder({ value, onChange }: PermissionsPolicyBuilderProps) { const [policies, setPolicies] = useState([]); const [newFeature, setNewFeature] = useState('camera'); const [newAllowlist, setNewAllowlist] = useState(''); const [customOrigin, setCustomOrigin] = useState(''); const [showPreview, setShowPreview] = useState(false); // Parse initial value useEffect(() => { try { if (value) { const parsed = JSON.parse(value) as PermissionsPolicyItem[]; setPolicies(parsed); } else { setPolicies([]); } } catch { setPolicies([]); } }, [value]); // Generate Permissions-Policy string preview const generatePolicyString = (pols: PermissionsPolicyItem[]): string => { return pols .map((pol) => { if (pol.allowlist.length === 0) { return `${pol.feature}=()`; } const allowlistStr = pol.allowlist.join(' '); return `${pol.feature}=(${allowlistStr})`; }) .join(', '); }; const policyString = generatePolicyString(policies); // Update parent component const updatePolicies = (newPolicies: PermissionsPolicyItem[]) => { setPolicies(newPolicies); onChange(JSON.stringify(newPolicies)); }; const handleAddFeature = () => { const existingIndex = policies.findIndex((p) => p.feature === newFeature); let allowlist: string[] = []; if (newAllowlist === 'self') { allowlist = ['self']; } else if (newAllowlist === '*') { allowlist = ['*']; } else if (customOrigin.trim()) { allowlist = [customOrigin.trim()]; } if (existingIndex >= 0) { // Update existing const updated = [...policies]; updated[existingIndex] = { feature: newFeature, allowlist }; updatePolicies(updated); } else { // Add new updatePolicies([...policies, { feature: newFeature, allowlist }]); } setCustomOrigin(''); }; const handleRemoveFeature = (feature: string) => { updatePolicies(policies.filter((p) => p.feature !== feature)); }; const handleQuickAdd = (features: string[]) => { const newPolicies = features.map((feature) => ({ feature, allowlist: [], })); // Merge with existing (don't duplicate) const merged = [...policies]; newPolicies.forEach((newPolicy) => { if (!merged.some((p) => p.feature === newPolicy.feature)) { merged.push(newPolicy); } }); updatePolicies(merged); }; return (

Permissions Policy Builder

{/* Quick Add Buttons */}
Quick Add:
{/* Add Feature Form */}
setNewFeature(e.target.value)} className="w-48" aria-label="Select Feature" > {FEATURES.map((feature) => ( ))} setNewAllowlist(e.target.value)} className="w-40" aria-label="Select Allowlist Origin" > {ALLOWLIST_PRESETS.map((preset) => ( ))} {newAllowlist === '' && ( setCustomOrigin(e.target.value)} placeholder="or enter origin (e.g., https://example.com)" className="flex-1" /> )}
{/* Current Policies */}
{policies.length === 0 ? ( No permissions policies configured. Add features above to restrict browser capabilities. ) : ( policies.map((policy) => (
{policy.feature}
{policy.allowlist.length === 0 ? ( Disabled ) : policy.allowlist.includes('*') ? ( Allowed (all origins) ) : policy.allowlist.includes('self') ? ( Self only ) : (
{policy.allowlist.map((origin) => ( {origin} ))}
)}
)) )}
{/* Policy String Preview */} {showPreview && policyString && (
            {policyString || '(empty)'}
          
)}
); }