Implements a unified permission notification UI that adapts to different runtime environments (Electron desktop vs web browser) with distinct visual presentations. ## What Changed ### New Components - `permission-notification-banner.tsx`: Adaptive notification component * Electron (desktop): Full banner with "⚠️ Approval Required" text and count badge * Web browser (portrait): Circular indicator badge showing pending count - `permission-approval-modal.tsx`: Interactive modal for reviewing/approving permissions * Displays permission type, detailed message, and diff viewer for file changes * Keyboard shortcuts: Enter (allow once), A (always), D (deny), Esc (close) * Queue management with "X of Y" counter for multiple pending permissions - `permission-notification.css`: Comprehensive styling with pulsing animations ### Integration - Updated `instance-shell2.tsx`: * Added banner to desktop center toolbar (next to Command Palette) * Added banner to mobile/phone layout center section * Added modal component for permission approval workflow - Updated `controls.css`: Imported new permission notification styles ## Why This Change **Before**: Permission requests had no visual indicator in the UI, making it difficult for users to know when agent/subagent actions required approval. **After**: Users receive clear, persistent visual notifications with: - Pulsing animation to draw attention - Environment-appropriate UI (full banner on desktop, compact badge on web) - Click-to-review workflow with full permission details ## Benefits 1. **Better UX**: Users immediately see when permissions need approval 2. **Responsive Design**: Adapts to desktop (Electron) and web browser contexts 3. **Accessible**: Proper ARIA labels, keyboard shortcuts, and focus management 4. **Queue Management**: Handles multiple pending permissions gracefully 5. **Contextual Information**: Shows diffs for file changes, permission types, etc. ## Impact - **No Breaking Changes**: Purely additive feature - **Build**: ✅ Verified successful build - **Testing**: ✅ Tested in Electron app and web browser
58 lines
2.0 KiB
TypeScript
58 lines
2.0 KiB
TypeScript
import { Show, createMemo, type Component } from "solid-js"
|
||
import { getPermissionQueueLength } from "../stores/instances"
|
||
import { isElectronHost } from "../lib/runtime-env"
|
||
|
||
interface PermissionNotificationBannerProps {
|
||
instanceId: string
|
||
onClick: () => void
|
||
}
|
||
|
||
const PermissionNotificationBanner: Component<PermissionNotificationBannerProps> = (props) => {
|
||
const queueLength = createMemo(() => getPermissionQueueLength(props.instanceId))
|
||
const hasPermissions = createMemo(() => queueLength() > 0)
|
||
const isElectron = isElectronHost()
|
||
|
||
return (
|
||
<Show when={hasPermissions()}>
|
||
{/* Electron: Full banner with text */}
|
||
<Show when={isElectron}>
|
||
<button
|
||
type="button"
|
||
class="permission-notification-banner"
|
||
onClick={props.onClick}
|
||
aria-label={`${queueLength()} permission${queueLength() > 1 ? "s" : ""} pending approval`}
|
||
>
|
||
<span class="permission-notification-icon" aria-hidden="true">
|
||
⚠️
|
||
</span>
|
||
<span class="permission-notification-text">
|
||
Approval Required
|
||
</span>
|
||
<Show when={queueLength() > 1}>
|
||
<span class="permission-notification-count" aria-label={`${queueLength()} permissions`}>
|
||
{queueLength()}
|
||
</span>
|
||
</Show>
|
||
</button>
|
||
</Show>
|
||
|
||
{/* Web: Compact indicator button */}
|
||
<Show when={!isElectron}>
|
||
<button
|
||
type="button"
|
||
class="permission-indicator-button"
|
||
onClick={props.onClick}
|
||
aria-label={`${queueLength()} permission${queueLength() > 1 ? "s" : ""} pending approval. Click to review.`}
|
||
title={`${queueLength()} permission${queueLength() > 1 ? "s" : ""} pending approval`}
|
||
>
|
||
<span class="permission-indicator-badge">
|
||
{queueLength() > 9 ? "9+" : queueLength()}
|
||
</span>
|
||
</button>
|
||
</Show>
|
||
</Show>
|
||
)
|
||
}
|
||
|
||
export default PermissionNotificationBanner
|