@burdenoff/microfe-vibecontrols 2026.709.2 → 2026.710.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/agent-manager/AgentManagerBookmarksDrawer.js +87 -85
- package/dist/components/agent-manager/AgentManagerBookmarksDrawer.js.map +1 -1
- package/dist/components/ai/InstructionFilesManager.js +138 -136
- package/dist/components/ai/InstructionFilesManager.js.map +1 -1
- package/dist/components/ai/PluginHarnessPicker.js +70 -64
- package/dist/components/ai/PluginHarnessPicker.js.map +1 -1
- package/dist/components/docs/DocsEditPanel.js +1 -1
- package/dist/components/docs/DocsEditPanel.js.map +1 -1
- package/dist/components/docs/DocsPageTree.js +1 -1
- package/dist/components/docs/DocsPageTree.js.map +1 -1
- package/dist/components/docs/DocsTabPanel.js +108 -106
- package/dist/components/docs/DocsTabPanel.js.map +1 -1
- package/dist/components/notes/NotesTabPanel.js +99 -99
- package/dist/components/notes/NotesTabPanel.js.map +1 -1
- package/dist/components/scorecard/ScorecardPanel.js +309 -308
- package/dist/components/scorecard/ScorecardPanel.js.map +1 -1
- package/dist/components/sessions/SessionPublicLinkPanel.js +104 -102
- package/dist/components/sessions/SessionPublicLinkPanel.js.map +1 -1
- package/dist/components/settings/AdvancedSection.js +92 -90
- package/dist/components/settings/AdvancedSection.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js +104 -102
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js.map +1 -1
- package/dist/constants/permissions.js +7 -0
- package/dist/constants/permissions.js.map +1 -1
- package/dist/pages/ActionsPage.js +303 -303
- package/dist/pages/ActionsPage.js.map +1 -1
- package/dist/pages/AgentDetailsPage.js +520 -516
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/AgentsPage.js +287 -283
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +554 -549
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/VibeAuditPage.js +2 -2
- package/dist/pages/VibeAuditPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +257 -257
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/dist/pages/VibeDetailsPage.js +688 -693
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/VibesPage.js +49 -41
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/pages/WebhooksPage.js +162 -138
- package/dist/pages/WebhooksPage.js.map +1 -1
- package/dist/pages/tunnels/DomainsTab.js +54 -47
- package/dist/pages/tunnels/DomainsTab.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VibeAuditPage.js","names":[],"sources":["../../src/pages/VibeAuditPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { Shield } from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { isNative, nativeNotify } from '../utils/nativeBridge';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n AuditDeleteDialog,\n AuditExportButton,\n AuditLogDetail,\n AuditLogFilters,\n AuditLogStats,\n AuditLogTable,\n} from '@/components/audit';\nimport {\n EmptyState,\n ErrorState,\n GetHelpButton,\n LoadingState,\n PageHeader,\n} from '@/components/shared';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport {\n useBulkDeleteVibeAuditLogsMutation,\n useDeleteVibeAuditLogMutation,\n useGetVibeAuditLogQuery,\n useListAgentsQuery,\n useListVibesQuery,\n useVibeAuditDashboardQuery,\n} from '@/generated/wspace-operations';\nimport type {\n VibeAuditAction,\n VibeAuditLogFilterInput,\n VibeAuditResourceType,\n VibeAuditStatus,\n} from '@/generated/wspace-types';\nimport { useVibeControls } from '@/providers/VibeControlsProvider';\n\nconst PAGE_SIZE = 50;\n\nexport function VibeAuditPage() {\n useVibeControls();\n\n const { t } = useI18n();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [debouncedSearchQuery, setDebouncedSearchQuery] = useState('');\n const [actionFilter, setActionFilter] = useState<string | null>('all');\n const [resourceTypeFilter, setResourceTypeFilter] = useState<string | null>('all');\n const [statusFilter, setStatusFilter] = useState<string | null>('all');\n const [agentFilter, setAgentFilter] = useState<string | null>('all');\n const [vibeFilter, setVibeFilter] = useState<string | null>('all');\n const [hasCommandFilter, setHasCommandFilter] = useState(false);\n const [page, setPage] = useState(0);\n // F2 — session-history drill-down. Initialised from a ?sessionId= URL param\n // (reciprocal link from the in-session History tab) and also settable by\n // clicking \"Show only this session\" on a SESSION-typed audit entry.\n const [sessionDrillId, setSessionDrillId] = useState<string | null>(() => {\n if (typeof window === 'undefined') return null;\n return new URLSearchParams(window.location.search).get('sessionId');\n });\n const [selectedLogId, setSelectedLogId] = useState<string | null>(null);\n const [selectedLogIds, setSelectedLogIds] = useState<Set<string>>(new Set());\n const [deleteTargetIds, setDeleteTargetIds] = useState<string[]>([]);\n const [deleteError, setDeleteError] = useState<string | null>(null);\n const [deleteSuccess, setDeleteSuccess] = useState<string | null>(null);\n\n const deleteErrorTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const canListAudit = hasPermission(VIBE_PERMISSIONS.AUDIT_LIST);\n const canDeleteAudit = hasPermission(VIBE_PERMISSIONS.AUDIT_DELETE);\n const canExportAudit = hasPermission(VIBE_PERMISSIONS.AUDIT_EXPORT);\n const shouldSkipQueries = permissionsLoading || !canListAudit;\n\n const filter: VibeAuditLogFilterInput = {};\n if (debouncedSearchQuery) filter.search = debouncedSearchQuery;\n if (actionFilter && actionFilter !== 'all') filter.action = actionFilter as VibeAuditAction;\n if (resourceTypeFilter && resourceTypeFilter !== 'all')\n filter.resourceType = resourceTypeFilter as VibeAuditResourceType;\n if (statusFilter && statusFilter !== 'all') filter.status = statusFilter as VibeAuditStatus;\n if (hasCommandFilter) filter.hasCommand = true;\n // Agent / Vibe filters: backend exposes `resourceId` + `resourceType`.\n // We narrow `resourceType` accordingly so the server returns only audit\n // rows whose target is the chosen agent / vibe. If the user already\n // chose a resourceType that conflicts (e.g. SESSION), the resourceId\n // filter would over-narrow — but that combination is documented as\n // intentional power-user behaviour.\n if (agentFilter && agentFilter !== 'all') {\n filter.resourceId = agentFilter;\n if (!filter.resourceType) filter.resourceType = 'AGENT' as VibeAuditResourceType;\n } else if (vibeFilter && vibeFilter !== 'all') {\n filter.resourceId = vibeFilter;\n if (!filter.resourceType) filter.resourceType = 'VIBE' as VibeAuditResourceType;\n }\n // Session drill-down — the server matches resourceType=SESSION AND\n // resourceId=sessionId. Works for killed (soft-deleted) sessions too.\n if (sessionDrillId) filter.sessionId = sessionDrillId;\n\n const { data, loading, error, refetch } = useVibeAuditDashboardQuery({\n variables: {\n filter,\n pagination: { limit: Math.min(Math.max((page + 1) * PAGE_SIZE, PAGE_SIZE), 100) },\n },\n skip: shouldSkipQueries,\n fetchPolicy: 'cache-and-network',\n notifyOnNetworkStatusChange: true,\n });\n\n const { data: agentsData } = useListAgentsQuery({\n variables: { pagination: { limit: 200 } },\n fetchPolicy: 'cache-first',\n skip: shouldSkipQueries,\n });\n const agentsList = (agentsData?.vibecontrolsAgents ?? []).map(\n (a: { id: string; name: string }) => ({ id: a.id, name: a.name })\n );\n\n const { data: vibesData } = useListVibesQuery({\n variables: { pagination: { limit: 200 } },\n fetchPolicy: 'cache-first',\n skip: shouldSkipQueries,\n });\n const vibesList = (vibesData?.vibes?.items ?? []).map((v: { id: string; name: string }) => ({\n id: v.id,\n name: v.name,\n }));\n\n const retentionDays = data?.vibeAuditLogStats?.retentionPolicy?.retentionDays ?? 90;\n const nextCleanupAt = data?.vibeAuditLogStats?.retentionPolicy?.nextCleanup ?? null;\n\n const { data: detailData } = useGetVibeAuditLogQuery({\n variables: { id: selectedLogId! },\n skip: !selectedLogId,\n });\n\n const [deleteAuditLog, { loading: deleteLoading }] = useDeleteVibeAuditLogMutation();\n const [bulkDeleteAuditLogs] = useBulkDeleteVibeAuditLogsMutation();\n\n useEffect(() => {\n const timeoutId = window.setTimeout(() => {\n setDebouncedSearchQuery(searchQuery);\n setPage(0);\n }, 300);\n\n return () => window.clearTimeout(timeoutId);\n }, [searchQuery]);\n\n useEffect(() => {\n return () => {\n if (deleteErrorTimer.current) {\n clearTimeout(deleteErrorTimer.current);\n }\n };\n }, []);\n\n const clearDeleteError = useCallback(() => {\n setDeleteError(null);\n if (deleteErrorTimer.current) {\n clearTimeout(deleteErrorTimer.current);\n deleteErrorTimer.current = null;\n }\n }, []);\n\n const clearDeleteSuccess = useCallback(() => {\n setDeleteSuccess(null);\n }, []);\n\n const allItems = data?.vibeAuditLogs.items ?? [];\n const items = allItems.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE);\n const totalAuditItems = data?.vibeAuditLogs.total ?? 0;\n const visibleLogIds = items.map((item: (typeof items)[number]) => item.id);\n const allVisibleSelected =\n visibleLogIds.length > 0 && visibleLogIds.every((id: string) => selectedLogIds.has(id));\n const partiallySelected =\n visibleLogIds.some((id: string) => selectedLogIds.has(id)) && !allVisibleSelected;\n\n const handleDelete = async (reason: string) => {\n if (deleteTargetIds.length === 0) return;\n\n clearDeleteError();\n clearDeleteSuccess();\n\n try {\n if (deleteTargetIds.length === 1) {\n await deleteAuditLog({ variables: { id: deleteTargetIds[0], input: { reason } } });\n setDeleteSuccess('Deleted 1 audit log');\n } else {\n const result = await bulkDeleteAuditLogs({\n variables: { ids: deleteTargetIds, input: { reason } },\n });\n const deletedCount = result.data?.bulkDeleteVibeAuditLogs.deletedCount ?? 0;\n const failedCount = result.data?.bulkDeleteVibeAuditLogs.failedCount ?? 0;\n setDeleteSuccess(\n `Deleted ${deletedCount} audit logs${failedCount > 0 ? ` • ${failedCount} failed` : ''}`\n );\n }\n\n setDeleteTargetIds([]);\n setSelectedLogIds((previous) => {\n const next = new Set(previous);\n deleteTargetIds.forEach((id) => next.delete(id));\n return next;\n });\n if (selectedLogId && deleteTargetIds.includes(selectedLogId)) {\n setSelectedLogId(null);\n }\n await refetch();\n if (isNative()) void nativeNotify('success');\n } catch (deleteAuditError) {\n console.error('Failed to delete audit log:', deleteAuditError);\n setDeleteError(tr('audit.deleteFailed', 'Failed to delete audit log. Please try again.'));\n if (isNative()) void nativeNotify('error');\n deleteErrorTimer.current = setTimeout(() => {\n setDeleteError(null);\n deleteErrorTimer.current = null;\n }, 30000);\n }\n };\n\n const handleOpenDelete = useCallback(\n (id: string) => {\n if (!canDeleteAudit) return;\n clearDeleteError();\n clearDeleteSuccess();\n setDeleteTargetIds([id]);\n },\n [canDeleteAudit, clearDeleteError, clearDeleteSuccess]\n );\n\n const handleToggleLogSelection = useCallback((id: string, checked: boolean) => {\n setSelectedLogIds((previous) => {\n const next = new Set(previous);\n if (checked) {\n next.add(id);\n } else {\n next.delete(id);\n }\n return next;\n });\n }, []);\n\n const handleToggleAllVisible = useCallback(\n (checked: boolean) => {\n setSelectedLogIds((previous) => {\n const next = new Set(previous);\n visibleLogIds.forEach((id: string) => {\n if (checked) {\n next.add(id);\n } else {\n next.delete(id);\n }\n });\n return next;\n });\n },\n [visibleLogIds]\n );\n\n const handleOpenBulkDelete = useCallback(() => {\n if (!canDeleteAudit || selectedLogIds.size === 0) return;\n clearDeleteError();\n clearDeleteSuccess();\n setDeleteTargetIds(Array.from(selectedLogIds));\n }, [canDeleteAudit, clearDeleteError, clearDeleteSuccess, selectedLogIds]);\n\n if (permissionsLoading) {\n return (\n <div className=\"mx-auto max-w-[1400px] p-4 sm:p-6\">\n <LoadingState message={tr('audit.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (permissions && permissions.permissionStrings?.length > 0 && !canListAudit) {\n return (\n <AccessDenied\n title={tr('common.accessDeniedTitle', 'Access Denied')}\n description={tr(\n 'common.accessDeniedDescription',\n \"You don't have permission to access this resource.\"\n )}\n />\n );\n }\n\n return (\n <div className=\"mx-auto max-w-[1400px] p-4 sm:p-6\">\n <PageHeader\n title={tr('nav.vibeAudit', 'Audit')}\n description={tr(\n 'audit.description',\n 'Comprehensive audit trail of all VibeControls operations'\n )}\n actions={canExportAudit ? <AuditExportButton filter={filter} /> : undefined}\n />\n\n <PagePurpose icon={<Shield className=\"size-4\" />}>\n {tr(\n 'audit.purpose',\n 'The audit trail records who did what across VibeControls — every agent registered, session started, setting changed and more — with timestamps and actors. Use it to investigate an incident, satisfy a compliance review, or simply understand a change after the fact. Filter and export the log for evidence.'\n )}\n </PagePurpose>\n\n {/* Retention banner — sourced from the backend `retentionPolicy`\n so the displayed window updates if the tier changes. */}\n <div className=\"mb-4 flex items-start gap-2 rounded-md border border-status-info-border bg-status-info-bg-subtle px-3 py-2 text-xs text-status-info-text\">\n <Shield size={14} className=\"mt-0.5 flex-shrink-0\" />\n <span>\n {tr(\n 'audit.retentionBanner',\n `Audit logs are kept for ${retentionDays} days. Older entries are automatically purged.`\n )}\n {nextCleanupAt\n ? ` ${tr('audit.retentionNextCleanup', `Next cleanup: ${new Date(nextCleanupAt).toLocaleString()}.`)}`\n : ''}\n </span>\n </div>\n\n {/* Session drill-down banner — shown when scoped to one session's activity. */}\n {sessionDrillId ? (\n <div className=\"mb-4 flex items-center justify-between gap-2 rounded-md border border-action-primary-border bg-[var(--color-accent-soft)] px-3 py-2 text-xs text-text-primary\">\n <span className=\"truncate\">\n {tr('audit.sessionScopeBanner', 'Showing activity for session')}{' '}\n <span className=\"font-mono\">{sessionDrillId}</span>\n </span>\n <button\n type=\"button\"\n onClick={() => {\n setSessionDrillId(null);\n setPage(0);\n }}\n className=\"flex-shrink-0 rounded bg-bg-sunken px-2 py-1 font-medium text-text-secondary hover:text-text-primary\"\n >\n {tr('audit.clearSessionScope', 'Clear')}\n </button>\n </div>\n ) : null}\n\n {/* AuditLogStats is a custom component that doesn't forward rest props\n onto a DOM node, so the tour anchor lives on a wrapper <div>. */}\n <div data-tour=\"audit-log-stats\">\n <AuditLogStats stats={data?.vibeAuditLogStats} loading={loading && !data} />\n </div>\n\n <AuditLogFilters\n searchQuery={searchQuery}\n onSearchChange={setSearchQuery}\n actionFilter={actionFilter}\n onActionChange={(value) => {\n setActionFilter(value);\n setPage(0);\n }}\n resourceTypeFilter={resourceTypeFilter}\n onResourceTypeChange={(value) => {\n setResourceTypeFilter(value);\n setPage(0);\n }}\n statusFilter={statusFilter}\n onStatusChange={(value) => {\n setStatusFilter(value);\n setPage(0);\n }}\n hasCommandFilter={hasCommandFilter}\n onHasCommandChange={(value) => {\n setHasCommandFilter(value);\n setPage(0);\n }}\n agentFilter={agentFilter}\n onAgentChange={(value) => {\n setAgentFilter(value);\n // Agent + Vibe are mutually exclusive via resourceId — clearing one when\n // the other is set keeps the resolved filter input coherent.\n if (value !== 'all') setVibeFilter('all');\n setPage(0);\n }}\n agents={agentsList}\n vibeFilter={vibeFilter}\n onVibeChange={(value) => {\n setVibeFilter(value);\n if (value !== 'all') setAgentFilter('all');\n setPage(0);\n }}\n vibes={vibesList}\n />\n\n {items.length > 0 ? (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"text-sm font-medium text-text-primary\">\n {selectedLogIds.size} selected\n </span>\n {selectedLogIds.size > 0 ? (\n <button\n type=\"button\"\n onClick={() => setSelectedLogIds(new Set())}\n className=\"text-sm text-text-secondary transition-colors hover:text-text-primary\"\n >\n Clear selection\n </button>\n ) : null}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={handleOpenBulkDelete}\n disabled={!canDeleteAudit || selectedLogIds.size === 0}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n Delete Selected{selectedLogIds.size > 0 ? ` (${selectedLogIds.size})` : ''}\n </button>\n </div>\n </div>\n </div>\n ) : null}\n\n {loading && !data ? (\n <LoadingState message={tr('audit.loadingLogs', 'Loading audit logs...')} />\n ) : error ? (\n <ErrorState message={error.message} onRetry={() => refetch()} />\n ) : totalAuditItems === 0 ? (\n <EmptyState\n icon={<Shield size={48} className=\"text-text-secondary\" />}\n title={tr('audit.noLogs', 'No audit logs')}\n description={tr(\n 'audit.emptyDescription',\n 'Audit logs will appear here as operations are performed in VibeControls.'\n )}\n action={\n <GetHelpButton prompt=\"What is the Audit Log in VibeControls and how do I use it?\" />\n }\n />\n ) : (\n <div data-tour=\"audit-log-table\">\n <AuditLogTable\n items={items}\n total={totalAuditItems}\n hasMore={data?.vibeAuditLogs.hasMore ?? false}\n page={page}\n pageSize={PAGE_SIZE}\n onPageChange={setPage}\n onSelectLog={setSelectedLogId}\n onDeleteLog={handleOpenDelete}\n selectedLogId={selectedLogId}\n selectedLogIds={selectedLogIds}\n allVisibleSelected={allVisibleSelected}\n partiallySelected={partiallySelected}\n onToggleLogSelection={handleToggleLogSelection}\n onToggleAllVisible={handleToggleAllVisible}\n />\n </div>\n )}\n\n {selectedLogId && detailData?.vibeAuditLog ? (\n <AuditLogDetail\n log={detailData.vibeAuditLog}\n onClose={() => setSelectedLogId(null)}\n footer={\n detailData.vibeAuditLog.resourceType === 'SESSION' &&\n detailData.vibeAuditLog.resourceId &&\n detailData.vibeAuditLog.resourceId !== sessionDrillId ? (\n <button\n type=\"button\"\n onClick={() => {\n setSessionDrillId(detailData.vibeAuditLog?.resourceId ?? null);\n setSelectedLogId(null);\n setPage(0);\n }}\n className=\"w-full rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg-hover\"\n >\n {tr('audit.showOnlyThisSession', \"Show only this session's activity\")}\n </button>\n ) : null\n }\n />\n ) : null}\n\n {deleteError ? (\n <div\n role=\"alert\"\n className=\"fixed bottom-4 right-4 z-50 rounded-md bg-status-error-bg px-4 py-3 text-sm text-status-error-text shadow-lg\"\n >\n {deleteError}\n <button\n type=\"button\"\n onClick={clearDeleteError}\n className=\"ml-3 text-xs underline opacity-80 hover:opacity-100\"\n >\n {tr('common.dismiss', 'Dismiss')}\n </button>\n </div>\n ) : null}\n\n {deleteSuccess ? (\n <div\n role=\"status\"\n className=\"fixed bottom-4 right-4 z-50 rounded-md bg-status-success-bg px-4 py-3 text-sm text-status-success-text shadow-lg\"\n >\n {deleteSuccess}\n <button\n type=\"button\"\n onClick={clearDeleteSuccess}\n className=\"ml-3 text-xs underline opacity-80 hover:opacity-100\"\n >\n {tr('common.dismiss', 'Dismiss')}\n </button>\n </div>\n ) : null}\n\n <AuditDeleteDialog\n isOpen={deleteTargetIds.length > 0}\n onClose={() => setDeleteTargetIds([])}\n onConfirm={handleDelete}\n loading={deleteLoading}\n title={deleteTargetIds.length > 1 ? 'Delete Audit Logs' : 'Delete Audit Log'}\n description={\n deleteTargetIds.length > 1\n ? `This will permanently delete ${deleteTargetIds.length} audit logs and record the reason in the audit trail.`\n : 'This action will be recorded in the audit trail.'\n }\n confirmLabel={deleteTargetIds.length > 1 ? 'Delete Logs' : 'Delete'}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VibeAuditPage.js","names":[],"sources":["../../src/pages/VibeAuditPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { Shield } from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { isNative, nativeNotify } from '../utils/nativeBridge';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n AuditDeleteDialog,\n AuditExportButton,\n AuditLogDetail,\n AuditLogFilters,\n AuditLogStats,\n AuditLogTable,\n} from '@/components/audit';\nimport {\n EmptyState,\n ErrorState,\n GetHelpButton,\n LoadingState,\n PageHeader,\n} from '@/components/shared';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport {\n useBulkDeleteVibeAuditLogsMutation,\n useDeleteVibeAuditLogMutation,\n useGetVibeAuditLogQuery,\n useListAgentsQuery,\n useListVibesQuery,\n useVibeAuditDashboardQuery,\n} from '@/generated/wspace-operations';\nimport type {\n VibeAuditAction,\n VibeAuditLogFilterInput,\n VibeAuditResourceType,\n VibeAuditStatus,\n} from '@/generated/wspace-types';\nimport { useVibeControls } from '@/providers/VibeControlsProvider';\n\nconst PAGE_SIZE = 50;\n\nexport function VibeAuditPage() {\n useVibeControls();\n\n const { t } = useI18n();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [debouncedSearchQuery, setDebouncedSearchQuery] = useState('');\n const [actionFilter, setActionFilter] = useState<string | null>('all');\n const [resourceTypeFilter, setResourceTypeFilter] = useState<string | null>('all');\n const [statusFilter, setStatusFilter] = useState<string | null>('all');\n const [agentFilter, setAgentFilter] = useState<string | null>('all');\n const [vibeFilter, setVibeFilter] = useState<string | null>('all');\n const [hasCommandFilter, setHasCommandFilter] = useState(false);\n const [page, setPage] = useState(0);\n // F2 — session-history drill-down. Initialised from a ?sessionId= URL param\n // (reciprocal link from the in-session History tab) and also settable by\n // clicking \"Show only this session\" on a SESSION-typed audit entry.\n const [sessionDrillId, setSessionDrillId] = useState<string | null>(() => {\n if (typeof window === 'undefined') return null;\n return new URLSearchParams(window.location.search).get('sessionId');\n });\n const [selectedLogId, setSelectedLogId] = useState<string | null>(null);\n const [selectedLogIds, setSelectedLogIds] = useState<Set<string>>(new Set());\n const [deleteTargetIds, setDeleteTargetIds] = useState<string[]>([]);\n const [deleteError, setDeleteError] = useState<string | null>(null);\n const [deleteSuccess, setDeleteSuccess] = useState<string | null>(null);\n\n const deleteErrorTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const canListAudit = hasPermission(VIBE_PERMISSIONS.AUDIT_LIST);\n const canDeleteAudit = hasPermission(VIBE_PERMISSIONS.AUDIT_DELETE);\n const canExportAudit = hasPermission(VIBE_PERMISSIONS.AUDIT_EXPORT);\n const shouldSkipQueries = permissionsLoading || !canListAudit;\n\n const filter: VibeAuditLogFilterInput = {};\n if (debouncedSearchQuery) filter.search = debouncedSearchQuery;\n if (actionFilter && actionFilter !== 'all') filter.action = actionFilter as VibeAuditAction;\n if (resourceTypeFilter && resourceTypeFilter !== 'all')\n filter.resourceType = resourceTypeFilter as VibeAuditResourceType;\n if (statusFilter && statusFilter !== 'all') filter.status = statusFilter as VibeAuditStatus;\n if (hasCommandFilter) filter.hasCommand = true;\n // Agent / Vibe filters: backend exposes `resourceId` + `resourceType`.\n // We narrow `resourceType` accordingly so the server returns only audit\n // rows whose target is the chosen agent / vibe. If the user already\n // chose a resourceType that conflicts (e.g. SESSION), the resourceId\n // filter would over-narrow — but that combination is documented as\n // intentional power-user behaviour.\n if (agentFilter && agentFilter !== 'all') {\n filter.resourceId = agentFilter;\n if (!filter.resourceType) filter.resourceType = 'AGENT' as VibeAuditResourceType;\n } else if (vibeFilter && vibeFilter !== 'all') {\n filter.resourceId = vibeFilter;\n if (!filter.resourceType) filter.resourceType = 'VIBE' as VibeAuditResourceType;\n }\n // Session drill-down — the server matches resourceType=SESSION AND\n // resourceId=sessionId. Works for killed (soft-deleted) sessions too.\n if (sessionDrillId) filter.sessionId = sessionDrillId;\n\n const { data, loading, error, refetch } = useVibeAuditDashboardQuery({\n variables: {\n filter,\n pagination: { limit: Math.min(Math.max((page + 1) * PAGE_SIZE, PAGE_SIZE), 100) },\n },\n skip: shouldSkipQueries,\n fetchPolicy: 'cache-and-network',\n notifyOnNetworkStatusChange: true,\n });\n\n const { data: agentsData } = useListAgentsQuery({\n variables: { pagination: { limit: 200 } },\n fetchPolicy: 'cache-first',\n skip: shouldSkipQueries,\n });\n const agentsList = (agentsData?.vibecontrolsAgents ?? []).map(\n (a: { id: string; name: string }) => ({ id: a.id, name: a.name })\n );\n\n const { data: vibesData } = useListVibesQuery({\n variables: { pagination: { limit: 200 } },\n fetchPolicy: 'cache-first',\n skip: shouldSkipQueries,\n });\n const vibesList = (vibesData?.vibes?.items ?? []).map((v: { id: string; name: string }) => ({\n id: v.id,\n name: v.name,\n }));\n\n const retentionDays = data?.vibeAuditLogStats?.retentionPolicy?.retentionDays ?? 90;\n const nextCleanupAt = data?.vibeAuditLogStats?.retentionPolicy?.nextCleanup ?? null;\n\n const { data: detailData } = useGetVibeAuditLogQuery({\n variables: { id: selectedLogId! },\n skip: !selectedLogId,\n });\n\n const [deleteAuditLog, { loading: deleteLoading }] = useDeleteVibeAuditLogMutation();\n const [bulkDeleteAuditLogs] = useBulkDeleteVibeAuditLogsMutation();\n\n useEffect(() => {\n const timeoutId = window.setTimeout(() => {\n setDebouncedSearchQuery(searchQuery);\n setPage(0);\n }, 300);\n\n return () => window.clearTimeout(timeoutId);\n }, [searchQuery]);\n\n useEffect(() => {\n return () => {\n if (deleteErrorTimer.current) {\n clearTimeout(deleteErrorTimer.current);\n }\n };\n }, []);\n\n const clearDeleteError = useCallback(() => {\n setDeleteError(null);\n if (deleteErrorTimer.current) {\n clearTimeout(deleteErrorTimer.current);\n deleteErrorTimer.current = null;\n }\n }, []);\n\n const clearDeleteSuccess = useCallback(() => {\n setDeleteSuccess(null);\n }, []);\n\n const allItems = data?.vibeAuditLogs.items ?? [];\n const items = allItems.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE);\n const totalAuditItems = data?.vibeAuditLogs.total ?? 0;\n const visibleLogIds = items.map((item: (typeof items)[number]) => item.id);\n const allVisibleSelected =\n visibleLogIds.length > 0 && visibleLogIds.every((id: string) => selectedLogIds.has(id));\n const partiallySelected =\n visibleLogIds.some((id: string) => selectedLogIds.has(id)) && !allVisibleSelected;\n\n const handleDelete = async (reason: string) => {\n if (deleteTargetIds.length === 0) return;\n\n clearDeleteError();\n clearDeleteSuccess();\n\n try {\n if (deleteTargetIds.length === 1) {\n await deleteAuditLog({ variables: { id: deleteTargetIds[0], input: { reason } } });\n setDeleteSuccess('Deleted 1 audit log');\n } else {\n const result = await bulkDeleteAuditLogs({\n variables: { ids: deleteTargetIds, input: { reason } },\n });\n const deletedCount = result.data?.bulkDeleteVibeAuditLogs.deletedCount ?? 0;\n const failedCount = result.data?.bulkDeleteVibeAuditLogs.failedCount ?? 0;\n setDeleteSuccess(\n `Deleted ${deletedCount} audit logs${failedCount > 0 ? ` • ${failedCount} failed` : ''}`\n );\n }\n\n setDeleteTargetIds([]);\n setSelectedLogIds((previous) => {\n const next = new Set(previous);\n deleteTargetIds.forEach((id) => next.delete(id));\n return next;\n });\n if (selectedLogId && deleteTargetIds.includes(selectedLogId)) {\n setSelectedLogId(null);\n }\n await refetch();\n if (isNative()) void nativeNotify('success');\n } catch (deleteAuditError) {\n console.error('Failed to delete audit log:', deleteAuditError);\n setDeleteError(tr('audit.deleteFailed', 'Failed to delete audit log. Please try again.'));\n if (isNative()) void nativeNotify('error');\n deleteErrorTimer.current = setTimeout(() => {\n setDeleteError(null);\n deleteErrorTimer.current = null;\n }, 30000);\n }\n };\n\n const handleOpenDelete = useCallback(\n (id: string) => {\n if (!canDeleteAudit) return;\n clearDeleteError();\n clearDeleteSuccess();\n setDeleteTargetIds([id]);\n },\n [canDeleteAudit, clearDeleteError, clearDeleteSuccess]\n );\n\n const handleToggleLogSelection = useCallback((id: string, checked: boolean) => {\n setSelectedLogIds((previous) => {\n const next = new Set(previous);\n if (checked) {\n next.add(id);\n } else {\n next.delete(id);\n }\n return next;\n });\n }, []);\n\n const handleToggleAllVisible = useCallback(\n (checked: boolean) => {\n setSelectedLogIds((previous) => {\n const next = new Set(previous);\n visibleLogIds.forEach((id: string) => {\n if (checked) {\n next.add(id);\n } else {\n next.delete(id);\n }\n });\n return next;\n });\n },\n [visibleLogIds]\n );\n\n const handleOpenBulkDelete = useCallback(() => {\n if (!canDeleteAudit || selectedLogIds.size === 0) return;\n clearDeleteError();\n clearDeleteSuccess();\n setDeleteTargetIds(Array.from(selectedLogIds));\n }, [canDeleteAudit, clearDeleteError, clearDeleteSuccess, selectedLogIds]);\n\n if (permissionsLoading) {\n return (\n <div className=\"mx-auto max-w-[1400px] p-4 sm:p-6\">\n <LoadingState message={tr('audit.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (permissions && permissions.permissionStrings?.length > 0 && !canListAudit) {\n return (\n <AccessDenied\n title={tr('common.accessDeniedTitle', 'Access Denied')}\n description={tr(\n 'common.accessDeniedDescription',\n \"You don't have permission to access this resource.\"\n )}\n />\n );\n }\n\n return (\n <div className=\"mx-auto max-w-[1400px] p-4 sm:p-6\">\n <PageHeader\n title={tr('nav.vibeAudit', 'Audit')}\n description={tr(\n 'audit.description',\n 'Comprehensive audit trail of all VibeControls operations'\n )}\n actions={canExportAudit ? <AuditExportButton filter={filter} /> : undefined}\n />\n\n <PagePurpose icon={<Shield className=\"size-4\" />}>\n {tr(\n 'audit.purpose',\n 'The audit trail records who did what across VibeControls — every agent registered, session started, setting changed and more — with timestamps and actors. Use it to investigate an incident, satisfy a compliance review, or simply understand a change after the fact. Filter and export the log for evidence.'\n )}\n </PagePurpose>\n\n {/* Retention banner — sourced from the backend `retentionPolicy`\n so the displayed window updates if the tier changes. */}\n <div className=\"mb-4 flex items-start gap-2 rounded-md border border-status-info-border bg-status-info-bg-subtle px-3 py-2 text-xs text-status-info-text\">\n <Shield size={14} className=\"mt-0.5 flex-shrink-0\" />\n <span>\n {tr(\n 'audit.retentionBanner',\n `Audit logs are kept for ${retentionDays} days. Older entries are automatically purged.`\n )}\n {nextCleanupAt\n ? ` ${tr('audit.retentionNextCleanup', `Next cleanup: ${new Date(nextCleanupAt).toLocaleString()}.`)}`\n : ''}\n </span>\n </div>\n\n {/* Session drill-down banner — shown when scoped to one session's activity. */}\n {sessionDrillId ? (\n <div className=\"mb-4 flex items-center justify-between gap-2 rounded-md border border-action-primary-border bg-[var(--color-accent-soft)] px-3 py-2 text-xs text-text-primary\">\n <span className=\"truncate\">\n {tr('audit.sessionScopeBanner', 'Showing activity for session')}{' '}\n <span className=\"font-mono\">{sessionDrillId}</span>\n </span>\n <button\n type=\"button\"\n onClick={() => {\n setSessionDrillId(null);\n setPage(0);\n }}\n className=\"flex-shrink-0 rounded bg-bg-sunken px-2 py-1 font-medium text-text-secondary hover:text-text-primary\"\n >\n {tr('audit.clearSessionScope', 'Clear')}\n </button>\n </div>\n ) : null}\n\n {/* AuditLogStats is a custom component that doesn't forward rest props\n onto a DOM node, so the tour anchor lives on a wrapper <div>. */}\n <div data-tour=\"audit-log-stats\">\n <AuditLogStats stats={data?.vibeAuditLogStats} loading={loading && !data} />\n </div>\n\n <AuditLogFilters\n searchQuery={searchQuery}\n onSearchChange={setSearchQuery}\n actionFilter={actionFilter}\n onActionChange={(value) => {\n setActionFilter(value);\n setPage(0);\n }}\n resourceTypeFilter={resourceTypeFilter}\n onResourceTypeChange={(value) => {\n setResourceTypeFilter(value);\n setPage(0);\n }}\n statusFilter={statusFilter}\n onStatusChange={(value) => {\n setStatusFilter(value);\n setPage(0);\n }}\n hasCommandFilter={hasCommandFilter}\n onHasCommandChange={(value) => {\n setHasCommandFilter(value);\n setPage(0);\n }}\n agentFilter={agentFilter}\n onAgentChange={(value) => {\n setAgentFilter(value);\n // Agent + Vibe are mutually exclusive via resourceId — clearing one when\n // the other is set keeps the resolved filter input coherent.\n if (value !== 'all') setVibeFilter('all');\n setPage(0);\n }}\n agents={agentsList}\n vibeFilter={vibeFilter}\n onVibeChange={(value) => {\n setVibeFilter(value);\n if (value !== 'all') setAgentFilter('all');\n setPage(0);\n }}\n vibes={vibesList}\n />\n\n {items.length > 0 ? (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"text-sm font-medium text-text-primary\">\n {selectedLogIds.size} selected\n </span>\n {selectedLogIds.size > 0 ? (\n <button\n type=\"button\"\n onClick={() => setSelectedLogIds(new Set())}\n className=\"text-sm text-text-secondary transition-colors hover:text-text-primary\"\n >\n Clear selection\n </button>\n ) : null}\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n {canDeleteAudit && (\n <button\n type=\"button\"\n onClick={handleOpenBulkDelete}\n disabled={selectedLogIds.size === 0}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n Delete Selected{selectedLogIds.size > 0 ? ` (${selectedLogIds.size})` : ''}\n </button>\n )}\n </div>\n </div>\n </div>\n ) : null}\n\n {loading && !data ? (\n <LoadingState message={tr('audit.loadingLogs', 'Loading audit logs...')} />\n ) : error ? (\n <ErrorState message={error.message} onRetry={() => refetch()} />\n ) : totalAuditItems === 0 ? (\n <EmptyState\n icon={<Shield size={48} className=\"text-text-secondary\" />}\n title={tr('audit.noLogs', 'No audit logs')}\n description={tr(\n 'audit.emptyDescription',\n 'Audit logs will appear here as operations are performed in VibeControls.'\n )}\n action={\n <GetHelpButton prompt=\"What is the Audit Log in VibeControls and how do I use it?\" />\n }\n />\n ) : (\n <div data-tour=\"audit-log-table\">\n <AuditLogTable\n items={items}\n total={totalAuditItems}\n hasMore={data?.vibeAuditLogs.hasMore ?? false}\n page={page}\n pageSize={PAGE_SIZE}\n onPageChange={setPage}\n onSelectLog={setSelectedLogId}\n onDeleteLog={handleOpenDelete}\n selectedLogId={selectedLogId}\n selectedLogIds={selectedLogIds}\n allVisibleSelected={allVisibleSelected}\n partiallySelected={partiallySelected}\n onToggleLogSelection={handleToggleLogSelection}\n onToggleAllVisible={handleToggleAllVisible}\n />\n </div>\n )}\n\n {selectedLogId && detailData?.vibeAuditLog ? (\n <AuditLogDetail\n log={detailData.vibeAuditLog}\n onClose={() => setSelectedLogId(null)}\n footer={\n detailData.vibeAuditLog.resourceType === 'SESSION' &&\n detailData.vibeAuditLog.resourceId &&\n detailData.vibeAuditLog.resourceId !== sessionDrillId ? (\n <button\n type=\"button\"\n onClick={() => {\n setSessionDrillId(detailData.vibeAuditLog?.resourceId ?? null);\n setSelectedLogId(null);\n setPage(0);\n }}\n className=\"w-full rounded-md bg-action-primary-bg px-3 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg-hover\"\n >\n {tr('audit.showOnlyThisSession', \"Show only this session's activity\")}\n </button>\n ) : null\n }\n />\n ) : null}\n\n {deleteError ? (\n <div\n role=\"alert\"\n className=\"fixed bottom-4 right-4 z-50 rounded-md bg-status-error-bg px-4 py-3 text-sm text-status-error-text shadow-lg\"\n >\n {deleteError}\n <button\n type=\"button\"\n onClick={clearDeleteError}\n className=\"ml-3 text-xs underline opacity-80 hover:opacity-100\"\n >\n {tr('common.dismiss', 'Dismiss')}\n </button>\n </div>\n ) : null}\n\n {deleteSuccess ? (\n <div\n role=\"status\"\n className=\"fixed bottom-4 right-4 z-50 rounded-md bg-status-success-bg px-4 py-3 text-sm text-status-success-text shadow-lg\"\n >\n {deleteSuccess}\n <button\n type=\"button\"\n onClick={clearDeleteSuccess}\n className=\"ml-3 text-xs underline opacity-80 hover:opacity-100\"\n >\n {tr('common.dismiss', 'Dismiss')}\n </button>\n </div>\n ) : null}\n\n <AuditDeleteDialog\n isOpen={deleteTargetIds.length > 0}\n onClose={() => setDeleteTargetIds([])}\n onConfirm={handleDelete}\n loading={deleteLoading}\n title={deleteTargetIds.length > 1 ? 'Delete Audit Logs' : 'Delete Audit Log'}\n description={\n deleteTargetIds.length > 1\n ? `This will permanently delete ${deleteTargetIds.length} audit logs and record the reason in the audit trail.`\n : 'This action will be recorded in the audit trail.'\n }\n confirmLabel={deleteTargetIds.length > 1 ? 'Delete Logs' : 'Delete'}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|