Last Updated: 2025-11-07 Status: Active Best Practices
This document outlines reusable code patterns, shared utilities, and components across the AutoBot codebase to eliminate duplication and improve maintainability.
- CSS Reusability
- JavaScript/TypeScript Utilities
- Vue Component Reusability
- Usage Examples
- Migration Guide
Purpose: Reusable styling for document feed wrapper sections Used by: KnowledgeStats.vue, KnowledgeCategories.vue Features:
- Gradient emerald green backgrounds
- Animated pulse badge
- Fade-in-up animation
- Dark mode support
Usage:
<script setup>
import '@/styles/document-feed-wrapper.css'
</script>
<template>
<div class="change-feed-section-wrapper">
<div class="section-header prominent">
<h3><i class="fas fa-sync-alt"></i> Title</h3>
<span class="section-badge">Badge Text</span>
</div>
<!-- Content here -->
</div>
</template>Benefits:
- ✅ Eliminated ~60 lines of duplicate CSS
- ✅ Consistent visual hierarchy
- ✅ Centralized style updates
Comprehensive formatting utilities eliminating 33+ duplicate implementations.
import { formatDate, formatTime, formatDateTime, formatTimeAgo } from '@/utils/formatHelpers'
// Date formatting
formatDate('2025-10-30T18:05:00Z') // "10/30/2025"
formatDate(new Date()) // "10/30/2025"
// Time formatting
formatTime('2025-10-30T14:30:00Z') // "2:30 PM"
formatTime(new Date(), true) // "14:30" (24-hour)
// Date and time together
formatDateTime('2025-10-30T14:30:00Z') // "10/30/2025, 2:30 PM"
// Relative time
formatTimeAgo(Date.now() - 3600000) // "1 hour ago"import { formatBytes, formatFileSize } from '@/utils/formatHelpers'
formatBytes(0) // "0 Bytes"
formatBytes(1024) // "1 KB"
formatBytes(1536) // "1.5 KB"
formatBytes(1048576) // "1 MB"
formatFileSize(1048576, 1) // "1.0 MB" (custom decimals)import { formatNumber, formatPercentage } from '@/utils/formatHelpers'
formatNumber(1234567) // "1,234,567"
formatNumber(1234.5678, 2) // "1,234.57"
formatPercentage(0.75, 1, true) // "75.0%" (from decimal)
formatPercentage(75, 1, false) // "75.0%" (from percentage)import { formatCategoryName, truncateString } from '@/utils/formatHelpers'
formatCategoryName('system_commands') // "System Commands"
formatCategoryName('auto_bot_docs') // "Auto Bot Docs"
truncateString('Hello World', 5) // "Hello..."Migration Status:
- ✅
DocumentChangeFeed.vue- Migrated to sharedformatBytes - ✅ 20+ components already using shared utilities
- 📋 TODO: Migrate remaining components with duplicate formatDate/formatFileSize
Reusable empty state component eliminating duplicate implementations in 11+ components.
Props:
icon(string): Font Awesome icon class (default:"fas fa-inbox")title(string): Optional title textmessage(string): Optional message textcompact(boolean): Compact mode with reduced spacing
Usage:
<template>
<EmptyState
icon="fas fa-inbox"
title="No documents found"
message="Start by adding your first document"
>
<template #actions>
<button @click="addDocument">Add Document</button>
</template>
</EmptyState>
</template>
<script setup>
import EmptyState from '@/components/ui/EmptyState.vue'
</script>Components to migrate:
- DocumentChangeFeed.vue (line 161-167)
- KnowledgeCategories.vue (line 69-73, 230-233)
- FailedVectorizationsManager.vue
- KnowledgeEntries.vue
- DeduplicationManager.vue
- KnowledgeBrowser.vue
- CategoryTree.vue
- NPUWorkersSettings.vue
- CodebaseAnalytics.vue
- VectorizationProgressModal.vue
- ChatMessages.vue
Reusable modal/dialog component eliminating duplicate implementations in 14+ components.
Props:
modelValue(boolean): v-model binding for visibilitytitle(string): Modal title (required)size(string): Modal size -"small"(500px),"medium"(900px),"large"(1200px)showClose(boolean): Show close button (default: true)closeOnOverlay(boolean): Close on overlay click (default: true)scrollable(boolean): Enable scrollable content (default: true)
Events:
update:modelValue: Emitted when modal visibility changesclose: Emitted when modal is closed
Slots:
default: Modal contentactions: Modal action buttons (footer)
Usage:
<template>
<BaseModal
v-model="showModal"
title="Delete Item"
size="small"
@close="handleClose"
>
<p>Are you sure you want to delete this item?</p>
<template #actions>
<button @click="showModal = false">Cancel</button>
<button @click="handleDelete">Delete</button>
</template>
</BaseModal>
</template>
<script setup>
import { ref } from 'vue'
import BaseModal from '@/components/ui/BaseModal.vue'
const showModal = ref(false)
</script>Components to migrate:
- KnowledgeCategories.vue (lines 120-179, 215-257)
- SecretsManager.vue
- PhaseStatusIndicator.vue
- KnowledgePersistenceDialog.vue
- KnowledgeEntries.vue
- AdvancedStepConfirmationModal.vue
- NPUWorkersSettings.vue
- ChatInterface.vue
- KnowledgeSearch.vue
- KnowledgeComponentReview.vue
- VectorizationProgressModal.vue
- UserManagementSettings.vue
- TerminalModals.vue
- MonitoringDashboard.vue
Reusable status badge component for consistent status indicators.
Props:
variant(string): Badge color variant -"success","danger","warning","info","primary","secondary"(default:"secondary")size(string): Badge size -"small","medium","large"(default:"medium")icon(string): Optional Font Awesome icon class
Usage:
<template>
<StatusBadge variant="success" icon="fas fa-check-circle">
Active
</StatusBadge>
<StatusBadge variant="danger" size="large">
Failed
</StatusBadge>
<StatusBadge variant="warning">
Pending
</StatusBadge>
</template>
<script setup>
import StatusBadge from '@/components/ui/StatusBadge.vue'
</script>Components to migrate:
- DocumentChangeFeed.vue (lines 12-27) - Change badges
- VectorizationStatusBadge.vue - Can be replaced entirely
- ServiceStatusIndicator.vue
- SystemStatusIndicator.vue
- ConnectionStatus.vue
Reusable data table component with sorting, pagination, and custom cell rendering.
Props:
columns(Column[]): Table columns configuration (required)data(any[]): Table data rows (required)showHeader(boolean): Show table header (default: true)title(string): Optional table titlepagination(boolean): Enable pagination (default: false)itemsPerPage(number): Items per page (default: 10)loading(boolean): Loading state (default: false)emptyIcon(string): Empty state icon (default:"fas fa-inbox")emptyTitle(string): Empty state titleemptyMessage(string): Empty state message
Events:
page-change: Emitted when page changes (page: number)sort-change: Emitted when sort changes (key: string, direction: 'asc' | 'desc')
Slots:
header-left: Custom header left contentheader-actions: Custom header actionscell-{key}: Custom cell rendering (per column)actions: Row actions column
Column Configuration:
interface Column {
key: string // Data key
label: string // Column header
sortable?: boolean // Enable sorting
format?: (value: any) => string // Custom formatter
}Usage:
<template>
<DataTable
:columns="columns"
:data="items"
:pagination="true"
:items-per-page="10"
title="User List"
>
<!-- Custom cell rendering -->
<template #cell-status="{ value, row }">
<StatusBadge :variant="value">{{ value }}</StatusBadge>
</template>
<!-- Row actions -->
<template #actions="{ row }">
<button @click="edit(row)">Edit</button>
<button @click="deleteItem(row)">Delete</button>
</template>
<!-- Header actions -->
<template #header-actions>
<button @click="addItem">Add New</button>
</template>
</DataTable>
</template>
<script setup lang="ts">
import DataTable from '@/components/ui/DataTable.vue'
import StatusBadge from '@/components/ui/StatusBadge.vue'
const columns = [
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email', sortable: true },
{ key: 'status', label: 'Status' },
{ key: 'createdAt', label: 'Created', format: (v) => formatDate(v) }
]
const items = ref([...])
</script>Components to migrate:
- FileListTable.vue - Primary use case
- NPUWorkersSettings.vue - Worker table
- UserManagementSettings.vue - User table
- CodebaseAnalytics.vue - Analytics tables
- ManPageManager.vue - Man page table
- HostCard.vue (could use for services)
These components already exist and should be used:
LoadingSpinner.vue- Simple spinnerStableLoadingState.vue- Skeleton loader with stable layoutUnifiedLoadingView.vue- Full-page loading viewSkeletonLoader.vue- Skeleton placeholder
BaseButton.vue- Base button componentTouchFriendlyButton.vue- Touch-optimized button
BaseInput- Moved to the shared kit (#14778):import { BaseInput } from '@autobot/ui'(libs/autobot-ui/src/components/BaseInput.vue). The main app's local copy is deleted. Props:modelValue,type,label,placeholder,helperText,error,size,disabled,readonly,required,clearable,clearLabel,id,autocomplete; eventsupdate:modelValue/clear; exposedfocus()/blur(); slotsprefix/suffix.class,styleanddata-*attrs land on the wrapper; every other attr (aria-label,aria-labelledby,name,maxlength, listeners) lands on the native<input>-- a field with no visiblelabelmust passaria-labeloraria-labelledby. Label, helper and clear-button text come from the app (no i18n in the kit). Styled by the--aui-input-*tokens, mapped inlibs/autobot-ui/src/tokens/adapter.css.
ProgressBar.vue- Progress bar componentMessageStatus.vue- Message status indicator
BasePanel.vue- Base panel container
The codebase has excellent composable organization in src/composables/:
useDocumentChanges.ts- Document lifecycle trackinguseKnowledgeBase.ts- Knowledge base operationsuseKnowledgeVectorization.ts- Vectorization stateuseConversationFiles.ts- Conversation file managementuseUploadProgress.ts- File upload progress
useModal.ts- Modal state managementuseDisplaySettings.ts- Display preferencesusePagination.ts- Pagination logicuseUnifiedLoading.ts- Loading state management
plugins/api.ts(useApiClient()) - Imperative API request handlingcomposables/api/useFetchEndpoint.ts- Reactive data-loading composableuseErrorHandler.ts- Error handlinguseLocalStorage.ts- Local storage abstractionuseClipboard.ts- Clipboard operationsuseKeyboard.ts- Keyboard shortcuts
useInfrastructure.ts- Infrastructure managementuseConnectionTester.ts- Connection testinguseTerminalStore.ts- Terminal state
Before (DocumentChangeFeed.vue):
<!-- Empty State -->
<div v-else class="empty-state">
<i class="fas fa-inbox fa-3x"></i>
<p>No recent changes detected</p>
<button class="btn btn-secondary" @click="handleScanNow">
Scan for Changes
</button>
</div>
<style scoped>
.empty-state {
text-align: center;
padding: 3rem 1rem;
color: #6b7280;
}
.empty-state i {
margin-bottom: 1rem;
color: #d1d5db;
}
.empty-state p {
margin-bottom: 1rem;
}
</style>After:
<script setup>
import EmptyState from '@/components/ui/EmptyState.vue'
</script>
<!-- Empty State -->
<EmptyState
v-else
icon="fas fa-inbox"
message="No recent changes detected"
>
<template #actions>
<button class="btn btn-secondary" @click="handleScanNow">
Scan for Changes
</button>
</template>
</EmptyState>
<!-- No scoped CSS needed -->Savings: ~25 lines of code removed
Before (KnowledgeCategories.vue):
<!-- Create/Edit Category Dialog -->
<div v-if="showCreateDialog || showEditDialog" class="dialog-overlay" @click="closeDialogs">
<div class="dialog" @click.stop>
<div class="dialog-header">
<h3>{{ showEditDialog ? 'Edit Category' : 'Create Category' }}</h3>
<button @click="closeDialogs" class="close-btn">
<i class="fas fa-times"></i>
</button>
</div>
<!-- ... content ... -->
</div>
</div>
<style scoped>
/* 150+ lines of modal CSS */
</style>After:
<script setup>
import BaseModal from '@/components/ui/BaseModal.vue'
</script>
<BaseModal
v-model="showCategoryDialog"
:title="editMode ? 'Edit Category' : 'Create Category'"
size="small"
>
<!-- Content here -->
<template #actions>
<button @click="showCategoryDialog = false">Cancel</button>
<button @click="saveCategory">Save</button>
</template>
</BaseModal>
<!-- No modal CSS needed -->Savings: ~150 lines of code removed
Before (FileListTable.vue):
<!-- 300+ lines of custom table implementation -->
<table>
<thead>
<tr>
<th @click="sort('name')">
Name
<i :class="getSortIcon('name')"></i>
</th>
<!-- More columns -->
</tr>
</thead>
<tbody>
<tr v-for="item in sortedItems" :key="item.id">
<td>{{ item.name }}</td>
<!-- More cells -->
</tr>
</tbody>
</table>
<!-- 200+ lines of table CSS and logic -->After:
<script setup>
import DataTable from '@/components/ui/DataTable.vue'
</script>
<DataTable
:columns="[
{ key: 'name', label: 'Name', sortable: true },
{ key: 'size', label: 'Size', format: formatBytes },
{ key: 'modified', label: 'Modified', format: formatDate }
]"
:data="files"
:pagination="true"
:items-per-page="20"
>
<template #actions="{ row }">
<button @click="download(row)">Download</button>
</template>
</DataTable>
<!-- Minimal CSS for custom styling only -->Savings: ~400 lines of code removed
Search for common patterns:
# Find empty states
grep -r "empty-state" autobot-frontend/src/components/
# Find modals
grep -r "dialog-overlay" autobot-frontend/src/components/
# Find status badges
grep -r "badge badge-" autobot-frontend/src/components/
# Find tables
grep -r "<table" autobot-frontend/src/components/- Import the reusable component
- Replace custom implementation
- Remove duplicate CSS
- Test functionality
- ✅ Visual appearance matches
- ✅ Interactions work correctly
- ✅ Dark mode supported
- ✅ Accessibility maintained
- ✅ Eliminated ~60 lines duplicate CSS (document feed wrapper)
- ✅ Consistent visual design across components
- ✅ Centralized style updates
- 📋 Potential: ~500+ lines more can be eliminated
- ✅ Eliminated 33+ duplicate format implementations
- ✅ Removed 7 lines from DocumentChangeFeed.vue
- ✅ Centralized formatting logic
- 📋 Potential: ~200+ lines more can be eliminated
- ✅ Created 4 new reusable components
- ✅ EmptyState: 11+ components to migrate (~275 lines saved)
- ✅ BaseModal: 14+ components to migrate (~2100 lines saved)
- ✅ StatusBadge: 5+ components to migrate (~150 lines saved)
- ✅ DataTable: 6+ components to migrate (~2400 lines saved)
- 📊 ~5,600+ lines of duplicate code can be eliminated
- 📊 ~40+ components can benefit from shared utilities
- 📊 Improved consistency across UI/UX
- 📊 Faster development with reusable patterns
GitHub Issue: #10894 - Track full migration progress
- ✅ Created shared CSS module (
document-feed-wrapper.css) - ✅ Migrated DocumentChangeFeed to use
formatBytesfrom shared utilities - ✅ Created 4 reusable UI components (EmptyState, BaseModal, StatusBadge, DataTable)
- ✅ Migrated DocumentChangeFeed.vue to EmptyState component (~14 lines saved)
- ✅ Migrated KnowledgeCategories.vue modals to BaseModal (~105 lines saved)
Lines Saved So Far: ~579 / ~5,600 lines (10.3%)
- ✅ Migrated KnowledgeBrowser.vue to EmptyState component (~7 lines saved)
- ✅ Migrated ManPageManager.vue to EmptyState component (~10 lines saved)
- ✅ Migrated DeleteConversationDialog.vue to BaseModal component (~80 lines saved)
- ✅ Migrated KnowledgeEntries.vue to EmptyState component (~11 lines saved)
- ✅ Migrated ChatMessages.vue to EmptyState component (~8 lines saved)
- ✅ Migrated FailedVectorizationsManager.vue to EmptyState component (~9 lines saved)
- ✅ Migrated DeduplicationManager.vue to EmptyState component (2 empty states, ~18 lines saved)
- ✅ Migrated FileTreeView.vue to EmptyState component (~11 lines saved)
- ✅ Migrated CodebaseAnalytics.vue to EmptyState component (8 empty states, ~43 lines saved)
- ✅ Migrated VectorizationProgressModal.vue to EmptyState component (~11 lines saved)
- ✅ Migrated NPUWorkersSettings.vue to EmptyState component (with action button, ~9 lines saved)
- ✅ Migrated CategoryTree.vue to EmptyState component (~9 lines saved)
- ✅ Migrated KnowledgeSearch.vue to EmptyState component (complex with content, ~13 lines saved)
- ✅ Migrated PromptsSettings.vue to EmptyState component (with action button, ~27 lines saved)
- ✅ Migrated SecretsManager.vue to EmptyState component (with action button, ~6 lines saved)
- ✅ Migrated ValidationDashboard.vue to EmptyState component (2 empty states, ~1 line saved)
- ✅ Migrated ChatSidebar.vue to EmptyState component (~1 line saved)
- ✅ Migrated KnowledgeStats.vue to EmptyState component (~4 lines saved)
- ✅ Migrated PhaseProgressionIndicator.vue to EmptyState component (with title prop and child content, ~31 lines saved)
- ✅ Migrated HistoryView.vue to EmptyState component (~6 lines saved)
- ✅ Migrated KnowledgeCategories.vue to EmptyState component (3 empty states, ~41 lines saved)
- ✅ Migrated CacheSettings.vue to EmptyState component (~6 lines saved)
- ✅ Migrated MonitoringDashboard.vue to EmptyState component (3 compact empty states, ~6 lines saved)
- ✅ Migrated FileListTable.vue to EmptyState component (improved semantic structure, ~8 lines saved)
- ✅ Migrated LogViewer.vue to EmptyState component (compact placeholder, ~1 line saved)
- ✅ Migrated WorkflowApproval.vue to EmptyState component (~1 line saved)
- ✅ Migrated AsyncErrorBoundaryDemo.vue to EmptyState component (~14 lines saved)
- ✅ Migrated InfrastructureManager.vue to EmptyState component (with action button, ~15 lines saved)
- ✅ Migrated ChatFilePanel.vue to EmptyState component (compact inline state, ~4 lines saved)
- ✅ Migrated PopoutChromiumBrowser.vue to EmptyState component (2 empty states with action button, ~19 lines saved)
📊 Batch 12 Deep Dive Assessment (January 2025): After exhaustive codebase analysis, the following findings guide our strategy:
EmptyState Migrations: ✅ Near Complete
- 33 components successfully migrated (~579 lines saved)
- Remaining candidates offer minimal benefit (1-3 lines each)
- Most contextual empty states already use compact inline patterns
BaseModal Migrations:
- ElevationDialog.vue (604 lines): Security-critical, custom red gradient, password input, risk badges - intentionally distinctive
- AdvancedStepConfirmationModal.vue (1,670 lines): Workflow management, nested modals, step editing - highly specialized
- KnowledgePersistenceDialog.vue (910 lines): Complex configuration with multiple tabs/sections
- VectorizationProgressModal.vue (561 lines): Real-time progress tracking with logs
- TerminalModals.vue (1,057 lines): Multiple terminal-specific modals in one file
- DeploymentProgressModal.vue: Progress modal with log streaming
- CommandPermissionDialog.vue: Permission workflow with approval logic
- AddHostModal.vue: Infrastructure configuration with validation
Why BaseModal isn't suitable for these:
- All have 500-1,600+ lines with extensive custom styling
- Highly specialized business logic (security, workflows, real-time updates)
- Custom layouts that don't fit BaseModal's header/content/actions pattern
- Many have nested modals, tabs, or complex form validation
- Migration would require massive refactoring with high risk, minimal benefit
Other Reusability Patterns:
- Loading spinners: Inline button states, not standalone components
- Status indicators: Already using ServiceStatusIndicator component
- Form patterns: Vary significantly by use case
- Error messages: Context-dependent styling and placement
Revised Goal Assessment: The initial ~5,600 line estimate was optimistic. Actual duplicate code is closer to ~1,500-2,000 lines across:
- Empty states: ✅ 579 lines saved (most complete)
- Modals: ❌ Not viable (too specialized)
- Other patterns: 🔄 Future opportunity (requires new components)
Recommended Next Steps:
- ✅ Mark EmptyState migrations as substantially complete
- 📋 Focus on creating NEW reusable patterns for remaining duplicates:
- LoadingState component for full-page loading (not button spinners)
- FormGroup component for consistent form field layouts
- ActionButton component for primary/secondary button patterns
- NotificationToast component for user feedback
- 📋 Re-estimate target based on actual patterns found (~1,500-2,000 lines realistic)
📊 Batch 13 Implementation Findings (January 2025): Attempted to implement batch 12 recommendations - key learnings:
UnifiedLoadingView Analysis:
- UnifiedLoadingView already exists and is well-designed
- Only 4 components currently use it (PopoutChromiumBrowser, NoVNCViewer, DesktopInterface, ChatInterface)
- Uses
useUnifiedLoadingcomposable for centralized loading state management - Why not widely adopted: Requires components to use the unified loading system
- Example: InfrastructureManager uses
isLoadingfrom domain-specificuseInfrastructurecomposable - Migrating would require refactoring entire composable to use unified loading system
- Most components have domain-specific loading state tied to their data fetching
- Example: InfrastructureManager uses
- Conclusion: UnifiedLoadingView is an architectural pattern, not a drop-in component
- Can't simply replace custom loading UI without changing state management architecture
- Migration would be highly invasive with uncertain benefit
- Current approach (domain-specific loading states) is actually more appropriate
Form Pattern Analysis:
- 20+ components have form inputs (label + input/textarea/select patterns)
- Forms are highly domain-specific:
- Infrastructure forms: Host configuration, deployment settings
- Knowledge forms: Category management, file upload
- Settings forms: Cache config, NPU workers, secrets
- Security forms: Permission dialogs, elevation requests
- Why FormGroup isn't viable: Each form has unique:
- Validation logic (inline, server-side, real-time)
- Layout requirements (horizontal, vertical, grid, inline)
- Field types and combinations
- Error display patterns
- Conditional field visibility
- Conclusion: Forms are not good candidates for generic components
- Too much context-specific logic and styling
- Forcing generic patterns would reduce flexibility
Revised Understanding: The codebase is actually well-architected. Most "duplicate" code is contextual variation, not true duplication:
- Loading states: Tied to domain-specific data fetching patterns
- Forms: Varied by business requirements
- Modals: Specialized for their use cases
- Empty states: ✅ Successfully abstracted (33 migrations, ~579 lines)
What We Learned:
- Not all similar-looking code is duplicate code
- Architecture matters - can't force generic solutions onto domain-specific patterns
- EmptyState worked because it's truly presentational with no logic
- UnifiedLoadingView exists but is an architectural choice, not a migration target
- Forms and modals are inherently contextual
Actual Remaining Opportunity: ~200-400 lines
- Focus on truly generic presentational components
- Don't force architectural changes for marginal savings
- Current codebase structure is appropriate for the problem domain
📊 Batch 14 Utility Consolidation (January 2025): Final sweep for duplicate utility functions - concrete savings found:
DeploymentProgressModal Format Functions: ✅ Migrated
- Found: 2 duplicate format functions (formatTimestamp, formatLogTime) - 20 lines
- Action: Replaced with shared formatHelpers utilities (formatDateTime, formatTime)
- After: 2-line wrappers using shared utilities + 1 import
- Lines Saved: ~18 lines
- Location:
autobot-frontend/src/components/infrastructure/DeploymentProgressModal.vue
Other Duration Formatting:
- AsyncComponentWrapper.vue:
formatLoadingTime()- unique to loading metrics (ms/s display) - RumDashboard.vue:
formatUptime()- unique to uptime display (h/m/s display) - Conclusion: These are contextual variations, not true duplicates
- Per batch 13 principles: Don't create utilities for single-use patterns
Batch 14 Summary:
- ✅ 18 lines saved (DeploymentProgressModal migration)
- ✅ formatHelpers.ts continues to prevent future duplication
- ✅ Validated batch 13 principle: Only consolidate truly duplicate patterns
📊 Batch 15 StatusBadge Adoptions (January 2025): Migrated 3 components to use existing StatusBadge component:
1. PopoutChromiumBrowser.vue ✅
- Before: Inline "Connected" badge with custom Tailwind classes
- After:
<StatusBadge variant="success" size="small">Connected</StatusBadge> - Lines Saved: ~1 line (improved consistency)
- Location:
autobot-frontend/src/components/PopoutChromiumBrowser.vue:205
2. HostCard.vue ✅
- Before: Inline status badge with 4 conditional color classes (active/pending/error/deploying)
- After:
<StatusBadge :variant="statusVariant" size="small">{{ host.status }}</StatusBadge>+ computed variant mapping - Lines Saved: ~11 lines (12 lines inline badge → 1 StatusBadge component)
- Location:
autobot-frontend/src/components/infrastructure/HostCard.vue:18-20
3. ChatFilePanel.vue ✅
- Before: Inline "AI Generated" badge with purple styling
- After:
<StatusBadge variant="primary" size="small">AI Generated</StatusBadge> - Lines Saved: ~2 lines
- Location:
autobot-frontend/src/components/chat/ChatFilePanel.vue:123-130
Batch 15 Summary:
- ✅ 3 components migrated to StatusBadge
- ✅ ~14 lines saved
- ✅ Increased StatusBadge usage from 2 to 5 components (150% adoption increase)
- ✅ Demonstrates value of leveraging existing components
📊 Batch 16 StatusBadge Enforcement (January 2025): Continued migration to StatusBadge component with more complex components:
1. RedisServiceControl.vue ✅
- Before: 3 status mapping functions (getStatusBadgeClass, getHealthIndicatorClass, getHealthCheckBadgeClass) with switch statements
- After: 3 computed variant mappings (statusVariant, healthVariant, getHealthCheckVariant) + StatusBadge components
- Functions Removed:
getStatusBadgeClass()(~14 lines)getHealthIndicatorClass()(~14 lines)getHealthCheckBadgeClass()(~14 lines)
- Lines Saved: ~42 lines (3 functions removed, replaced with 3 compact variant maps)
- Location:
autobot-frontend/src/components/services/RedisServiceControl.vue - Note: Kept
getStatusDotClass()andgetHealthCheckCardClass()- still needed for dot animation and card styling
2. ResearchBrowser.vue ✅
- Before: 2 inline status class mappings (statusClass computed, getResultStatusClass function)
- After: 2 variant mapping functions (statusVariant computed, getResultStatusVariant function) + StatusBadge components
- Functions Replaced:
statusClasscomputed property (9 lines) →statusVariantcomputed (7 lines)getResultStatusClassfunction (9 lines) →getResultStatusVariantfunction (7 lines)
- CSS Removed:
.status-badgeclass (3 lines) - Lines Saved: ~7 lines
- Location:
autobot-frontend/src/components/ResearchBrowser.vue
Batch 16 Summary:
- ✅ 2 components migrated to StatusBadge
- ✅ ~49 lines saved
- ✅ Increased StatusBadge usage from 5 to 7 components (40% increase)
- ✅ Demonstrates value even in complex components with multiple status types
📊 Batch 17 StatusBadge Enforcement (January 2025): Migrated MonitoringDashboard.vue with 2 badge patterns:
MonitoringDashboard.vue ✅
- Before: 2 badge CSS classes with variant styles (priority-badge, severity-badge)
- After: 2 variant mapping functions (getPriorityVariant, getSeverityVariant) + StatusBadge components
- Badges Removed:
.priority-badgewith 3 variants (high/medium/low) - 9 lines CSS.severity-badgewith 2 variants (critical/warning) - 6 lines CSS
- Functions Added:
getPriorityVariant()- maps high/medium/low to danger/warning/infogetSeverityVariant()- maps critical/warning to danger/warning
- Template Updates:
- Line 286: Replaced
<span :class="['priority-badge', rec.priority]">with StatusBadge - Line 321: Replaced
<span :class="['severity-badge', alert.severity]">with StatusBadge
- Line 286: Replaced
- Lines Saved: ~15 lines (CSS removed)
- Location:
autobot-frontend/src/components/monitoring/MonitoringDashboard.vue
Batch 17 Summary:
- ✅ 1 component migrated (2 badge patterns)
- ✅ ~15 lines saved
- ✅ Increased StatusBadge usage from 7 to 9 instances (29% increase)
- ✅ Demonstrates CSS consolidation benefit
📊 Batch 18 StatusBadge Enforcement (January 2025): Migrated 4 components with 5 badge patterns total:
1. SecretsManager.vue ✅
- Before: 2 badge patterns with scope and type variants
- After:
getScopeVariant()andgetTypeVariant()mapping functions + StatusBadge components - Badges Removed:
.badgebase class +.badge-chat,.badge-generalscope variants - 8 lines CSS.badge-ssh_key,.badge-password,.badge-api_keytype variants - 9 lines CSS
- Template Updates: Lines 87-90 replaced inline badges with StatusBadge
- Lines Saved: ~17 lines
- Location:
autobot-frontend/src/components/SecretsManager.vue
2. CommandPermissionDialog.vue ✅
- Before: Risk level badge with 4 variants (low/medium/high/critical)
- After:
getRiskVariant()mapping function + StatusBadge component - Badges Removed:
.risk-badgewith 4 variants - 28 lines CSS - Function Added:
getRiskVariant()maps LOW/MEDIUM/HIGH/CRITICAL to success/warning/danger/danger - Template Updates: Line 28 replaced risk-badge with StatusBadge
- Lines Saved: ~28 lines
- Location:
autobot-frontend/src/components/CommandPermissionDialog.vue
3. ElevationDialog.vue ✅
- Before: Risk level badge with 4 variants (identical pattern to CommandPermissionDialog)
- After:
getRiskVariant()mapping function + StatusBadge component - Badges Removed:
.risk-badgewith 4 variants - 28 lines CSS - Function Added: Same getRiskVariant() pattern for consistency
- Template Updates: Line 28 replaced risk-badge with StatusBadge
- Lines Saved: ~28 lines
- Location:
autobot-frontend/src/components/ElevationDialog.vue
4. KnowledgeStats.vue ✅
- Before: Status badge with 2 variants (online/offline)
- After:
getStatusVariant()TypeScript function + StatusBadge component - Badges Removed:
.status-badgewith online/offline variants - 17 lines CSS - Function Added:
getStatusVariant()maps online/offline/unknown to success/danger/secondary - Template Updates: Line 68 replaced status-badge with StatusBadge
- Lines Saved: ~17 lines
- Location:
autobot-frontend/src/components/knowledge/KnowledgeStats.vue
Batch 18 Summary:
- ✅ 4 components migrated (5 badge patterns total)
- ✅ ~90 lines saved (CSS + template simplification)
- ✅ Increased StatusBadge usage from 9 to 14 instances (56% increase)
- ✅ Demonstrates pattern consistency: Both CommandPermissionDialog and ElevationDialog use identical risk badge mapping
- ✅ Covers diverse contexts: Secrets management, command permissions, elevation dialogs, knowledge stats
📊 Batch 19 StatusBadge Final Sweep (January 2025): Final StatusBadge migration completing the enforcement wave:
NPUWorkersSettings.vue ✅
- Before: Status badge with 4 variants (online/offline/busy/error)
- After:
getStatusVariant()TypeScript function + StatusBadge component - Badges Removed:
.status-badgewith 4 variants - 29 lines CSS - Function Added:
getStatusVariant()maps online/offline/busy/error to success/secondary/warning/danger - Template Updates: Line 116 replaced status-badge with StatusBadge (retained status-dot for visual indicator)
- Lines Saved: ~29 lines
- Location:
autobot-frontend/src/components/settings/NPUWorkersSettings.vue
Batch 19 Summary:
- ✅ 1 component migrated (final candidate)
- ✅ ~29 lines saved
- ✅ Increased StatusBadge usage from 14 to 15 instances (7% increase)
- ✅ StatusBadge enforcement substantially complete - 650% usage increase from baseline (2 → 15 instances)
Goal: Begin BaseButton adoption to replace duplicate inline button patterns across components.
Strategic Context: Following StatusBadge enforcement completion (batches 15-19), shifted focus to button component consolidation. Discovered TWO unused button components:
- BaseButton.vue - 11 variants (primary/secondary/success/danger/warning/info/light/dark/outline/ghost/link), 5 sizes
- TouchFriendlyButton.vue - 5 variants with touch optimization features (ripple, haptic feedback, 44px min targets)
Decision: Started with BaseButton due to more comprehensive variant support (11 vs 5), deferring TouchFriendlyButton overlap resolution for later.
1. ErrorBoundary.vue - Error recovery component
- Buttons: 3 (primary: retry, secondary: reload, ghost: toggle details)
- Lines Saved: ~47 lines of duplicate button CSS
- Technical Notes:
- Preserved conditional text rendering (
retrying ? 'Retrying...' : 'Try Again') - Maintained disabled state binding (
:disabled="retrying") - All click handlers and component logic unchanged
- Preserved conditional text rendering (
- Location:
autobot-frontend/src/components/ErrorBoundary.vue - Commit: abd34a6 (lines 54, 25-43, 274-320 removed)
2. async/AsyncErrorFallback.vue - Async component error fallback
- Buttons: 4 (primary: retry, secondary: reload, outline: go home, ghost: toggle)
- Lines Saved: ~66 lines of duplicate button CSS (kept .fa-spin animation)
- Technical Notes:
- Preserved exponential backoff retry logic
- Maintained icon animations (
:class="{ 'fa-spin': retrying }") - Preserved retry count display (
Retry (${retryCount}/${maxRetries})) - Kept service worker cache clearing on reload
- Location:
autobot-frontend/src/components/async/AsyncErrorFallback.vue - Commit: abd34a6 (lines 65-67, 27-57, 340-405 removed)
3. PhaseStatusIndicator.vue - Project phase status display
- Buttons: 3 (primary: refresh, secondary: validate, info: report)
- Lines Saved: ~44 lines of duplicate button CSS
- Technical Notes:
- Preserved loading state animations (fa-sync spinning)
- Maintained disabled states during operations
- Options API component (required components registration)
- Location:
autobot-frontend/src/components/PhaseStatusIndicator.vue - Commit: abd34a6 (lines 124-130, 88-99, 557-600 removed)
Batch 20 Summary:
- ✅ 3 components migrated (error recovery, async loading, status display)
- ✅ 10 button elements replaced with BaseButton
- ✅ ~157 lines of duplicate CSS removed (47 + 66 + 44)
- ✅ BaseButton usage increased from 0 to 3 components (new baseline)
- ✅ 5 variants validated: primary, secondary, ghost, outline, info
Migration Pattern Established:
<!-- BEFORE: Inline button with duplicate CSS -->
<button @click="retry" class="btn btn-primary" :disabled="retrying">
{{ retrying ? 'Retrying...' : 'Try Again' }}
</button>
<style scoped>
.btn {
padding: 0.5rem 1rem;
border: none;
border-radius: 6px;
cursor: pointer;
/* ...47 more lines... */
}
</style>
<!-- AFTER: BaseButton component -->
<BaseButton variant="primary" @click="retry" :disabled="retrying">
{{ retrying ? 'Retrying...' : 'Try Again' }}
</BaseButton>
<!-- No duplicate CSS needed -->Technical Approach:
- Used BaseButton's 11-variant system for comprehensive coverage
- Preserved all functionality: disabled states, click handlers, conditional content
- Maintained icon animations and loading states
- Zero behavior changes - pure refactor for code reuse
- Both Composition API and Options API components supported
Next Steps:
Continue BaseButton migrations✅ IN PROGRESS - Batch 21 complete (5 total components now using BaseButton)Address TouchFriendlyButton vs BaseButton overlap✅ RESOLVED - Touch features integrated into BaseButton- Document migration guide with before/after examples
Goal: Continue BaseButton adoption across workflow management and knowledge integration components.
1. WorkflowApproval.vue - Workflow approval and management interface
- Buttons: 4 (success: approve step, danger: deny step + cancel workflow, secondary: refresh)
- Lines Saved: ~44 lines of duplicate button CSS
- Technical Notes:
- Workflow approval actions with conditional rendering
- Preserved disabled states during approval operations
- Composition API with TypeScript (<script setup lang="ts">)
- All click handlers and conditional visibility maintained
- Location:
autobot-frontend/src/components/WorkflowApproval.vue - Commit: bc2d72f (lines 200, 143-158, 173-188, 677-720 removed)
2. ManPageManager.vue - Man page integration management
- Buttons: 7 (3× outline sm: refresh/hide, primary: initialize/search, success: integrate, info: test)
- Lines Saved: ~43 lines of duplicate button CSS
- Technical Notes:
- Leveraged BaseButton's built-in
:loadingprop - Simplified loading state handling - Removed manual spinner conditionals (
v-if="!loading"/v-elseicon logic) - Options API with setup() + components registration
- Multiple refresh buttons, integration actions, search functionality
- Preserved all icon animations and disabled states
- Leveraged BaseButton's built-in
- Location:
autobot-frontend/src/components/ManPageManager.vue - Commit: bc2d72f (lines 323-329, multiple button replacements, 936-978 removed)
Batch 21 Summary:
- ✅ 2 components migrated (workflow management, knowledge integration)
- ✅ 11 button elements replaced with BaseButton
- ✅ ~87 lines of duplicate CSS removed (44 + 43)
- ✅ BaseButton usage increased from 3 to 5 components (67% increase)
- ✅ 6 variants validated: primary, secondary, success, danger, info, outline
- ✅ 2 size variants validated: sm, md
Technical Highlight - Loading State Simplification:
<!-- BEFORE: Manual loading spinner logic -->
<button>
<i class="fas fa-rocket" v-if="!loading?.initialize"></i>
<i class="fas fa-spinner fa-spin" v-else></i>
Initialize Machine Knowledge
</button>
<!-- AFTER: BaseButton handles loading automatically -->
<BaseButton :loading="loading?.initialize">
<i class="fas fa-rocket"></i>
Initialize Machine Knowledge
</BaseButton>
<!-- BaseButton shows spinner automatically when loading=true -->Cumulative BaseButton Progress:
- Batch 20: 3 components, ~157 lines, 10 buttons
- Batch 21: 2 components, ~87 lines, 11 buttons
- Combined Total: 5 components, ~244 lines saved, 21 buttons consolidated
Goal: Resolve TouchFriendlyButton vs BaseButton overlap by extending BaseButton with touch optimization features.
Strategic Decision: Extended BaseButton with optional touch features rather than maintaining two separate button components. This approach provides:
- ✅ Single unified button component for all use cases
- ✅ Progressive enhancement - desktop apps use lightweight BaseButton, mobile apps enable touch features
- ✅ Maintains all 11 BaseButton variants + touch capabilities
- ✅ Backward compatible with batch 20 migrations (touchOptimized defaults to false)
1. Optional Touch Props:
interface Props {
// ... existing props ...
touchOptimized?: boolean // Enable all touch features (default: false)
touchFeedback?: boolean // Visual ripple effect (default: true)
hapticFeedback?: boolean // Device vibration (default: true)
}2. Touch Event Handlers:
@touchstart- Triggers ripple effect and haptic feedback@touchend- Resets pressed state@touchcancel- Handles touch cancellation- Emits:
touchStart,touchEndevents for parent components
3. Ripple Effect System:
- Dynamic ripple creation at touch point coordinates
- 600ms animation with scale and opacity transition
- Automatic cleanup after animation completion
- Respects
touchFeedbackprop (can be disabled)
4. Haptic Feedback:
- 10ms vibration on touch start using
navigator.vibrate() - Gracefully handles devices without vibration support
- Respects
hapticFeedbackprop (can be disabled)
5. Touch-Optimized Styling:
- 44px minimum touch targets (iOS/Android accessibility standard)
-webkit-tap-highlight-color: transparent(removes default mobile tap highlight)touch-action: manipulation(improves touch responsiveness)overflow: hidden(contains ripple effects)- Touch-specific pressed state with
scale(0.95)transform - Media query
@media (hover: none) and (pointer: coarse)disables desktop hover on touch devices
Desktop Button (default - no touch features):
<BaseButton variant="primary" @click="handleAction">
Click Me
</BaseButton>
<!-- Lightweight, desktop-optimized -->Mobile Touch-Optimized Button:
<BaseButton
variant="primary"
touchOptimized
@click="handleAction"
@touchStart="handleTouchStart"
>
Tap Me
</BaseButton>
<!-- Includes ripple effects, haptic feedback, 44px touch targets -->Customized Touch Features:
<BaseButton
variant="primary"
touchOptimized
:touchFeedback="false"
:hapticFeedback="true"
>
Vibrate Only
</BaseButton>
<!-- Haptic feedback enabled, visual ripple disabled -->Touch State Management:
const ripple = ref<HTMLElement>()
const isPressed = ref(false)
const handleTouchStart = (event: TouchEvent) => {
if (disabled || loading || !touchOptimized) return
isPressed.value = true
if (touchFeedback) createRipple(event)
if (hapticFeedback && 'vibrate' in navigator) navigator.vibrate(10)
emit('touchStart', event)
}Ripple Effect Calculation:
const createRipple = (event: TouchEvent) => {
const button = ripple.value.parentElement!
const rect = button.getBoundingClientRect()
const touch = event.touches[0]
const x = touch.clientX - rect.left
const y = touch.clientY - rect.top
const rippleElement = document.createElement('div')
rippleElement.className = 'ripple-effect'
rippleElement.style.left = `${x - 25}px`
rippleElement.style.top = `${y - 25}px`
ripple.value.appendChild(rippleElement)
setTimeout(() => ripple.value.removeChild(rippleElement), 600)
}CSS Enhancements:
.btn-touch-optimized {
min-height: 44px;
min-width: 44px;
overflow: hidden;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
.ripple-effect {
animation: ripple-animation 0.6s ease-out;
/* ... ripple styles ... */
}Before: Two separate components
- BaseButton.vue - 11 variants, no touch support
- TouchFriendlyButton.vue - 5 variants, touch optimized (0 usage)
After: Single unified component
- BaseButton.vue - 11 variants + optional touch features
- TouchFriendlyButton.vue - Can be deprecated or converted to wrapper
- ✅ Backward compatible - existing batch 20 migrations unchanged
- ✅ Zero breaking changes - touchOptimized defaults to false
- ✅ Future-ready - all buttons can enable touch features as needed
- Batch 20 components unaffected - touchOptimized=false by default
- New mobile components - Can use touchOptimized=true for enhanced UX
- Responsive components - Can conditionally enable based on device detection
- No duplicate code - Single button component serves both desktop and mobile
Files Modified:
autobot-frontend/src/components/base/BaseButton.vue(extended with touch features) — superseded (#18849): the main app now uses the shared kit button,import { BaseButton } from '@autobot/ui'(libs/autobot-ui/src/components/BaseButton.vue); the local file is gone
TouchFriendlyButton.vue Status: Recommend deprecation or conversion to lightweight wrapper around <BaseButton touchOptimized> for backward compatibility.
Goal: Migrate dialog components with permission/elevation workflows to BaseButton.
Components Migrated: 2 components, 7 buttons, ~187 lines saved
Purpose: Command execution permission dialog with approval/denial/comment actions.
Buttons Migrated:
- Comment Actions:
btn btn-secondary→<BaseButton variant="secondary">(Cancel comment)btn btn-primary→<BaseButton variant="primary" :loading="isProcessing">(Send Feedback)
- Footer Actions:
btn btn-cancel→<BaseButton variant="secondary">(Deny)btn btn-comment→<BaseButton variant="warning">(Comment)btn btn-allow→<BaseButton variant="success" :loading="isProcessing">(Allow)
Loading State Benefit:
<!-- BEFORE: Manual loading spinner logic -->
<button class="btn btn-allow" :class="{ processing: isProcessing }">
<i v-if="isProcessing" class="fas fa-spinner fa-spin"></i>
<i v-else class="fas fa-check"></i>
{{ isProcessing ? 'Executing...' : 'Allow' }}
</button>
<!-- AFTER: BaseButton handles loading automatically -->
<BaseButton variant="success" :loading="isProcessing">
<i class="fas fa-check"></i>
{{ isProcessing ? 'Executing...' : 'Allow' }}
</BaseButton>CSS Removed: ~145 lines (.btn, .btn:disabled, .btn-cancel, .btn-allow, .btn-comment, .btn-secondary, .btn-primary styles)
Purpose: Administrator privilege elevation dialog with password authentication.
Buttons Migrated:
btn btn-cancel→<BaseButton variant="secondary">(Cancel)btn btn-approve→<BaseButton variant="danger" :loading="isProcessing">(Authorize)
Variant Mapping:
- Custom
btn-approvewith red background (#dc2626) →variant="danger"(perfect color match)
CSS Removed: ~42 lines (.btn, .btn:disabled, .btn-cancel, .btn-approve styles)
Batch 22 Summary:
- Components: 2 (CommandPermissionDialog, ElevationDialog)
- Buttons: 7 consolidated
- Lines: ~187 saved
- Variants: 5 (secondary, primary, warning, success, danger)
- Combined Total: 7 components, ~431 lines saved, 28 buttons consolidated
Goal: Migrate browser automation and knowledge management components to BaseButton.
Components Migrated: 2 components, 12 buttons, ~96 lines saved
Purpose: Chromium browser automation interface with Playwright integration.
Buttons Migrated:
- Error Overlay:
btn btn-primary btn-sm→<BaseButton variant="primary" size="sm" :loading="isInitializingBrowser">(Retry Connection)
- Empty State:
btn btn-primary→<BaseButton variant="primary" :loading="isInitializingBrowser">(Launch Browser Session)
- Interaction Overlay:
btn btn-primary→<BaseButton variant="primary">(Wait & Monitor)btn btn-secondary→<BaseButton variant="secondary">(Take Control)btn btn-outline→<BaseButton variant="outline">(Dismiss)
CSS Removed: ~49 lines (.btn, .btn-sm, .btn-primary, .btn-secondary, .btn-outline styles)
Purpose: System knowledge base management with vector operations.
Buttons Migrated:
- Primary Actions (vector operations):
btn btn-primary btn-highlight→<BaseButton variant="primary" :loading="isVectorizing" class="btn-highlight">(Generate Vector Embeddings)btn btn-primary→<BaseButton variant="primary" :loading="isInitializing">(Initialize Machine Knowledge)btn btn-primary→<BaseButton variant="primary" :loading="isReindexing">(Reindex Documents)
- Secondary Actions (man pages):
btn btn-secondary→<BaseButton variant="secondary" :loading="isRefreshing">(Refresh Man Pages)btn btn-secondary→<BaseButton variant="secondary" :loading="isPopulating">(Populate Common Commands)btn btn-secondary→<BaseButton variant="secondary" :loading="isDocPopulating">(Index AutoBot Docs)
- Utility:
btn btn-outline→<BaseButton variant="outline">(Refresh Stats)
Custom Styling Preserved:
- Kept
.btn-highlightclass for gradient styling on vector embeddings button - Applied as additional class:
<BaseButton class="btn-highlight">
CSS Removed: ~47 lines (.btn, .btn:disabled, .btn-primary, .btn-secondary, .btn-outline styles)
Batch 23 Summary:
- Components: 2 (PopoutChromiumBrowser, SystemKnowledgeManager)
- Buttons: 12 consolidated
- Lines: ~96 saved
- Variants: 4 (primary, secondary, outline, sm size)
- Combined Total: 9 components, ~527 lines saved, 40 buttons consolidated
Goal: Migrate ResearchBrowser component with comprehensive browser automation controls to BaseButton.
Component Migrated: 1 component, 16 buttons, ~39 lines saved
Purpose: AI research browser automation with Playwright integration and agent control.
Buttons Migrated by Category:
Header Controls:
btn btn-secondary btn-sm→<BaseButton variant="secondary" size="sm" :loading="isRefreshingStatus">(Refresh status)btn btn-outline btn-xs→<BaseButton variant="outline" size="xs">(Copy URL)
Interaction Alert:
btn btn-primary btn-sm→<BaseButton variant="primary" size="sm" :loading="isWaitingForUser">(Wait)btn btn-secondary btn-sm→<BaseButton variant="secondary" size="sm">(Open Browser)
Result Actions:
btn btn-warning btn-sm→<BaseButton variant="warning" size="sm">(Open Browser for Result)
Session Controls (4 buttons):
btn btn-outline btn-sm→<BaseButton variant="outline" size="sm" :loading="isPerformingAction">(Extract Content, Save MHTML)btn btn-outline btn-sm→<BaseButton variant="outline" size="sm" :loading="isNavigating">(Navigate)btn btn-danger btn-sm→<BaseButton variant="danger" size="sm" :loading="isClosingSession">(Close Session)
Navigation Input:
btn btn-primary btn-sm→<BaseButton variant="primary" size="sm" :disabled="!navigationUrl" :loading="isNavigating">(Go)btn btn-secondary btn-sm→<BaseButton variant="secondary" size="sm">(Cancel)
Browser Controls:
btn btn-primary btn-xs→<BaseButton variant="primary" size="xs" :loading="isNavigatingBrowser">(Navigate browser)btn btn-warning btn-xs→<BaseButton variant="warning" size="xs" :loading="isPausingAgent">(Take Control)btn btn-success btn-xs→<BaseButton variant="success" size="xs" :loading="isResumingAgent">(Resume Agent)btn btn-outline btn-xs→<BaseButton variant="outline" size="xs">(Toggle Browser View)btn btn-primary btn-xs→<BaseButton variant="primary" size="xs">(Pop Out)
Key Features Demonstrated:
- ✅ Consistent :loading prop across all async operations
- ✅ Both sm and xs size variants for different contexts
- ✅ 7 different variants used: primary, secondary, outline, warning, danger, success
- ✅ Conditional :disabled with :loading (navigation button)
CSS Removed: ~39 lines (Tailwind @apply directives: .btn, .btn:disabled, .btn-primary, .btn-secondary, .btn-outline, .btn-warning, .btn-danger, .btn-success, .btn-sm, .btn-xs)
Batch 24 Summary:
- Component: 1 (ResearchBrowser)
- Buttons: 16 consolidated
- Lines: ~39 saved
- Variants: 7 (primary, secondary, outline, warning, danger, success, + sm/xs sizes)
- Combined Total: 10 components, ~566 lines saved, 56 buttons consolidated
Goal: Migrate terminal modal dialogs and chat sidebar to BaseButton for consistent UI patterns.
Components Migrated: 2 components, 19 buttons, ~114 lines saved
Purpose: Terminal confirmation modals for reconnect, command execution, emergency kill, and workflow actions.
Buttons Migrated by Modal:
Reconnect Modal:
btn btn-secondary→<BaseButton variant="secondary" :disabled="isReconnecting">(Cancel)btn btn-primary→<BaseButton variant="primary" :loading="isReconnecting">(Reconnect)
Command Confirmation Modal:
btn btn-danger→<BaseButton variant="danger" :loading="isExecutingCommand">(Execute Command)btn btn-secondary→<BaseButton variant="secondary" :disabled="isExecutingCommand">(Cancel)
Emergency Kill Modal:
btn btn-danger→<BaseButton variant="danger" :loading="isKillingProcesses">(Kill All Processes)btn btn-secondary→<BaseButton variant="secondary" :disabled="isKillingProcesses">(Cancel)
Key Patterns:
- ✅ Consistent :loading prop for async operations
- ✅ Manual spinner removal (BaseButton handles internally)
- ✅ Proper :disabled usage during loading states
⚠️ Advanced Pattern: Workflow buttons use conditional loading::loading="isProcessingWorkflow && lastWorkflowAction === 'execute'"to isolate loading state per action
CSS Removed: ~91 lines (removed .btn, .btn-primary, .btn-secondary, .btn-danger, .btn-success, .btn-warning, .loading-spinner, @keyframes spin)
Purpose: Chat session management, multi-select deletion, system control, and display settings.
Buttons Migrated by Section:
Sidebar Toggle:
- Custom toggle →
<BaseButton variant="ghost" class="p-3">(Collapse/Expand)
Selection Mode (2 buttons):
- Selection controls →
<BaseButton variant="ghost" size="xs">(Select, Cancel)
Chat History Actions (2 buttons):
- History item controls →
<BaseButton variant="ghost" size="xs" class="text-blueGray-400 p-1">(Edit) - History item controls →
<BaseButton variant="ghost" size="xs" class="text-red-400 p-1">(Delete)
Chat Actions Grid (4 buttons):
btn btn-primary text-xs→<BaseButton variant="primary" size="xs" class="py-1.5 px-2">(New)btn btn-secondary text-xs→<BaseButton variant="secondary" size="xs" :disabled="!store.currentSessionId">(Reset)btn btn-danger text-xs→<BaseButton variant="danger" size="xs" :disabled="!store.currentSessionId">(Delete)btn btn-outline text-xs→<BaseButton variant="outline" size="xs">(Refresh)
Selection Mode Actions:
btn btn-danger w-full→<BaseButton variant="danger" size="xs" class="w-full" :disabled="selectedSessions.size === 0">(Delete Selected)
System Control:
btn btn-primary w-full→<BaseButton variant="primary" size="xs" class="w-full" :loading="isSystemReloading">(Reload System)
Edit Modal (2 buttons):
- Modal cancel →
<BaseButton variant="secondary">(Cancel) - Modal save →
<BaseButton variant="primary">(Save)
Key Features Demonstrated:
- ✅ Ghost variant for subtle UI controls (toggle, selection, history actions)
- ✅ Size xs for compact grid layouts
- ✅ Loading state for system reload operation
- ✅ Conditional :disabled based on state (currentSessionId, selectedSessions)
- ✅ Custom classes preserved for specific styling needs
CSS Removed: ~23 lines (Tailwind @apply directives: .btn, .btn-primary, .btn-secondary, .btn-danger, .btn-outline, .btn:disabled)
Batch 25 Summary:
- Components: 2 (TerminalModals, ChatSidebar)
- Buttons: 19 consolidated (6 terminal + 13 chat)
- Lines: ~114 saved (~91 terminal + ~23 chat)
- Variants: 5 (primary, secondary, danger, outline, ghost)
- Combined Total: 12 components, ~680 lines saved, 75 buttons consolidated
Goal: Migrate knowledge management, service control, and monitoring components to BaseButton for consistent UI patterns.
Components Migrated: 3 components, 19 buttons, ~129 lines saved
Purpose: Knowledge base document change tracking with scanning and filtering capabilities.
Buttons Migrated:
Main Controls:
btn btn-primary btn-sm→<BaseButton variant="primary" size="sm" :loading="isScanning">(Scan Now)btn btn-secondary→<BaseButton variant="secondary">(Scan for Changes - empty state)
Action Buttons:
btn btn-sm btn-outline-secondary→<BaseButton variant="outline" size="sm">(Clear History)btn btn-sm btn-outline-secondary→<BaseButton variant="outline" size="sm">(Export Changes)
Filter Buttons (4 buttons):
filter-btn+.activeclass →<BaseButton :variant="activeFilter === 'all' ? 'primary' : 'outline'" size="sm">(All)filter-btn+.activeclass →<BaseButton :variant="activeFilter === 'added' ? 'primary' : 'outline'" size="sm">(Added)filter-btn+.activeclass →<BaseButton :variant="activeFilter === 'updated' ? 'primary' : 'outline'" size="sm">(Updated)filter-btn+.activeclass →<BaseButton :variant="activeFilter === 'removed' ? 'primary' : 'outline'" size="sm">(Removed)
Key Patterns:
- ✅ Dynamic variant switching for active filters (primary vs outline)
- ✅ Loading state for scan operations
- ✅ Size sm for compact action buttons
CSS Removed: ~75 lines (.btn, .btn-primary, .btn-secondary, .btn-outline-secondary, .btn-sm, .filter-btn, .filter-btn:hover, .filter-btn.active)
Purpose: Redis service management with start, stop, restart controls and confirmation dialogs.
Buttons Migrated:
Service Controls:
btn btn-success→<BaseButton variant="success" :disabled="serviceStatus.status === 'running' || loading">(Start)btn btn-warning→<BaseButton variant="warning" :disabled="serviceStatus.status !== 'running' || loading">(Restart)btn btn-danger→<BaseButton variant="danger" :disabled="serviceStatus.status !== 'running' || loading">(Stop)btn btn-secondary→<BaseButton variant="secondary" :loading="loading">(Refresh)
Confirmation Dialog:
- Cancel button →
<BaseButton variant="secondary">(Cancel) - Confirm button →
<BaseButton :variant="confirmDialog.type === 'danger' ? 'danger' : 'primary'">(Confirm)
Key Patterns:
- ✅ Conditional :disabled based on service status
- ✅ Loading state for refresh operation
- ✅ Dynamic variant for confirm button based on action severity
CSS Removed: ~30 lines (.btn, .btn-success, .btn-warning, .btn-danger, .btn-secondary)
Purpose: Phase 9 GPU/NPU monitoring dashboard with real-time performance tracking.
Buttons Migrated:
Dashboard Controls:
- Toggle monitoring →
<BaseButton :variant="monitoringActive ? 'danger' : 'success'" :disabled="loading">(Start/Stop) - Refresh button →
<BaseButton variant="secondary" :loading="loading">(Refresh Dashboard)
Alert & Recommendations:
- Alert banner →
<BaseButton variant="outline" size="sm" class="btn-outline-light">(View Details) - Recommendations →
<BaseButton variant="outline" size="sm" class="btn-outline-primary">(Refresh Recommendations) - Modal close →
<BaseButton variant="ghost" size="xs" class="btn-close">(Close Modal)
Key Patterns:
- ✅ Dynamic variant toggle (success ↔ danger) based on monitoring state
- ✅ Loading states for async operations
- ✅ Custom outline classes preserved for light backgrounds
- ✅ Ghost variant for minimal close button
CSS Removed: ~24 lines (.btn, .btn:disabled, .btn-success, .btn-danger, .btn-secondary, .btn-outline-primary, .btn-outline-light, .btn-sm)
Batch 26 Summary:
- Components: 3 (DocumentChangeFeed, RedisServiceControl, MonitoringDashboard)
- Buttons: 19 consolidated (8 knowledge + 6 services + 5 monitoring)
- Lines: ~129 saved (~75 knowledge + ~30 services + ~24 monitoring)
- Variants: 6 (primary, secondary, success, warning, danger, outline, ghost)
- Combined Total: 15 components, ~809 lines saved, 94 buttons consolidated
Goal: Migrate advanced workflow modal with complex step management controls to BaseButton for consistent UI patterns.
Components Migrated: 1 component, 17 buttons, ~170 lines saved
Purpose: Advanced workflow step management modal with command editing, risk assessment, and step reordering capabilities.
Buttons Migrated:
Modal Header:
- Close button →
<BaseButton variant="ghost" size="xs" class="close-button">(×)
Command Editor:
- Edit command →
<BaseButton variant="outline" size="xs" class="edit-command-btn">(📝 Edit) - Save command →
<BaseButton variant="success" size="sm">(💾 Save) - Cancel command →
<BaseButton variant="secondary" size="sm">(❌ Cancel)
Step Management:
- Toggle steps manager →
<BaseButton variant="outline" size="sm">(▼ Hide / ▶ Show) - Move step up →
<BaseButton variant="outline" size="xs" :disabled="index === 0">(↑) - Move step down →
<BaseButton variant="outline" size="xs" :disabled="index === workflowSteps.length - 1">(↓) - Delete step →
<BaseButton variant="danger" size="xs" :disabled="workflowSteps.length <= 1">(🗑️) - Edit step →
<BaseButton variant="outline" size="xs">(✏️ Edit) - Insert step after →
<BaseButton variant="success" size="xs">(➕ Insert After) - Add new step →
<BaseButton variant="success" class="add-step-btn">(➕ Add New Step) - Add step (form) →
<BaseButton variant="success">(✅ Add Step) - Cancel add step →
<BaseButton variant="secondary">(❌ Cancel)
Edit Dialog:
- Close edit dialog →
<BaseButton variant="ghost" size="xs" class="close-button">(×) - Save edit →
<BaseButton variant="success" :disabled="!isEditFormValid || isSavingEdit" :loading="isSavingEdit">(💾 Save Changes) - Cancel edit →
<BaseButton variant="secondary" :disabled="isSavingEdit">(❌ Cancel)
Modal Actions (Primary):
- Execute step →
<BaseButton variant="success" :disabled="!currentStep" class="execute-btn">(✅ Execute This Step) - Skip step →
<BaseButton variant="secondary" class="skip-btn">(⏭️ Skip This Step) - Manual control →
<BaseButton variant="primary" class="manual-btn">(👤 Take Manual Control)
Modal Actions (Secondary):
- Execute all →
<BaseButton variant="info" class="execute-all-btn">(🚀 Execute All Remaining) - Save workflow →
<BaseButton variant="success" class="save-workflow-btn">(💾 Save Workflow) - Toggle advanced →
<BaseButton variant="secondary" class="toggle-advanced-btn">(⚙️ Hide/Show Advanced)
Key Patterns:
- ✅ Complex conditional :disabled logic for step management controls
- ✅ Loading state integration with form validation (saveEdit)
- ✅ Ghost variant for minimal close buttons
- ✅ Size xs for compact step control buttons
- ✅ Dynamic variant mapping (success for execute, info for batch operations)
- ✅ Preserved custom classes for layout-specific styling (add-step-btn, execute-btn)
CSS Removed: ~170 lines removed from scoped styles:
.close-button,.edit-command-btn(~13 lines).toggle-btn(~12 lines).step-control,.step-control:hover,.step-control:disabled,.step-control.delete(~28 lines).edit-step-btn,.insert-step-btn(~14 lines).add-step-btn(~13 lines).execute-btn,.skip-btn,.manual-btn,.execute-all-btn,.save-workflow-btn,.save-btn,.cancel-btn(~93 lines including hover/disabled states).toggle-advanced-btn(~14 lines)- Media query references removed (~35 lines across 3 breakpoints)
Batch 27 Summary:
- Components: 1 (AdvancedStepConfirmationModal)
- Buttons: 17 consolidated (1 modal header + 3 command editor + 9 step management + 3 edit dialog + 6 modal actions)
- Lines: ~170 saved
- Variants: 7 (primary, secondary, success, danger, info, outline, ghost)
- Combined Total: 16 components, ~979 lines saved, 111 buttons consolidated
Goal: Migrate chat input interface with file attachments, voice input, emoji picker, and quick actions to BaseButton.
Components Migrated: 1 component, 10 buttons, ~65 lines saved
Purpose: Comprehensive chat input interface with file uploads, voice input, emoji picker, and quick action shortcuts.
Buttons Migrated:
File Management:
- Retry upload →
<BaseButton variant="danger" size="xs" class="retry-upload-btn">(per upload item) - Clear all files →
<BaseButton variant="ghost" size="sm" class="text-red-600">(Clear all) - Remove file →
<BaseButton variant="ghost" size="xs" class="remove-file-btn">(per attached file)
Input Actions:
- Attach file →
<BaseButton variant="ghost" size="xs" class="action-btn" :disabled="isDisabled">(📎) - Voice input →
<BaseButton variant="ghost" size="xs" class="action-btn" :class="{ 'active': isVoiceRecording }" :disabled="isDisabled">(🎤) - Emoji picker →
<BaseButton variant="ghost" size="xs" class="action-btn" :disabled="isDisabled">(😊)
Quick Actions (4 buttons in v-for):
- Help/Summarize/Translate/Explain →
<BaseButton variant="ghost" size="sm" class="action-btn quick-action-btn" :disabled="isDisabled">(dynamic actions)
Main Actions:
- Send message →
<BaseButton variant="primary" class="send-button" :disabled="!canSend" :loading="isSending" :class="{ 'pulse': messageQueueLength > 0 }">(✈️ )
Emoji Picker:
- Close emoji picker →
<BaseButton variant="ghost" size="xs" class="close-emoji-btn">(×) - Emoji buttons (12 in v-for) →
<BaseButton variant="ghost" size="sm" class="emoji-btn">(😀)
Key Patterns:
- ✅ Loading state integration for send button (
:loadingprop) - ✅ Conditional :disabled for all input actions
- ✅ Active state preservation via :class for voice recording
- ✅ Ghost variant for minimal UI controls
- ✅ Queue indicator preserved in send button content
- ✅ Size xs for compact action buttons
- ✅ Custom classes preserved for layout (action-btn, send-button)
CSS Removed: ~65 lines removed from scoped styles:
.retry-upload-btn(~3 lines).remove-file-btn(~3 lines).action-btn,.action-btn:not(.quick-action-btn),.action-btn.active,.action-btn:disabled(~14 lines).quick-action-btn(~4 lines).send-button,.send-button.sending(~10 lines) - kept sizing and pulse animation.close-emoji-btn(~3 lines).emoji-btn(~3 lines)- Focus states:
.action-btn:focus,.quick-action-btn:focus,.emoji-btn:focus,.send-button:focus(~8 lines) - Remaining: action-label, send-button sizing/animation (preserved for layout)
Batch 28 Summary:
- Components: 1 (ChatInput)
- Buttons: 10 consolidated (3 file management + 3 input actions + 4 quick actions + 1 send + 2 emoji picker)
- Lines: ~65 saved
- Variants: 3 (primary, danger, ghost)
- Combined Total: 17 components, ~1,044 lines saved, 121 buttons consolidated
Goal: Migrate knowledge base file browser with category filters, search, batch operations, and file viewer to BaseButton.
Components Migrated: 1 component, 9 buttons, ~156 lines saved
Purpose: Comprehensive knowledge base file browser with category navigation, search, batch vectorization, and file viewer.
Buttons Migrated:
Category Management:
- Populate button (v-for per category) →
<BaseButton variant="primary" size="sm" :loading="populationStates[mainCat.id]?.isPopulating" :disabled="populationStates[mainCat.id]?.isPopulating" class="populate-btn">(Populate knowledge)
Category Filters (v-for pattern):
- Category tabs →
<BaseButton :variant="selectedCategory === cat.value ? 'primary' : 'outline'" size="sm" class="category-tab">(Filter by category)
Search Controls:
- Clear search →
<BaseButton variant="ghost" size="xs" class="clear-btn">(×)
Batch Operations Toolbar:
- Vectorize selected →
<BaseButton variant="primary" :disabled="!canVectorizeSelection || isVectorizing" :loading="isVectorizing" class="toolbar-btn vectorize">(Batch vectorize) - Clear selection →
<BaseButton variant="secondary" class="toolbar-btn cancel">(Clear batch selection)
Navigation:
- Breadcrumb root →
<BaseButton variant="ghost" size="sm" class="breadcrumb-item">(🏠 Root)
Error Handling:
- Retry load →
<BaseButton variant="primary" class="retry-btn">(🔄 Retry)
Pagination:
- Load more →
<BaseButton variant="primary" class="load-more-btn">(Load More)
File Viewer:
- Close viewer →
<BaseButton variant="ghost" size="sm" class="close-btn">(×)
Key Patterns:
- ✅ Loading state integration for populate and vectorize buttons (
:loadingprop) - ✅ Dynamic variant switching for category tabs (primary when active, outline when inactive)
- ✅ Conditional :disabled for batch operations
- ✅ Ghost variant for minimal UI controls (clear, breadcrumb, close)
- ✅ v-for pattern with computed variant logic
- ✅ Progress percentage display in button content during population
- ✅ Size xs for compact control buttons
- ✅ Custom classes preserved for toolbar styling
CSS Removed: ~156 lines removed from scoped styles:
.populate-btn(~32 lines) - kept spacing only.category-taband active/hover states (~27 lines) - kept layout.clear-btn(~10 lines) - kept positioning.toolbar-btnvariants (vectorize/cancel) (~27 lines) - kept custom colors.breadcrumb-itembutton styles (~18 lines) - removed all.retry-btn(~13 lines) - kept spacing only.load-more-btn(~18 lines) - kept container only.close-btn(~11 lines) - kept sizing only
Batch 29 Summary:
- Components: 1 (KnowledgeBrowser)
- Buttons: 9 consolidated (1 populate + category tabs + 1 search + 2 toolbar + 1 breadcrumb + 1 retry + 1 load-more + 1 close)
- Lines: ~156 saved
- Variants: 4 (primary, secondary, outline, ghost)
- Combined Total: 18 components, ~1,200 lines saved, 130 buttons consolidated
Goal: Migrate knowledge base administrative management interface with population and database management actions to BaseButton.
Components Migrated: 1 component, 5 buttons, ~61 lines saved
Purpose: Administrative knowledge management interface for populating and managing the knowledge base.
Buttons Migrated:
Knowledge Population Actions (3 buttons):
- Populate AutoBot Documentation →
<BaseButton variant="primary" :disabled="isPopulating" :loading="populateStatus.autobotDocs === 'loading'" class="action-btn">(~30 documents) - Populate System Commands →
<BaseButton variant="primary" :disabled="isPopulating" :loading="populateStatus.systemCommands === 'loading'" class="action-btn">(~150 commands) - Populate Manual Pages →
<BaseButton variant="primary" :disabled="isPopulating" :loading="populateStatus.manPages === 'loading'" class="action-btn">(~50 man pages)
Database Management:
- Clear All Knowledge →
<BaseButton variant="danger" :disabled="isClearing || isPopulating" :loading="isClearing" class="action-btn">(Destructive action)
Status Messages:
- Dismiss message →
<BaseButton variant="ghost" size="xs" class="dismiss-btn">(×)
Key Patterns:
- ✅ Loading state integration for async operations (
:loadingprop replaces manual spinner) - ✅ Conditional icon display (hide icon during loading, BaseButton shows spinner)
- ✅ Multiple disabled conditions (isPopulating, isClearing)
- ✅ Danger variant for destructive actions
- ✅ Ghost variant for minimal dismiss buttons
- ✅ Status tracking with computed button text
- ✅ Full width layout for action buttons
CSS Removed: ~61 lines removed from scoped styles:
.action-btnbase styles (~14 lines) - kept width: 100% only.action-btn:disabled(~4 lines).action-btn.primary(~8 lines).action-btn.danger(~8 lines).dismiss-btn(~17 lines) - kept positioning only- Hover states and transitions (~10 lines)
Goal: Migrate failed vectorization jobs management interface with retry and cleanup actions to BaseButton.
Components Migrated: 1 component, 4 buttons, ~58 lines saved
Purpose: Failed vectorization jobs manager with per-job retry and cleanup functionality.
Buttons Migrated:
Header Actions (2 buttons):
- Refresh →
<BaseButton variant="primary" size="sm" :disabled="loading" :loading="loading" class="btn-refresh">(Sync alt icon) - Clear All →
<BaseButton variant="danger" size="sm" v-if="failedJobs.length > 0" :disabled="loading" class="btn-clear-all">(Trash alt icon)
Per-Job Actions (v-for, 2 buttons per job):
- Retry →
<BaseButton variant="success" size="sm" :disabled="loading || retryingJobs.has(job.job_id)" :loading="retryingJobs.has(job.job_id)" class="btn-retry">(Redo icon) - Delete →
<BaseButton variant="secondary" size="sm" :disabled="loading" class="btn-delete">(Trash icon)
Key Patterns:
- ✅ Per-item loading states in v-for - Using
Set<string>for tracking individual job retry states - ✅ Conditional loading prop with per-item check:
:loading="retryingJobs.has(job.job_id)" - ✅ Conditional icon display with Set check:
v-if="!retryingJobs.has(job.job_id)" - ✅ Multiple disabled conditions (global loading + per-item retrying)
- ✅ Success variant for positive actions (retry)
- ✅ Danger variant for destructive bulk actions (clear all)
- ✅ Secondary variant for per-item delete (less prominent than bulk clear)
- ✅ Conditional rendering for bulk actions (
v-if="failedJobs.length > 0")
CSS Removed: ~58 lines removed from scoped styles:
.btn-refreshbase styles (~10 lines).btn-clear-allbase styles (~10 lines).btn-retrybase styles + success variant (~14 lines).btn-deletebase styles + secondary variant (~14 lines)- Hover states and transitions (~10 lines)
Batch 30 Summary:
- Components: 1 (KnowledgeAdvanced)
- Buttons: 5 consolidated (3 populate actions + 1 clear + 1 dismiss)
- Lines: ~61 saved
- Variants: 3 (primary, danger, ghost)
Batch 31 Summary:
- Components: 1 (FailedVectorizationsManager)
- Buttons: 4 consolidated (2 header actions + 2 per-job actions)
- Lines: ~58 saved
- Variants: 4 (primary, danger, success, secondary)
Goal: Migrate file browser list table with per-row action buttons to BaseButton.
Components Migrated: 1 component, 4 buttons, ~24 lines saved
Purpose: File browser list table with per-row file/directory actions (view, open, rename, delete).
Buttons Migrated (v-for per file/directory):
Conditional File Actions:
- View file →
<BaseButton variant="ghost" size="sm" v-if="!file.is_dir" class="action-btn view-btn">(Eye icon) - Open directory →
<BaseButton variant="ghost" size="sm" v-if="file.is_dir" class="action-btn open-btn">(Folder open icon)
Universal Actions:
- Rename →
<BaseButton variant="ghost" size="sm" class="action-btn rename-btn">(Edit icon) - Delete →
<BaseButton variant="ghost" size="sm" class="action-btn delete-btn">(Trash icon)
Key Patterns:
- ✅ Ghost variant for minimal icon-only action buttons
- ✅ Conditional rendering in v-for (view vs open based on file.is_dir)
- ✅ Per-row actions in table cells
- ✅ Consistent size (sm) for compact table layout
- ✅ Preserved aria-label and title for accessibility
- ✅ Icon-only buttons with hover interactions handled by BaseButton
CSS Removed: ~24 lines removed from scoped styles:
.action-btnbase styles + hover states (~6 lines).view-btn:hovercolor override (~3 lines).open-btn:hovercolor override (~3 lines).rename-btn:hovercolor override (~3 lines).delete-btn:hovercolor override (~3 lines)- Tailwind utility classes for sizing, spacing, colors (~6 lines)
Batch 32 Summary:
- Components: 1 (FileListTable)
- Buttons: 4 consolidated (2 conditional + 2 universal per-row actions)
- Lines: ~24 saved
- Variants: 1 (ghost for minimal action buttons)
Goal: Migrate file browser header navigation and action buttons to BaseButton.
Components Migrated: 1 component, 3 buttons, ~19 lines saved
Purpose: File browser header with path navigation and file management actions.
Buttons Migrated:
Path Navigation:
- Path go button →
<BaseButton variant="primary" size="sm" class="path-go-btn">(Arrow right icon, navigate to entered path)
File Actions:
- New Folder →
<BaseButton variant="outline" size="sm" aria-label="Create new folder">(Folder plus icon + text) - Upload File →
<BaseButton variant="outline" size="sm" aria-label="Upload file">(Upload icon + text)
Key Patterns:
- ✅ Primary variant for main path navigation action (blue background)
- ✅ Outline variant for secondary file actions (white background with border)
- ✅ Consistent sm size for compact header layout
- ✅ Icon + text combination for clear action labels
- ✅ Preserved aria-label attributes for accessibility
- ✅ Maintained path input integration with Enter key handler
CSS Removed: ~19 lines removed from scoped styles:
.path-go-btnTailwind classes (~3 lines).file-actions buttonbase styles (~3 lines).file-actions button:hoverhover state (~3 lines).file-actions button iicon styles (~3 lines)- Padding, colors, borders, focus states (~7 lines)
Batch 33 Summary:
- Components: 1 (FileBrowserHeader)
- Buttons: 3 consolidated (1 navigation + 2 file actions)
- Lines: ~19 saved
- Variants: 2 (primary for navigation, outline for actions)
Goal: Migrate knowledge base deduplication and orphan management interface to BaseButton.
Components Migrated: 1 component, 3 buttons, ~50 lines saved
Purpose: Knowledge base maintenance tool for scanning and removing duplicate and orphaned documents.
Buttons Migrated:
Scan Action:
- Scan for Issues →
<BaseButton variant="primary" size="sm" :disabled="scanning" :loading="scanning">(Search icon)
Cleanup Actions:
- Remove All Duplicates →
<BaseButton variant="warning" :disabled="cleaning" :loading="cleaning">(Trash icon, warning variant for caution) - Remove All Orphans →
<BaseButton variant="danger" :disabled="cleaning" :loading="cleaning">(Trash icon, danger variant for destructive action)
Key Patterns:
- ✅ Loading state integration (
:loadingprop replaces manual spinner conditionals) - ✅ Conditional icon display (
v-if="!loading"to hide icon during loading) - ✅ Dynamic button text based on state (scanning/cleaning vs idle)
- ✅ Warning variant for potentially destructive batch operations (duplicates)
- ✅ Danger variant for irreversible operations (orphans)
- ✅ Primary variant for main scan action
- ✅ Shared cleaning state for both cleanup actions
CSS Removed: ~50 lines removed from scoped styles:
.btn-scanbase styles + hover + disabled (~18 lines).btn-cleanupbase styles + disabled (~14 lines).btn-warningvariant + hover (~6 lines).btn-dangervariant + hover (~6 lines)- Flex, padding, colors, transitions (~6 lines)
Batch 34 Summary:
- Components: 1 (DeduplicationManager)
- Buttons: 3 consolidated (1 scan + 2 cleanup actions)
- Lines: ~50 saved
- Variants: 3 (primary, warning, danger)
- Combined Total: 23 components, ~1,412 lines saved, 149 buttons consolidated
Goal: Migrate comprehensive chat message display with inline actions, command approvals, and message editing modals to BaseButton.
Components Migrated: 1 component, 10 buttons, ~60 lines saved
Purpose: Main chat message display with inline message actions, command approval workflow, comment system, and message editing capabilities.
Buttons Migrated:
Message Actions (Inline per message):
- Edit message →
<BaseButton variant="ghost" size="xs" v-if="message.sender === 'user'" class="action-btn">(conditional on user messages) - Copy message →
<BaseButton variant="ghost" size="xs" class="action-btn">(universal action) - Delete message →
<BaseButton variant="ghost" size="xs" class="action-btn danger">(universal action)
Comment Actions:
- Cancel comment →
<BaseButton variant="secondary" size="sm" class="cancel-comment-btn">(Cancel) - Submit approval →
<BaseButton variant="primary" size="sm" :disabled="!approvalComment.trim()" class="submit-comment-btn">(Submit Approval/Denial)
Approval Actions (Command approval workflow):
- Approve command →
<BaseButton variant="success" size="sm" :disabled="processingApproval || showCommentInput" class="approve-btn">(Approve) - Add comment →
<BaseButton variant="outline" size="sm" :disabled="processingApproval || showCommentInput" class="comment-btn">(Comment) - Deny command →
<BaseButton variant="danger" size="sm" :disabled="processingApproval || showCommentInput" class="deny-btn">(Deny)
Edit Modal Actions:
- Cancel edit →
<BaseButton variant="secondary" @click="cancelEdit">(Cancel) - Save edit →
<BaseButton variant="primary" @click="saveEditedMessage" :disabled="!editingContent.trim()">(Save)
Key Patterns:
- ✅ Ghost variant with xs size for minimal inline message actions (edit, copy, delete)
- ✅ Conditional rendering for user-only actions (edit message)
- ✅ Success/danger variants for approval workflow (approve = green, deny = red)
- ✅ Outline variant for neutral actions (comment)
- ✅ Disabled state management with complex conditions (processingApproval || showCommentInput)
- ✅ Form validation in disabled state (!approvalComment.trim(), !editingContent.trim())
- ✅ Secondary variant for cancel actions in modals and forms
- ✅ Primary variant for main submit actions
- ✅ Preserved custom classes for layout-specific styling
CSS Removed: ~60 lines removed from scoped styles:
.action-btnbase and color overrides for user/assistant messages (~17 lines).action-btn.danger:hover(~3 lines).approve-btn,.deny-btnbase styles and variants (~12 lines).cancel-comment-btn,.submit-comment-btn,.comment-btn(~12 lines)- Responsive overrides for
.action-btn,.approve-btn,.deny-btn(~12 lines) - Remaining: Layout containers (
.message-actions,.approval-actions,.comment-actions) preserved for flex layouts
Batch 35 Summary:
- Components: 1 (ChatMessages)
- Buttons: 10 consolidated (3 inline message actions + 2 comment actions + 3 approval workflow + 2 edit modal)
- Lines: ~60 saved
- Variants: 6 (primary, secondary, success, danger, outline, ghost)
- Combined Total: 24 components, ~1,472 lines saved, 159 buttons consolidated
Goal: Migrate comprehensive knowledge entry management interface with tabs, filters, bulk actions, per-entry actions, pagination, and edit dialog to BaseButton.
Components Migrated: 1 component, 15 buttons, ~90 lines saved
Purpose: Main knowledge entry management interface with upload/manage/advanced tabs, bulk operations, filtering, per-entry actions, pagination, and full-featured edit dialog.
Buttons Migrated:
Tab Navigation (3 buttons):
- Upload tab →
<BaseButton variant="ghost" :class="['manage-tab-btn', { active: manageTab === 'upload' }]">(Upload) - Manage tab →
<BaseButton variant="ghost" :class="['manage-tab-btn', { active: manageTab === 'manage' }]">(Manage) - Advanced tab →
<BaseButton variant="ghost" :class="['manage-tab-btn', { active: manageTab === 'advanced' }]">(Advanced)
Bulk Actions (2 buttons):
- Export selected →
<BaseButton variant="primary" size="sm" :disabled="selectedEntries.length === 0">(Export (N)) - Delete selected →
<BaseButton variant="danger" size="sm" :disabled="selectedEntries.length === 0">(Delete (N))
Filter Actions (1 button):
- Clear filters →
<BaseButton variant="secondary" size="sm" class="clear-filters-btn">(Clear Filters)
Per-Entry Actions in Table (3 buttons per entry in v-for):
- View entry →
<BaseButton variant="ghost" size="xs" class="icon-btn">(eye icon) - Edit entry →
<BaseButton variant="ghost" size="xs" class="icon-btn">(edit icon) - Delete entry →
<BaseButton variant="ghost" size="xs" class="icon-btn danger">(trash icon)
Pagination (2 buttons):
- Previous page →
<BaseButton variant="outline" size="sm" :disabled="currentPage === 1">(chevron-left) - Next page →
<BaseButton variant="outline" size="sm" :disabled="currentPage === totalPages">(chevron-right)
Dialog Actions (4 buttons):
- Close dialog →
<BaseButton variant="ghost" size="sm" class="close-btn">(× icon) - Edit button (view mode) →
<BaseButton variant="primary" v-if="dialogMode === 'view'">(Edit) - Cancel edit →
<BaseButton variant="secondary" v-if="dialogMode === 'edit'">(Cancel) - Save changes →
<BaseButton variant="primary" v-if="dialogMode === 'edit'">(Save Changes)
Key Patterns:
- ✅ Ghost variant for minimal tab navigation with .active class preserved
- ✅ Primary/danger variants for bulk actions with dynamic count display
- ✅ Ghost variant with xs size for compact table icon buttons
- ✅ Outline variant for pagination controls
- ✅ Disabled state with selection count validation (selectedEntries.length === 0)
- ✅ Disabled state with boundary checks (currentPage === 1, currentPage === totalPages)
- ✅ Conditional rendering with v-if for dialog mode (view vs edit)
- ✅ Secondary variant for cancel actions
- ✅ Preserved custom classes for active state styling (.manage-tab-btn.active)
CSS Removed: ~90 lines removed from scoped styles:
.manage-tab-btnbase styles and hover (~13 lines) - kept .active class.action-btnbase, hover, danger, disabled states (~27 lines).clear-filters-btnbase and hover (~14 lines).icon-btnbase, hover, danger hover (~23 lines).page-btnbase, hover, disabled states (~22 lines).close-btnbase and hover (~17 lines).edit-btn,.cancel-btn,.save-btnshared and individual styles (~40 lines)- Remaining: Layout containers (.manage-tabs, .pagination, .dialog-actions) and .active state preserved
Batch 36 Summary:
- Components: 1 (KnowledgeEntries)
- Buttons: 15 consolidated (3 tabs + 2 bulk actions + 1 filter + 3 per-entry actions + 2 pagination + 4 dialog)
- Lines: ~90 saved
- Variants: 5 (primary, secondary, danger, outline, ghost)
- Combined Total: 25 components, ~1,562 lines saved, 174 buttons consolidated
Goal: Migrate main knowledge category browsing interface with category navigation, management actions, document viewing, and modal forms to BaseButton.
Components Migrated: 1 component, 8 buttons, ~65 lines saved
Purpose: Main knowledge category browsing interface with main category selection, legacy user category management, and document panel.
Buttons Migrated:
Navigation (1 button):
- Back to categories →
<BaseButton variant="outline" class="back-btn">(Back to Categories)
Category Management (2 buttons):
- Create category →
<BaseButton variant="primary" size="sm" class="create-category-btn">(New Category)
Per-Category Actions (2 buttons per category with @click.stop):
- Edit category →
<BaseButton variant="ghost" size="xs" @click.stop="editCategory(category)">(edit icon) - Delete category →
<BaseButton variant="ghost" size="xs" @click.stop="deleteCategory(category)" class="action-btn danger">(trash icon)
Document Actions (1 button):
- View documents →
<BaseButton variant="outline" size="sm" @click.stop="viewDocuments(category)">(View Documents)
Dialog Actions (2 buttons with form validation):
- Cancel →
<BaseButton variant="secondary" @click="closeDialogs">(Cancel) - Save/Update →
<BaseButton variant="primary" :disabled="!categoryForm.name.trim()">(Create/Update - dynamic text)
Panel Actions (1 button):
- Close panel →
<BaseButton variant="ghost" size="sm" class="close-panel-btn">(× icon)
Key Patterns:
- ✅ Outline variant for navigation and view actions
- ✅ Primary variant for create action with sm size
- ✅ Ghost variant with xs size for compact per-category icon buttons
- ✅ Event propagation control with @click.stop on nested clickable elements
- ✅ Form validation with disabled state (!categoryForm.name.trim())
- ✅ Dynamic button text based on dialog mode (showEditDialog ? 'Update' : 'Create')
- ✅ Secondary variant for cancel actions
- ✅ Preserved category card click handlers while allowing independent action buttons
CSS Removed: ~65 lines removed from scoped styles:
.back-btnbase styles and hover (~18 lines).create-category-btnbase and hover (~17 lines).action-btnbase, hover, danger states (~23 lines).view-docs-btnbase and hover (~16 lines).cancel-btn,.save-btnshared and individual styles (~32 lines).close-panel-btnbase and hover (~17 lines)- Remaining: Layout containers (.category-grid, .category-card, .panel-header) and card selection state preserved
Batch 37 Summary:
- Components: 1 (KnowledgeCategories)
- Buttons: 8 consolidated (1 navigation + 1 create + 2 per-category actions + 1 view + 2 dialog + 1 panel)
- Lines: ~65 saved
- Variants: 4 (primary, secondary, outline, ghost)
- Combined Total: 26 components, ~1,627 lines saved, 182 buttons consolidated
Goal: Migrate comprehensive knowledge management decision dialog with bulk actions, compile functionality, and decision tracking to BaseButton.
Components Migrated: 1 component, 9 buttons, ~85 lines saved
Purpose: Comprehensive knowledge management dialog for reviewing, categorizing, and persisting chat knowledge items with bulk operations and compile functionality.
Buttons Migrated:
Header (1 button):
- Close dialog →
<BaseButton variant="ghost" size="sm" class="close-button">(× icon)
Bulk Actions (5 buttons with selection validation):
- Select all →
<BaseButton variant="outline" class="bulk-button">(✅ Select All) - Deselect all →
<BaseButton variant="outline" class="bulk-button">(❌ Deselect All) - Add to KB →
<BaseButton variant="success" :disabled="!hasSelectedItems" class="bulk-button add">(💾 Add Selected to KB) - Keep temporary →
<BaseButton variant="warning" :disabled="!hasSelectedItems" class="bulk-button temp">(⏰ Keep Selected Temporarily) - Delete →
<BaseButton variant="danger" :disabled="!hasSelectedItems" class="bulk-button delete">(🗑️ Delete Selected)
Compile Section (1 button):
- Compile chat →
<BaseButton variant="primary" class="compile-button">(📚 Compile Chat to Knowledge Base)
Dialog Actions (2 buttons):
- Apply decisions →
<BaseButton variant="success" :disabled="!hasDecisions" class="primary-button">(✅ Apply Decisions) - Cancel →
<BaseButton variant="secondary" class="secondary-button">(❌ Cancel)
Key Patterns:
- ✅ Ghost variant with sm size for minimal header close button
- ✅ Outline variant for selection control actions
- ✅ Success/warning/danger variants for categorized bulk actions
- ✅ Disabled state with computed property validation (hasSelectedItems, hasDecisions)
- ✅ Primary variant for major action (compile chat)
- ✅ Success variant for primary dialog action with disabled state
- ✅ Secondary variant for cancel action
- ✅ Consistent emoji icons preserved in button text
CSS Removed: ~85 lines removed from scoped styles:
.close-buttonbase and hover (~13 lines).bulk-buttonbase, hover, disabled, and variant-specific styles (.add, .temp, .delete) (~34 lines).compile-buttonbase and hover (~14 lines).primary-buttonbase, hover, disabled (~18 lines).secondary-buttonbase and hover (~6 lines)- Responsive media query button styles removed
- Remaining: Layout containers (.bulk-buttons, .action-buttons) and summary items preserved
Batch 38 Summary:
- Components: 1 (KnowledgePersistenceDialog)
- Buttons: 9 consolidated (1 close + 5 bulk actions + 1 compile + 2 dialog actions)
- Lines: ~85 saved
- Variants: 6 (primary, secondary, success, warning, danger, outline, ghost)
- Combined Total: 27 components, ~1,712 lines saved, 191 buttons consolidated
Goal: Migrate system phase validation and progression controls with status monitoring, validation triggers, and auto-progression to BaseButton.
Components Migrated: 1 component, 6 buttons, ~70 lines saved
Purpose: System phase status monitoring with on-demand validation, manual progression triggers, and auto-progression controls.
Buttons Migrated:
Header Controls (1 button):
- Load validation data →
<BaseButton variant="outline" :disabled="loading" class="load-validation-btn">(Load Validation Data)
Error State (1 button):
- Retry load →
<BaseButton variant="warning" class="retry-button">(Retry)
Per-Phase Actions (2 buttons per phase):
- Progress phase →
<BaseButton variant="primary" size="sm" :disabled="progressionInProgress" class="btn-progression">(Progress) - Validate phase →
<BaseButton variant="success" size="sm" :disabled="validationInProgress" class="btn-validate">(Validate)
Auto-Progression Controls (2 buttons):
- Run full validation →
<BaseButton variant="primary" :disabled="validationInProgress" class="btn-full-validation">(Run Full System Validation) - Trigger auto-progression →
<BaseButton variant="success" :disabled="progressionInProgress || !autoProgressionEnabled" class="btn-auto-progression">(Trigger Auto-Progression)
Key Patterns:
- ✅ Outline variant for header control action
- ✅ Warning variant for error state retry action
- ✅ Primary/success variants with sm size for per-phase actions
- ✅ Disabled states with loading/progress flags (loading, progressionInProgress, validationInProgress)
- ✅ Disabled state with conditional logic (!autoProgressionEnabled)
- ✅ Dynamic button text with loading state (loading ? 'Loading...' : 'Load Validation Data')
- ✅ Spinner icons for loading states (fa-spinner fa-spin)
CSS Removed: ~70 lines removed from scoped styles:
.load-validation-btnbase, hover, disabled (~23 lines).retry-buttonbase, hover, icon styles (~20 lines).btn-progression,.btn-validateshared and individual styles (~17 lines).btn-full-validation,.btn-auto-progressionshared and individual styles (~30 lines)- Remaining: Layout containers (.header-controls, .phase-actions, .controls-grid) preserved
Batch 39 Summary:
- Components: 1 (PhaseProgressionIndicator)
- Buttons: 6 consolidated (1 header + 1 retry + 2 per-phase actions + 2 auto-progression controls)
- Lines: ~70 saved
- Variants: 4 (primary, success, warning, outline)
- Combined Total: 28 components, ~1,782 lines saved, 197 buttons consolidated
Goal: Migrate system status monitoring indicator with notification management, status details, and quick actions to BaseButton.
Components Migrated: 1 component, 5 buttons, ~35 lines saved
Purpose: Fixed system status indicator with dropdown details panel, notification list, and quick action controls.
Buttons Migrated:
Main Status Indicator (1 button):
- Status indicator →
<BaseButton variant="primary" :class="statusClasses" :title="getStatusDescription(indicator.status)">(System status with dynamic classes)
Details Panel Controls (2 buttons):
- Close details →
<BaseButton variant="ghost" size="sm" class="text-gray-400...">(Close) - Refresh status →
<BaseButton variant="primary" size="xs" class="px-3 py-1...">(Refresh)
Notification Actions (2 buttons):
- Clear all notifications →
<BaseButton variant="danger" size="xs" v-if="activeNotificationCount > 0" class="px-3 py-1...">(Clear All) - Hide notification →
<BaseButton variant="ghost" size="xs" class="ml-2 p-1">(Per-notification hide, v-for)
Key Patterns:
- ✅ Primary variant for main status indicator with preserved dynamic class bindings (statusClasses computed property)
- ✅ Ghost variant with sm/xs sizes for minimal close/hide buttons
- ✅ Primary/danger variants with xs size for quick actions
- ✅ Conditional rendering with notification count (v-if="activeNotificationCount > 0")
- ✅ Per-notification actions in v-for loop
- ✅ Preserved complex status-based styling (bg-green/yellow/red/gray with animate-pulse)
- ✅ Teleport integration with dropdown details panel
- ✅ Icon components (Heroicons) with dynamic rendering
CSS Impact: ~35 lines saved from cleaner template code (no button-specific CSS in this component - uses custom animations and scrollbar styles for other UI elements).
Batch 40 Summary:
- Components: 1 (SystemStatusIndicator)
- Buttons: 5 consolidated (1 main status + 1 close + 2 quick actions + 1 per-notification hide)
- Lines: ~35 saved
- Variants: 3 (primary, ghost, danger)
- Combined Total: 29 components, ~1,817 lines saved, 202 buttons consolidated
Goal: Create reusable BaseAlert component to consolidate inline alert patterns and migrate first component.
New Component: BaseAlert.vue (autobot-frontend/src/components/ui/BaseAlert.vue)
Superseded (#18819): this component, and
components/base/ErrorBanner.vue, are consolidated into the shared kit'sBaseAlert(libs/autobot-ui/src/components/BaseAlert.vue,import { BaseAlert } from '@autobot/ui'), used by both apps. The local files are gone.
Features:
- 5 variants: success, info, warning, error, critical
- Icon support with Heroicons (CheckCircleIcon, InformationCircleIcon, ExclamationTriangleIcon, XCircleIcon)
- Optional title and message props
- Slots: default (message), icon, actions
- Dismissible with optional auto-dismiss timer (milliseconds)
- Bordered variant with left accent border (4px)
- Dark mode support with adjusted colors
- TypeScript interface for props
- Accessible with role="alert"
- Emits dismiss event
First Migration: LoginForm.vue (2 alerts, ~22 lines saved)
- Replaced error-alert div with BaseAlert variant="error"
- Replaced warning-alert div with BaseAlert variant="warning"
- Removed error-alert/warning-alert CSS (~18 lines)
- Removed icon CSS (~2 lines: icon-alert-circle, icon-lock)
Component: KnowledgeUpload.vue (2 alerts, ~18 lines saved)
Alerts Migrated:
- Success message → BaseAlert variant="success"
- Error message → BaseAlert variant="error"
Changes:
- Added BaseAlert import
- Replaced alert divs with BaseAlert components
- Removed alert CSS (~15 lines: .alert + .alert-success + .alert-error)
- Removed FontAwesome icon markup (CheckCircle, ExclamationCircle)
Component: NPUWorkersSettings.vue (1 alert, ~14 lines saved)
Alert Migrated:
- Worker form error → BaseAlert variant="error"
Changes:
- Added BaseAlert import
- Replaced error-alert div with BaseAlert component
- Removed error-alert CSS (~14 lines: base class + icon styles)
- Replaced FontAwesome with Heroicons automatically
Component: ValidationDashboard.vue (alerts list, ~40 lines saved)
Alerts Migrated:
- Alert list with v-for loop (critical/warning/info variants)
- Dynamic variant binding based on alert.level
- Title and message props from alert data
- Timestamp in actions slot
Changes:
- Added BaseAlert import and component registration
- Replaced v-for div with BaseAlert v-for loop
- Used bordered prop for left accent border
- Moved timestamp to actions slot for right-aligned display
- Removed alert CSS (~40 lines: .alert, .alert-critical, .alert-warning, .alert-info, .alert-title)
- Added .alerts-list CSS for flex gap spacing
Key Patterns:
- Dynamic variant binding:
:variant="alert.level" - Title/message props from data
- Actions slot for timestamp display
- V-for rendering with BaseAlert
Component: MonitoringDashboard.vue (alert banner, ~17 lines saved)
Alert Migrated:
- Critical alert banner with dynamic count message
- BaseButton in actions slot for "View Details"
Changes:
- Added BaseAlert import and component registration
- Replaced alert-banner div with BaseAlert variant="critical"
- Dynamic message with template literal for alert count
- BaseButton placed in actions slot
- Removed alert-banner CSS (~17 lines: base class + critical variant)
Note: Alert items list in modal not migrated - uses custom structure with StatusBadge, specific header layout, and recommendation section that doesn't fit BaseAlert pattern.
Component: ResearchBrowser.vue (interaction alert, ~10 lines saved)
Alert Migrated:
- Interaction required warning with action buttons
- Warning variant for user attention
- Two BaseButtons in actions slot (Wait, Open Browser)
Changes:
- Added BaseAlert import and component registration
- Replaced interaction-alert div with BaseAlert variant="warning"
- Used bordered prop for left accent border
- Actions slot contains flex container with two buttons
- Removed inline Tailwind classes (~10 lines of utility classes)
BaseAlert Migration Summary (Batches 41-46):
- Components Migrated: 6 components (LoginForm, KnowledgeUpload, NPUWorkersSettings, ValidationDashboard, MonitoringDashboard, ResearchBrowser)
- Alerts Consolidated: 10+ alerts
- Lines Saved: ~121 lines
- Target: ~50-100 lines estimated → 121 lines achieved ✅ TARGET EXCEEDED
- Variants Used: All 5 variants (success, info, warning, error, critical)
- Key Patterns: Simple messages, v-for loops, actions slot with buttons, dynamic variant binding, title + message structure
Goal: Migrate 4 terminal-related modals to BaseModal, consolidating duplicate overlay and modal structure code.
Component: TerminalModals.vue (963 → 781 lines, ~182 lines saved, 19% reduction)
Modals Migrated:
- Reconnect modal - Connection lost dialog (small size)
- Command confirmation modal - Destructive command warning with risk assessment (medium size)
- Emergency kill modal - Process termination warning (medium size, emergency styling)
- Legacy workflow modal - AI workflow step confirmation with 3 action buttons (large size)
Changes:
- Added BaseModal import and component usage
- Converted all 4 modals from inline overlay/modal divs to BaseModal with v-model
- Mapped size variants (small, medium, large) directly to BaseModal sizes
- Preserved all content-specific styling (command-preview, risk-assessment, workflow-options)
- Maintained BaseButton integration throughout all modal actions
- Implemented conditional closeOnOverlay based on loading states (isReconnecting, isExecutingCommand, isKillingProcesses, isProcessingWorkflow)
CSS Removed:
- Modal overlay structure (~10 lines)
- Confirmation modal overlay and structure (~30 lines)
- Modal header, title, and content structure (~20 lines)
- Modal actions footer structure (~10 lines)
- Duplicate mobile responsiveness rules (~30 lines)
- Total: ~100 lines of structure CSS
Patterns Preserved:
- Error/success message displays remain unchanged
- Risk assessment styling intact (risk-level variants: low/moderate/high/critical)
- Emergency warning styling preserved
- Workflow step counter and options styling maintained
- Loading states with disabled close-on-overlay during operations
Goal: Migrate document viewer modal to BaseModal.
Component: KnowledgeSearch.vue (741 → 686 lines, ~54 lines saved, 7% reduction)
Modal Migrated:
- Document viewer modal - Full document display with metadata and copy action (large size, scrollable)
Changes:
- Added BaseModal import
- Converted document-modal-overlay div to BaseModal with v-model bound to showDocumentModal
- Used large scrollable modal size for optimal document viewing
- Document metadata (type, category, updated date) moved into default slot
- Copy action and close buttons moved to actions slot
CSS Removed:
- document-modal-overlay and fadeIn animation (~15 lines)
- document-modal container and slideUp animation (~15 lines)
- document-modal-header structure (~10 lines)
- modal-close-button styling (~3 lines)
- document-modal-content wrapper (~3 lines)
- document-modal-footer structure (~8 lines)
- Total: ~54 lines
Content-Specific Styles Preserved:
- document-modal-meta display
- modal-meta-item styling
- modal-loading spinner
- document-text display
- modal-no-content empty state
- modal-action-button custom styling
Goal: Migrate all 3 secrets management modals to BaseModal.
Component: SecretsManager.vue (1103 → 1037 lines, ~65 lines saved, 6% reduction)
Modals Migrated:
- Create/Edit modal - Secret form for creating/updating secrets (medium size, form validation)
- View modal - Secret details display with show/hide value toggle (medium size)
- Transfer modal - Confirmation dialog for transferring secrets between scopes (medium size, checkbox confirmation)
Changes:
- Added BaseModal to component imports and registration
- Converted all 3 modal-overlay divs to BaseModal with v-model patterns
- Create/Edit: Combined showCreateModal || showEditModal into single v-model condition
- View: Bound v-model to showViewModal
- Transfer: Bound v-model to showTransferModal
- All form submissions and action buttons moved to actions slots
- Conditional closeOnOverlay for Create/Edit (!saving) and Transfer (!transferring) modals
CSS Removed:
- modal-overlay structure (~15 lines)
- modal container and sizing (~8 lines)
- modal-header with h3 and close button (~20 lines)
- btn-close button styling (~12 lines)
- modal-body padding (~3 lines)
- modal-actions footer structure (~7 lines)
- Total: ~65 lines
Features Preserved:
- Create/Edit modal: Form structure with required fields, validation, saving state
- View modal: Secret value show/hide toggle, metadata display, copy functionality
- Transfer modal: Confirmation checkbox, warning message, transferring state
- Custom button styling maintained (btn-primary, btn-secondary)
- Form groups and validation intact
- StatusBadge integration for scope and type badges
Goal: Migrate all 3 NPU worker management modals to BaseModal.
Component: NPUWorkersSettings.vue (1446 → 1359 lines, ~87 lines saved, 6% reduction)
Modals Migrated:
- Add/Edit Worker modal - Complex form with validation, BaseAlert integration (medium size)
- Delete Confirmation modal - Warning dialog with danger styling (small size)
- Worker Metrics modal - Performance metrics grid display (large size)
Changes:
- Added BaseModal import and component usage
- Add/Edit Worker: Conditional title (showEditWorkerDialog ? 'Edit' : 'Add'), form validation, operation locking
- Delete Confirmation: Custom title slot with red warning styling, conditional close during deletion
- Worker Metrics: Conditional rendering with v-if="selectedWorkerMetrics", metrics grid layout
- All modals use conditional closeOnOverlay based on operation states (isSavingWorker, isDeletingWorker, operationInProgress)
CSS Removed:
- .modal-overlay structure with inset positioning and backdrop (~10 lines)
- .modal-dialog + size variants (.modal-sm, .modal-lg) (~15 lines)
- .modal-header structure (~10 lines)
- .modal-title styling (~5 lines)
- .modal-close button (~10 lines)
- .modal-body scrollable container (~5 lines)
- .modal-footer actions container (~7 lines)
- Total: ~70 lines of structure CSS
Patterns Preserved:
- Form validation with isWorkerFormValid computed property
- Loading states with spinner icons
- Operation locking to prevent race conditions
- BaseAlert error display integration
- Custom title slots for icons and styling
- Metrics grid display for performance data
Goal: Migrate user authentication and profile management modals to BaseModal.
Component: UserManagementSettings.vue (662 → 589 lines, ~73 lines saved, 11% reduction)
Modals Migrated:
- Login modal - Simple wrapper around LoginForm component (medium size)
- Change Password modal - Password form with validation (medium size)
Changes:
- Added BaseModal import
- Removed teleport wrappers (BaseModal handles portal internally)
- Login: Clean integration with LoginForm, success/error callback handling
- Change Password: Three password fields (current, new, confirm), conditional closeOnOverlay during password change
- Actions moved to slots with proper button ordering (Cancel first, Action second)
CSS Removed:
- .modal-overlay structure (~12 lines)
- .modal-content container (~8 lines)
- .modal-header structure (~7 lines)
- .modal-header h3 styling (~4 lines)
- .close-btn button (~7 lines)
- .change-password-form padding wrapper (~3 lines)
- Dark theme modal overrides (content, header, h3) (~12 lines)
- Total: ~79 lines
Features Preserved:
- LoginForm component integration unchanged
- Password form validation (matching new/confirm passwords)
- Loading states with spinner icons
- Disabled button states during async operations
- Success/error callback handling (onLoginSuccess, onLoginError)
- User profile state management
Goal: Migrate performance monitoring alerts modal to BaseModal.
Component: MonitoringDashboard.vue (1386 → 1333 lines, ~53 lines saved, 4% reduction)
Modal Migrated:
- Performance Alerts modal - Scrollable list of performance alerts with severity badges (large, scrollable)
Changes:
- Added BaseModal import and component registration
- Converted modal-overlay to BaseModal with large scrollable size
- StatusBadge integration for severity display maintained
- Alert list with v-for iteration preserved
- Empty state for when no alerts present
CSS Removed:
- .modal-overlay structure (~12 lines)
- .modal-content container with max dimensions (~10 lines)
- .modal-header structure (~8 lines)
- .modal-header h5 styling (~4 lines)
- .btn-close button (~8 lines)
- .modal-body scrollable container (~6 lines)
- Total: ~57 lines
Patterns Preserved:
- StatusBadge integration with getSeverityVariant() mapping
- Alert severity classes (critical, warning)
- Timestamp formatting via formatTimestamp()
- Alert structure (header with badge/category/timestamp + message + recommendation)
- Empty state with check icon when no alerts
- Scrollable content for potentially long alert lists
Goal: Migrate large dual-mode knowledge entry modal to BaseModal.
Component: KnowledgeEntries.vue (1130 → 1068 lines, ~62 lines saved, 5.5% reduction)
Modal Migrated:
- View/Edit Dialog - Large scrollable modal with dual mode (view/edit) for knowledge entries
Changes:
- Added BaseModal import
- Converted dialog-overlay structure to BaseModal with large scrollable size
- Dynamic title based on dialogMode ('View Entry' vs 'Edit Entry')
- Conditional content rendering (view mode vs edit mode) in default slot
- Actions slot with mode-specific buttons (Edit in view, Cancel/Save in edit)
CSS Removed:
- .dialog-overlay fixed positioning and overlay (~18 lines)
- .dialog modal structure with max dimensions (~12 lines)
- .dialog.large size variant (~3 lines)
- .dialog-header with flex layout (~8 lines)
- .dialog-content padding wrapper (~4 lines)
- .dialog-actions footer with flex layout (~8 lines)
- Total: ~71 lines
Patterns Preserved:
- Entry metadata grid display with category badges
- Tags list with chip styling
- Content viewer with HTML rendering
- Edit form with category select, source input, tags input, content textarea
- Form validation and save/cancel actions
- Scrollable content for long knowledge entries
Goal: Migrate Redis service confirmation dialog to BaseModal.
Component: RedisServiceControl.vue (434 → 419 lines, ~15 lines saved, 3.5% reduction)
Modal Migrated:
- Confirmation Dialog - Medium modal for confirming service operations (restart/stop)
Changes:
- Added BaseModal import
- Converted fixed overlay structure to BaseModal with medium size
- Dynamic title from confirmDialog.title
- Message and warning sections in default slot
- Actions slot with Cancel and Confirm buttons
- Dynamic Confirm button variant (danger for stop, primary for restart)
Template Simplified:
- Removed fixed positioning overlay structure (~23 lines)
- Removed custom centering flex layout
- Removed custom modal card structure
- BaseModal handles all positioning and overlay
Patterns Preserved:
- Dynamic title based on operation type
- Message display with operation description
- Conditional warning section with yellow alert styling
- Dynamic button variants based on operation risk
- onConfirm callback pattern for action handling
Goal: Migrate chat message editing modal to BaseModal.
Component: ChatMessages.vue (1351 → 1351 lines, ~0 lines net, improved consistency)
Modal Migrated:
- Edit Message Modal - Medium modal for editing user messages in chat
Changes:
- Added BaseModal import
- Converted fixed overlay structure to BaseModal with medium size
- Textarea with keyboard shortcut support preserved
- Actions slot with Cancel and Save buttons
- Save button disabled validation maintained
Template Simplified:
- Removed fixed positioning overlay structure
- Removed custom centering flex layout
- Removed custom modal card structure
- BaseModal handles all positioning and overlay
- Note: Slight net increase due to BaseModal import + slot structure, but gained consistency and maintainability
Patterns Preserved:
- Textarea ref for focus management
- Keyboard shortcut handling (Ctrl+Enter / Cmd+Enter)
- Save button disabled when content empty (trim validation)
- Keyboard shortcut hint text below textarea
- Cancel/Save action pattern
Goal: Migrate edit chat name modal to BaseModal.
Component: ChatSidebar.vue (428 → 431 lines, ~3 lines net increase, consistency gain)
Modal Migrated:
- Edit Session Name Modal - Simple text input modal for renaming chat sessions
Changes:
- Added BaseModal import
- Converted inline modal to BaseModal with medium size
- Input field with keyboard shortcuts preserved (Enter to save, Escape to cancel)
- Actions slot with Cancel and Save buttons
- Input ref maintained for focus management
Template Simplified:
- Removed fixed positioning overlay (~9 lines of template structure)
- Removed custom centering flex layout
- Removed custom modal card wrapper
- BaseModal handles all positioning and overlay
- Note: Slight net increase due to BaseModal import + slot structure, but gained consistency
Patterns Preserved:
- Input ref for focus management (editInput)
- Keyboard shortcut handlers (@keyup.enter, @keyup.escape)
- Save button triggers saveSessionName method
- Cancel button triggers cancelEdit method
- Inline Tailwind utility classes for input styling
Goal: Migrate validation report modal to BaseModal.
Component: PhaseStatusIndicator.vue (653 → 595 lines, ~58 lines saved, 8.9% reduction)
Modal Migrated:
- Validation Report Modal - Large scrollable modal displaying validation report
Changes:
- Added BaseModal import and component registration
- Converted modal-overlay structure to BaseModal with large scrollable size
- Pre-formatted text display for validation report preserved
- No custom actions (uses default close button only)
CSS Removed:
- .modal-overlay fixed positioning and structure (~12 lines)
- .modal-content wrapper with max dimensions (~9 lines)
- .modal-header layout and styling (~7 lines)
- .modal-header h3 styling (~4 lines)
- .close-btn button styles (~8 lines)
- .close-btn:hover state (~3 lines)
- .modal-body scrollable container (~5 lines)
- Removed manual keyboard event handlers (@click.self, @keyup.enter, @keyup.space)
- Total: ~57 lines
Patterns Preserved:
- .validation-report styling (background, padding, font-family, monospace, etc.)
- Pre tag for formatted text display
- Large size for potentially long text content
- Scrollable content area
BaseModal Migration Summary (Batches 47-57):
- Components Migrated: 11 components (TerminalModals, KnowledgeSearch, SecretsManager, NPUWorkersSettings, UserManagementSettings, MonitoringDashboard, KnowledgeEntries, RedisServiceControl, ChatMessages, ChatSidebar, PhaseStatusIndicator)
- Modals Consolidated: 19 modals total (4 terminal + 1 document + 3 secrets + 3 workers + 2 user mgmt + 1 monitoring + 1 knowledge + 1 service + 2 chat + 1 phase status)
- Lines Saved: ~642 lines total
- Batches 47-49: ~301 lines (182 + 54 + 65)
- Batches 50-52: ~213 lines (87 + 73 + 53)
- Batches 53-55: ~73 lines (62 + 15 - 4)
- Batches 56-57: ~55 lines (-3 + 58)
- Target: ~450-500 lines estimated → 642 lines achieved ✅ TARGET EXCEEDED (128%)
- Sizes Used: All 3 sizes (small, medium, large)
- Key Patterns: v-model binding, size variants, scrollable modals, conditional closeOnOverlay, custom title slots, actions slot with custom buttons, form submissions in modals, StatusBadge integration, operation locking, loading states, dual-mode modals, confirmation dialogs, keyboard shortcuts, pre-formatted text display
Goal: Migrate validation dashboard stat cards and content sections to BasePanel.
Component: ValidationDashboard.vue (605 → 607 lines, CSS consolidation)
Panels Migrated:
- 4 Stat Cards - System overview metrics with elevated variant
- System Maturity card (health-coded percentage)
- Phases Completed card (progress fraction)
- Active Capabilities card
- System Health card (status text)
- 5 Content Sections - Main dashboard panels with bordered variant
- Phase Progress section (phases list with completion bars)
- System Alerts section (BaseAlert components integration)
- Recommendations section (urgency badges)
- Progression Status section (grid layout with metrics)
- Phase Progression Indicator section (embedded component)
Template Changes:
- Replaced
.stat-carddivs withBasePanel variant="elevated" size="small" - Replaced
.sectiondivs withBasePanel variant="bordered" size="medium" - Moved h2/h3 titles to header slot
- Preserved all internal structure (metrics, alerts, recommendations, progress)
CSS Removed (~15 lines):
.stat-cardpanel structure (background, padding, border-radius, box-shadow) - 9 lines.sectionpanel structure - 6 lines.section h2, .section h3styling - 4 lines (handled by BasePanel header slot)
Key Features Preserved:
- System maturity calculation and health color coding
- Phase progress tracking with status colors
- System alerts with BaseAlert integration
- Recommendations with urgency indicators
- Progression status metrics
- All responsive grid layouts
Goal: Migrate voice interface configuration panels to BasePanel.
Component: VoiceInterface.vue (659 → 638 lines, ~21 lines saved, 3.2% reduction)
Panels Migrated:
- Voice Settings Panel - Speech recognition configuration
- Language selector (en-US, en-GB, es-ES, fr-FR, de-DE)
- Voice speed slider (0.5x - 2x range)
- Voice pitch slider (0.5x - 2x range)
- Auto-listen checkbox
- Voice History Panel - Recent voice commands display
- Command timestamp
- Transcribed text
- Confidence percentage
Template Changes:
- Replaced
.voice-settingsdiv withBasePanel variant="bordered" size="medium" - Replaced
.voice-historydiv withBasePanel variant="bordered" size="medium" - Moved h3 titles to header slot
- Preserved all form controls and history list structure
CSS Removed (~21 lines total):
.voice-settingspanel structure - 7 lines- padding, background, border-radius, border, box-shadow
.voice-settings h3title styling - 5 lines.voice-historypanel structure - 7 lines- padding, background, border-radius, border, box-shadow
.voice-history h3title styling - 5 lines
Key Features Preserved:
- Speech recognition language selection
- Voice speed and pitch controls (sliders)
- Auto-listen toggle functionality
- Voice command history with confidence scores
- Real-time voice visualization
- Voice status indicators (listening, processing, speaking)
BasePanel Migration Summary (Batches 58-59):
- Components Migrated: 2 components
- Panels Consolidated: 11 panels (4 stat cards + 5 sections + 2 voice panels)
- Lines Saved: ~36 lines total
- Batch 58: ~15 lines (CSS consolidation)
- Batch 59: ~21 lines (CSS consolidation)
- Variants Used: elevated (stat cards), bordered (content sections)
- Sizes Used: small (stat cards), medium (content sections)
- Key Patterns: header slot for titles, default slot for content, BasePanel wrapping existing content structures
BasePanel Adoption Findings:
- ✅ Successful for content panels: Stat cards and section containers migrate cleanly
- ❌ Not suitable for list items: Components with
.workflow-card,.phase-card,.step-cardpatterns are list items in grids/loops, not content panels ⚠️ Large dashboards: MonitoringDashboard (16 panels), CodebaseAnalytics (16 panels), SystemMonitor (12 panels) are high-value but complex- 📋 Estimated Remaining Opportunity: ~150-250 lines across larger dashboard components
Goal: Migrate performance monitoring dashboard metric cards, chart cards, and optimization section to BasePanel.
Component: MonitoringDashboard.vue (1333 → 1312 lines, ~21 lines saved, 1.6% reduction)
Panels Migrated:
-
4 Metric Cards - Performance overview cards with elevated variant (small size)
- Overall Health card - System maturity score with health status
- GPU card - NVIDIA RTX 4070 utilization, memory, temperature, power
- NPU card - Intel NPU utilization, acceleration ratio, inferences
- System card - 22-core CPU, memory, load average, network stats
-
2 Chart Cards - Timeline visualization cards with bordered variant (medium size)
- GPU Utilization Chart - Time series with range selector (5/15/60 min)
- System Performance Chart - Time series with range selector (5/15/60 min)
-
1 Optimization Section - Recommendations panel with bordered variant (medium size)
- Performance Optimization Recommendations - Priority-coded suggestions with StatusBadge
Template Changes:
<!-- Before: Metric Card -->
<div class="metric-card overall-health">
<div class="card-header">
<h5><i class="fas fa-heartbeat"></i> Overall Health</h5>
</div>
<div class="card-body">
<div :class="['health-score', overallHealth]">{{ overallHealthText }}</div>
<div class="performance-score">Score: {{ performanceScore }}/100</div>
</div>
</div>
<!-- After: BasePanel -->
<BasePanel variant="elevated" size="small">
<template #header>
<h5><i class="fas fa-heartbeat"></i> Overall Health</h5>
</template>
<div class="overall-health">
<div :class="['health-score', overallHealth]">{{ overallHealthText }}</div>
<div class="performance-score">Score: {{ performanceScore }}/100</div>
</div>
</BasePanel>
<!-- Before: Chart Card -->
<div class="chart-card">
<div class="chart-header">
<h5>GPU Utilization Timeline</h5>
<div class="chart-controls">
<select v-model="gpuTimeRange">...</select>
</div>
</div>
<div class="chart-container">...</div>
</div>
<!-- After: BasePanel with Header Wrapper -->
<BasePanel variant="bordered" size="medium">
<template #header>
<div class="chart-header-content">
<h5>GPU Utilization Timeline</h5>
<div class="chart-controls">
<select v-model="gpuTimeRange">...</select>
</div>
</div>
</template>
<div class="chart-container">...</div>
</BasePanel>CSS Removed (~60 lines):
.metric-cardstructure (background, border-radius, box-shadow, height) - 7 lines.metric-card .card-header(background, padding, border) - 5 lines.metric-card .card-header h5(margin, color, font-size) - 5 lines.metric-card .card-body(padding, height, overflow) - 5 lines.chart-cardstructure (background, border-radius, box-shadow) - 6 lines.chart-headerlayout (flex, justify, align, padding, background, border) - 8 lines.chart-header h5(margin, color, font-size) - 5 lines.optimization-sectionstructure (background, border-radius, box-shadow, margin) - 7 lines.section-headerlayout (flex, justify, align, padding, background, border) - 8 lines.section-header h4(margin, color, font-size) - 5 lines
CSS Added (~20 lines):
.chart-header-content(flex layout for header slot with controls) - 9 lines.section-header-content(flex layout for header slot with actions) - 7 lines.service-health .section-header(scoped to non-migrated service-health section) - 4 lines
Features Preserved:
- Real-time WebSocket monitoring with connection status indicators
- GPU/NPU/System metrics with EmptyState fallbacks for unavailable hardware
- Chart.js timeline visualizations with time range selector controls
- StatusBadge integration for priority/severity indicators
- BaseButton integration for monitoring controls
- BaseAlert integration for critical alerts banner
- BaseModal integration for alerts detail modal
- Recommendations list with priority color coding (list items not migrated)
- Service health cards grid (list items not migrated)
Key Pattern: Header wrappers (.chart-header-content, .section-header-content) created to maintain flex layout for controls/actions in BasePanel header slot
Goal: Migrate real-time codebase analytics dashboard cards to BasePanel.
Component: CodebaseAnalytics.vue (1607 → 1576 lines, ~31 lines saved, 1.9% reduction)
Panels Migrated:
-
4 Analytics Cards - Enhanced metrics with bordered variant (medium size)
- System Overview - API requests/min, response time, active connections, system health
- Communication Patterns - WebSocket connections, API call frequency, data transfer rate
- Code Quality - Overall score gauge, test coverage, code duplicates, technical debt
- Performance Metrics - Efficiency gauge, memory usage, CPU usage, load time
-
4 Stat Cards - Codebase statistics with elevated variant (small size)
- Total Files - File count metric
- Lines of Code - Total lines metric
- Functions - Function count metric
- Classes - Class count metric
Template Changes:
<!-- Before: Analytics Card -->
<div class="analytics-card quality-card">
<div class="card-header">
<h3><i class="fas fa-code-branch"></i> Code Quality</h3>
<button @click="loadCodeQuality" class="refresh-btn">
<i class="fas fa-sync"></i>
</button>
</div>
<div class="card-content">
<div v-if="codeQuality" class="quality-metrics">...</div>
<EmptyState v-else icon="fas fa-star" message="No quality metrics" />
</div>
</div>
<!-- After: BasePanel with Header Wrapper -->
<BasePanel variant="bordered" size="medium">
<template #header>
<div class="card-header-content">
<h3><i class="fas fa-code-branch"></i> Code Quality</h3>
<button @click="loadCodeQuality" class="refresh-btn">
<i class="fas fa-sync"></i>
</button>
</div>
</template>
<div v-if="codeQuality" class="quality-metrics">...</div>
<EmptyState v-else icon="fas fa-star" message="No quality metrics" />
</BasePanel>
<!-- Before: Stat Card -->
<div class="stat-card">
<div class="stat-value">{{ codebaseStats.total_files || 0 }}</div>
<div class="stat-label">Total Files</div>
</div>
<!-- After: BasePanel -->
<BasePanel variant="elevated" size="small">
<div class="stat-value">{{ codebaseStats.total_files || 0 }}</div>
<div class="stat-label">Total Files</div>
</BasePanel>CSS Removed (~52 lines):
.analytics-cardstructure (background, border, border-radius, overflow, transition) - 7 lines.analytics-card:hover(transform, box-shadow, border-color) - 4 lines.card-headerlayout (background, padding, border, flex, justify, align) - 8 lines.card-header h3(margin, color, font-size, font-weight) - 6 lines.card-content(padding) - 3 lines.stat-cardstructure (background, padding, border-radius, text-align, border, transition) - 8 lines.stat-card:hover(border-color, transform) - 3 lines- Plus hover states and spacing - 13 lines
CSS Added (~10 lines):
.card-header-content(flex layout for header slot with controls) - 8 lines.stat-value,.stat-label(text-align: center) - 2 lines (added to existing styles)
Features Preserved:
- Real-time analytics with live/static indicator toggle
- EmptyState fallbacks for all 8 panels when data unavailable
- System health status with color-coded badges
- Quality score and efficiency gauges with dynamic classes
- Refresh controls per analytics card
- Statistics grid layout preserved
- All metric calculations and formatting intact
- Problems, duplicates, declarations sections NOT migrated (list items in v-for)
Key Pattern: Header wrapper (.card-header-content) created to maintain flex layout for titles + refresh buttons in BasePanel header slot
Goal: Migrate real-time system monitoring dashboard glass-cards to BasePanel.
Component: SystemMonitor.vue (686 → 684 lines, ~2 lines saved, 0.3% reduction)
Panels Migrated:
- 6 Glass Cards - System monitoring panels with elevated variant (medium size)
- Performance Metrics - CPU, Memory, GPU, NPU, Network usage bars with refresh indicator
- Service Status - Online/offline service list with version info (v-for service-item)
- Performance History - Canvas chart with timeframe selector buttons
- API Health - Endpoint groups with response times (v-for endpoint-item)
- Quick Actions - Router links for chat, upload, terminal, logs
- Recent Activity - Activity feed with icons and timestamps (v-for activity-item)
Template Changes:
<!-- Before: Glass Card -->
<div class="metric-card glass-card">
<div class="card-header">
<h3>System Performance</h3>
<div class="refresh-indicator" :class="{ spinning: isRefreshing }">⟳</div>
</div>
<div class="metric-content">
<div class="metric-item">...</div>
</div>
</div>
<!-- After: BasePanel with Header Wrapper -->
<BasePanel variant="elevated" size="medium">
<template #header>
<div class="card-header-content">
<h3>System Performance</h3>
<div class="refresh-indicator" :class="{ spinning: isRefreshing }">⟳</div>
</div>
</template>
<div class="metric-content">
<div class="metric-item">...</div>
</div>
</BasePanel>CSS Removed (~21 lines):
.glass-cardstructure (background, border, border-radius, padding, backdrop-filter, box-shadow) - 8 lines.card-headerlayout (display, justify, align, margin, padding, border) - 8 lines.card-header h3(font-size, font-weight, color) - 5 lines
CSS Added (~9 lines):
.card-header-content(flex layout for header slot with controls/stats) - 7 lines.card-header-content h3(font-size, font-weight, color) - 2 lines
Features Preserved:
- Glass morphism visual style (backdrop-filter blur) now via BasePanel elevated variant
- Real-time refresh indicator with spinning animation (@keyframes spin)
- Service status badges with online/offline states
- Chart.js canvas integration with timeframe control buttons
- API endpoint grouping with health status color coding
- Router-link quick actions grid layout
- Activity feed with icon + timestamp structure
- All v-for list items preserved (service-item, endpoint-item, activity-item)
Key Pattern: Header wrapper (.card-header-content) created for cards with controls/stats in header slot (refresh indicator, status summary, API stats, timeframe buttons)
Goal: Migrate comprehensive knowledge base statistics dashboard with vector DB stats, overview cards, charts, and sections to BasePanel.
Component: KnowledgeStats.vue (1632 → 1578 lines, ~54 lines saved, 3.3% reduction)
Panels Migrated (14 total):
1-4. Vector Stat Cards (4 cards) → BasePanel variant="elevated" size="medium" (glass morphism):
<!-- Before: vector-stat-card with glass morphism -->
<div class="vector-stat-card">
<div class="vector-stat-icon facts">
<i class="fas fa-lightbulb"></i>
</div>
<div class="vector-stat-content">
<h4>Total Facts</h4>
<p class="vector-stat-value">{{ vectorStats.total_facts || 0 }}</p>
<p class="vector-stat-label">Knowledge items stored</p>
</div>
</div>
<!-- After: BasePanel elevated (handles glass morphism) -->
<BasePanel variant="elevated" size="medium">
<div class="vector-stat-icon facts">
<i class="fas fa-lightbulb"></i>
</div>
<div class="vector-stat-content">
<h4>Total Facts</h4>
<p class="vector-stat-value">{{ vectorStats.total_facts || 0 }}</p>
<p class="vector-stat-label">Knowledge items stored</p>
</div>
</BasePanel>5-9. Overview Stat Cards (5 cards) → BasePanel variant="elevated" size="small":
<!-- Before: stat-card structure -->
<div class="stat-card" role="article" aria-labelledby="facts-title">
<div class="stat-icon facts" aria-hidden="true">
<i class="fas fa-lightbulb"></i>
</div>
<div class="stat-content">
<h4 id="facts-title">Total Facts</h4>
<p class="stat-value" aria-live="polite">{{ vectorStats?.total_facts || 0 }}</p>
<p class="stat-change" aria-label="Knowledge items stored in Redis database">
Knowledge items in Redis
</p>
</div>
</div>
<!-- After: BasePanel small with preserved accessibility -->
<BasePanel variant="elevated" size="small" role="article" aria-labelledby="facts-title">
<div class="stat-icon facts" aria-hidden="true">
<i class="fas fa-lightbulb"></i>
</div>
<div class="stat-content">
<h4 id="facts-title">Total Facts</h4>
<p class="stat-value" aria-live="polite">{{ vectorStats?.total_facts || 0 }}</p>
<p class="stat-change" aria-label="Knowledge items stored in Redis database">
Knowledge items in Redis
</p>
</div>
</BasePanel>10-11. Chart Containers (2 charts) → BasePanel variant="bordered" size="medium":
<!-- Before: chart-container -->
<div class="chart-container">
<h4>Documents by Category</h4>
<div class="bar-chart">
<!-- chart content -->
</div>
</div>
<!-- After: BasePanel bordered -->
<BasePanel variant="bordered" size="medium">
<h4>Documents by Category</h4>
<div class="bar-chart">
<!-- chart content -->
</div>
</BasePanel>12-14. Section Containers (3 sections) → BasePanel variant="bordered" size="medium":
- Activity Section (recent activity timeline)
- Tag Cloud Section (popular tags with dynamic sizing)
- Man Pages Section (ManPageManager component wrapper)
CSS Removed (~60 lines):
/* Removed duplicate card structures: */
.stat-card { background: white; border: 1px solid #e5e7eb; border-radius: 0.5rem; padding: 1.5rem; display: flex; gap: 1rem; } /* 8 lines */
.vector-stat-card { background: rgba(255,255,255,0.1); backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.2); border-radius: 0.75rem; padding: 1.5rem; display: flex; align-items: center; gap: 1rem; transition: all 0.3s ease; } /* 17 lines */
.chart-container { background: white; border: 1px solid #e5e7eb; border-radius: 0.5rem; padding: 1.5rem; } /* 12 lines */
.activity-section { background: white; border: 1px solid #e5e7eb; border-radius: 0.5rem; padding: 1.5rem; margin-bottom: 2rem; } /* 8 lines */
.tag-cloud-section { background: white; border: 1px solid #e5e7eb; border-radius: 0.5rem; padding: 1.5rem; margin-bottom: 2rem; } /* 8 lines */
.manpages-section { background: white; border: 1px solid #e5e7eb; border-radius: 0.5rem; padding: 1.5rem; margin-bottom: 2rem; } /* 7 lines */Key Features Preserved:
- Conditional styling preserved (
:class="{ 'needs-attention': needsVectorization }") - Component integration maintained (StatusBadge, EmptyState, ManPageManager)
- ARIA labels and accessibility attributes (role, aria-labelledby, aria-live, aria-label)
- Vector database statistics with gradient purple background wrapper
- Glass morphism visual style via BasePanel elevated variant
- Bar chart and pie chart with type stats integration
- Tag cloud with dynamic font sizing (
:style="{ fontSize: \${tag.size}rem` }"`) - Activity timeline with activity type icons (created, updated, deleted)
- All v-for list items preserved (type-item, category-bar, activity-item, health-item, detail-item)
Key Patterns:
- Glass morphism cards use BasePanel elevated variant (handles backdrop-filter automatically)
- Overview metrics use small elevated panels
- Charts and content sections use medium bordered panels
- Accessibility attributes (role, aria-*) passed directly to BasePanel
- Conditional classes preserved for dynamic styling needs
Goal: Migrate system health monitoring dashboard with health cards and status sections to BasePanel.
Component: MCPDashboard.vue (574 → 544 lines, ~30 lines saved, 5.2% reduction)
Panels Migrated (6 total):
1-4. Health Cards (4 cards) → BasePanel variant="elevated" size="medium":
<!-- Before: health-card with conditional styling -->
<div class="health-card" :class="getHealthClass(health.frontend)">
<div class="card-header">
<i class="fas fa-desktop"></i>
<h3>Frontend</h3>
<span class="status-icon">
<i :class="getStatusIcon(health.frontend.status)"></i>
</span>
</div>
<div class="card-body">
<div class="metric">
<span class="label">Console Errors:</span>
<span class="value" :class="{ 'text-danger': health.frontend.errorCount > 0 }">
{{ health.frontend.errorCount }}
</span>
</div>
</div>
</div>
<!-- After: BasePanel elevated with header slot -->
<BasePanel variant="elevated" size="medium" :class="getHealthClass(health.frontend)">
<template #header>
<i class="fas fa-desktop"></i>
<h3>Frontend</h3>
<span class="status-icon">
<i :class="getStatusIcon(health.frontend.status)"></i>
</span>
</template>
<div class="card-body">
<div class="metric">
<span class="label">Console Errors:</span>
<span class="value" :class="{ 'text-danger': health.frontend.errorCount > 0 }">
{{ health.frontend.errorCount }}
</span>
</div>
</div>
</BasePanel>5-6. Status Sections (2 sections) → BasePanel variant="bordered" size="medium":
<!-- Before: activity-section -->
<div class="activity-section">
<h3><i class="fas fa-history"></i> Recent Activity</h3>
<div class="activity-log">
<!-- log entries -->
</div>
</div>
<!-- After: BasePanel bordered with header slot -->
<BasePanel variant="bordered" size="medium">
<template #header>
<h3><i class="fas fa-history"></i> Recent Activity</h3>
</template>
<div class="activity-log">
<!-- log entries -->
</div>
</BasePanel>CSS Removed (~30 lines):
/* Removed duplicate card structures: */
.health-card { background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); padding: 0; overflow: hidden; transition: transform 0.2s, box-shadow 0.2s; }
.health-card:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.15); }
.card-header { padding: 15px 20px; background: #f8f9fa; border-bottom: 1px solid #e9ecef; display: flex; align-items: center; gap: 10px; }
.card-header h3 { margin: 0; font-size: 18px; flex: 1; }
.activity-section, .mcp-tools-section { background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); padding: 20px; margin-bottom: 20px; }
/* Kept conditional health state border classes (.health-good, .health-warning, .health-error, .health-unknown) */Key Features Preserved:
- Conditional health state styling (health-good/warning/error/unknown classes with colored borders)
- Status icon positioning with margin-left: auto
- Health metrics with conditional danger highlighting
- Activity log entries with log level styling (log-error, log-warning, log-success)
- MCP tools grid with active/inactive states
- Card hover effects handled by BasePanel
- All header icons and titles preserved
Key Patterns:
- Health cards use elevated variant for prominence with shadow effects
- Status sections use bordered variant for clean separation
- Header slot used for titles with icons
- Conditional classes preserved for dynamic health states
- BasePanel handles hover transitions automatically
Goal: Migrate knowledge base management component panels to BasePanel.
Component: SystemKnowledgeManager.vue (1013 → 1011 lines, ~2 lines saved, 0.2% reduction)
Panels Migrated (5 total):
1-4. Status Cards (4 cards) → BasePanel variant="elevated" size="small":
<!-- Before: status-card with icon and content -->
<div class="status-card">
<div class="status-icon">📚</div>
<div class="status-content">
<h3>{{ stats.total_facts || 0 }}</h3>
<p>Total Facts</p>
</div>
</div>
<!-- After: BasePanel elevated with status-card-content wrapper -->
<BasePanel variant="elevated" size="small">
<div class="status-card-content">
<div class="status-icon">📚</div>
<div class="status-content">
<h3>{{ stats.total_facts || 0 }}</h3>
<p>Total Facts</p>
</div>
</div>
</BasePanel>- Info Section → BasePanel
variant="bordered" size="medium":
<!-- Before: info-section with title and content -->
<div class="info-section">
<h3>ℹ️ About System Knowledge</h3>
<div class="info-content">
<p><strong>Initialize Machine Knowledge:</strong> Creates vector embeddings...</p>
<!-- more info paragraphs -->
</div>
</div>
<!-- After: BasePanel bordered with header slot -->
<BasePanel variant="bordered" size="medium">
<template #header>
<h3>ℹ️ About System Knowledge</h3>
</template>
<div class="info-content">
<p><strong>Initialize Machine Knowledge:</strong> Creates vector embeddings...</p>
<!-- more info paragraphs -->
</div>
</BasePanel>CSS Removed (~16 lines):
/* Removed duplicate card/section structures: */
.status-card { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); display: flex; align-items: center; gap: 15px; }
.info-section { background: #f8f9fa; border-radius: 8px; padding: 20px; margin-bottom: 30px; }
.info-section h3 { margin: 0 0 15px 0; color: #2c3e50; }
/* Kept content-level styles: */
.status-card-content { display: flex; align-items: center; gap: 15px; }
.status-icon { font-size: 32px; }
.status-content h3/p { /* styling preserved */ }
.info-content p { margin: 10px 0; line-height: 1.6; color: #555; }Key Features Preserved:
- Status card icon and content layout (status-icon + status-content)
- Stats bindings (stats.total_facts, stats.total_vectors, commandsIndexed, docsIndexed)
- Info section header moved to BasePanel header slot
- Info content paragraphs with usage instructions for all operations (Initialize, Reindex, Refresh Man Pages, Populate Commands, Index Docs)
- All styling and spacing maintained
Key Patterns:
- Status cards use elevated variant small for compact metric display
- Info section uses bordered variant medium for documentation content
- Header slot used for info section title with emoji
- Status cards wrap content in status-card-content div for internal layout
- BasePanel handles container styling, content classes remain for internal structure
Goal: Migrate refresh button to BaseButton for consistent styling and behavior (returning to BaseButton migrations).
Component: MCPDashboard.vue (545 → 528 lines, ~17 lines saved, 3.1% reduction)
Button Migrated (1 total):
- Refresh Button → BaseButton
variant="primary"with loading state:
<!-- Before: custom button with manual loading handling -->
<button @click="refreshData" :disabled="loading" class="btn-refresh">
<i class="fas fa-sync-alt" :class="{ 'fa-spin': loading }"></i>
Refresh
</button>
<!-- After: BaseButton with built-in loading -->
<BaseButton
@click="refreshData"
:disabled="loading"
variant="primary"
:loading="loading"
icon="fas fa-sync-alt"
>
Refresh
</BaseButton>CSS Removed (~20 lines):
/* Removed manual button styling: */
.btn-refresh { padding: 8px 16px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; display: flex; align-items: center; gap: 8px; transition: background 0.3s; }
.btn-refresh:hover:not(:disabled) { background: #0056b3; }
.btn-refresh:disabled { opacity: 0.6; cursor: not-allowed; }Key Features Preserved:
- Loading state with spinning icon (BaseButton
:loadingprop handles icon animation) - Disabled state during refresh operation
- Click handler for refreshData method
- Primary blue styling via variant="primary"
- Icon positioning and display
Key Patterns:
- BaseButton :loading prop replaces manual :class="{ 'fa-spin': loading }"
- Icon specified via icon prop instead of template element
- Variant primary provides blue background matching previous .btn-refresh
- All hover, active, and disabled states handled by BaseButton
- Consistent with 29 other components using BaseButton
Note: This batch returns to BaseButton migrations after completing BasePanel work (Batches 58-65). MCPDashboard.vue was migrated to BasePanel in Batch 64, but its button was not migrated at that time.
Goal: Migrate connection status monitoring buttons to BaseButton for consistency and centralized behavior.
Component: ConnectionStatus.vue (390 → 405 lines, +15 lines - consistency gain, 3.8% increase)
Buttons Migrated (4 total):
- Toggle Details Button → BaseButton
variant="ghost" size="sm":
<!-- Before: custom button with SVG chevron -->
<button
@click="toggleDetails"
class="text-gray-400 hover:text-gray-600 ml-2"
:aria-expanded="showDetails"
aria-label="Toggle connection details"
>
<svg class="w-4 h-4 transition-transform" :class="{ 'rotate-180': showDetails }">
<!-- chevron path -->
</svg>
</button>
<!-- After: BaseButton ghost with SVG in slot -->
<BaseButton
@click="toggleDetails"
variant="ghost"
size="sm"
:aria-expanded="showDetails"
aria-label="Toggle connection details"
class="ml-2 text-gray-400 hover:text-gray-600"
>
<svg class="w-4 h-4 transition-transform" :class="{ 'rotate-180': showDetails }">
<!-- chevron path -->
</svg>
</BaseButton>2-3. Action Buttons (Force Reconnect, Health Check) → BaseButton variant="link" size="xs":
<!-- Before: custom text buttons with manual loading text -->
<button
@click="forceReconnect"
class="text-blue-600 hover:text-blue-800 text-xs"
:disabled="reconnecting"
>
{{ reconnecting ? 'Reconnecting...' : 'Force Reconnect' }}
</button>
<!-- After: BaseButton link with :loading prop -->
<BaseButton
@click="forceReconnect"
variant="link"
size="xs"
:loading="reconnecting"
:disabled="reconnecting"
class="text-blue-600 hover:text-blue-800"
>
{{ reconnecting ? 'Reconnecting...' : 'Force Reconnect' }}
</BaseButton>- Close Toast Button → BaseButton
variant="ghost" size="sm":
<!-- Before: custom button with X icon -->
<button
@click="removeToast(toast.id)"
class="ml-2 text-gray-400 hover:text-gray-600"
>
<svg class="w-4 h-4"><!-- X icon path --></svg>
</button>
<!-- After: BaseButton ghost with accessibility -->
<BaseButton
@click="removeToast(toast.id)"
variant="ghost"
size="sm"
class="ml-2 text-gray-400 hover:text-gray-600"
aria-label="Close notification"
>
<svg class="w-4 h-4"><!-- X icon path --></svg>
</BaseButton>Key Features Preserved:
- Toggle details with animated chevron rotation (:class="{ 'rotate-180': showDetails }")
- Loading states for reconnect and health check (BaseButton :loading prop)
- Toast notification close functionality with icon
- All Tailwind utility classes for positioning (ml-2) and colors (text-blue-600, hover:text-blue-800)
- Accessibility attributes (aria-expanded, aria-label added for close button)
- Button disabled states during operations
Key Patterns:
- Ghost variant for icon-only buttons (toggle, close)
- Link variant for text action buttons (reconnect, health check)
- Size xs for compact action buttons, sm for icon buttons
- SVG icons passed in default slot
- Tailwind classes preserved on BaseButton for custom colors
- BaseButton :loading handles loading states instead of manual text changes
- Accessibility improvements (added aria-label to close button)
Note: File increased by 15 lines due to BaseButton's more explicit prop syntax (multi-line prop declarations for readability), but gains consistency with 30 other components and centralized button behavior. This is a consistency gain migration rather than lines saved.
BasePanel Migration Summary (Batches 58-65):
- Components Migrated: 8 components (ValidationDashboard, VoiceInterface, MonitoringDashboard, CodebaseAnalytics, SystemMonitor, KnowledgeStats, MCPDashboard, SystemKnowledgeManager)
- Panels Consolidated: 57 panels (13 stat cards + 10 sections + 2 voice panels + 4 metric cards + 4 chart cards + 1 optimization section + 4 analytics cards + 6 glass cards + 4 vector stat cards + 4 health cards + 4 status cards + 1 info section)
- Lines Saved: ~176 lines total
- Batch 58: ~0 lines (CSS consolidation, template overhead offset)
- Batch 59: ~36 lines (CSS consolidation)
- Batch 60: ~21 lines (CSS consolidation)
- Batch 61: ~31 lines (CSS consolidation)
- Batch 62: ~2 lines (CSS consolidation)
- Batch 63: ~54 lines (CSS consolidation)
- Batch 64: ~30 lines (CSS consolidation)
- Batch 65: ~2 lines (CSS consolidation)
- Variants Used: elevated (metric/stat/glass/vector/health/status cards), bordered (sections/charts/optimization/analytics/activity/tag-cloud/manpages/status/info)
- Sizes Used: small (metric/stat/status cards), medium (sections/charts/optimization/analytics/glass cards/vector cards/health cards/info section)
- Key Patterns: header slot for titles, header wrappers for controls, default slot for content, accessibility attributes preservation, conditional styling preservation
Migration Status Update:
- EmptyState migrations: ~579 lines (38.6% of realistic target)
- Utility consolidation: ~18 lines (batch 14)
- StatusBadge adoptions: ~197 lines (batches 15-19)
- Batch 15: ~14 lines (3 components)
- Batch 16: ~49 lines (2 components)
- Batch 17: ~15 lines (1 component, 2 patterns)
- Batch 18: ~90 lines (4 components, 5 patterns)
- Batch 19: ~29 lines (1 component - final sweep)
- BaseButton adoptions: ~1,834 lines saved, -15 lines consistency gain (batches 20-40, 66-67)
- Batch 20: ~157 lines (3 components, 10 buttons)
- Batch 21: ~87 lines (2 components, 11 buttons)
- Batch 22: ~187 lines (2 components, 7 buttons)
- Batch 23: ~96 lines (2 components, 12 buttons)
- Batch 24: ~39 lines (1 component, 16 buttons)
- Batch 25: ~114 lines (2 components, 19 buttons)
- Batch 26: ~129 lines (3 components, 19 buttons)
- Batch 27: ~170 lines (1 component, 17 buttons)
- Batch 28: ~65 lines (1 component, 10 buttons)
- Batch 29: ~156 lines (1 component, 9 buttons)
- Batch 30: ~61 lines (1 component, 5 buttons)
- Batch 31: ~58 lines (1 component, 4 buttons)
- Batch 32: ~24 lines (1 component, 4 buttons)
- Batch 33: ~19 lines (1 component, 3 buttons)
- Batch 34: ~50 lines (1 component, 3 buttons)
- Batch 35: ~60 lines (1 component, 10 buttons)
- Batch 36: ~90 lines (1 component, 15 buttons)
- Batch 37: ~65 lines (1 component, 8 buttons)
- Batch 38: ~85 lines (1 component, 9 buttons)
- Batch 39: ~70 lines (1 component, 6 buttons)
- Batch 40: ~35 lines (1 component, 5 buttons)
- Batch 66: ~17 lines (1 component, 1 button)
- Batch 67: -15 lines (1 component, 4 buttons - consistency gain)
- BaseAlert adoptions: ~121 lines (batches 41-46)
- Batch 41: ~22 lines (1 component, 2 alerts) + BaseAlert.vue creation
- Batch 42: ~18 lines (1 component, 2 alerts)
- Batch 43: ~14 lines (1 component, 1 alert)
- Batch 44: ~40 lines (1 component, alerts list with v-for)
- Batch 45: ~17 lines (1 component, 1 banner)
- Batch 46: ~10 lines (1 component, 1 alert)
- BaseModal adoptions: ~642 lines (batches 47-57)
- Batch 47: ~182 lines (1 component, 4 modals)
- Batch 48: ~54 lines (1 component, 1 modal)
- Batch 49: ~65 lines (1 component, 3 modals)
- Batch 50: ~87 lines (1 component, 3 modals)
- Batch 51: ~73 lines (1 component, 2 modals)
- Batch 52: ~53 lines (1 component, 1 modal)
- Batch 53: ~62 lines (1 component, 1 modal)
- Batch 54: ~15 lines (1 component, 1 modal)
- Batch 55: ~0 lines (1 component, 1 modal - consistency gain)
- Batch 56: ~-3 lines (1 component, 1 modal - consistency gain)
- Batch 57: ~58 lines (1 component, 1 modal)
- BasePanel adoptions: ~176 lines (batches 58-65)
- Batch 58: ~0 lines (1 component, 9 panels - consistency gain, CSS consolidation)
- Batch 59: ~36 lines (1 component, 2 panels)
- Batch 60: ~21 lines (1 component, 7 panels)
- Batch 61: ~31 lines (1 component, 8 panels)
- Batch 62: ~2 lines (1 component, 6 panels)
- Batch 63: ~54 lines (1 component, 14 panels)
- Batch 64: ~30 lines (1 component, 6 panels)
- Batch 65: ~2 lines (1 component, 5 panels)
- Batch 66: ~17 lines (1 component, 1 button - return to BaseButton migrations)
- Batch 67: -15 lines (1 component, 4 buttons - consistency gain)
- Total Progress: ~3,552 lines / ~1,500-2,000 realistic target (178-237%) ✅ TARGET EXCEEDED
- StatusBadge Milestone: 15 instances across 11 components (650% increase from 2 baseline)
- BaseButton Milestone: 31 components using BaseButton (207 buttons consolidated)
- BaseAlert Milestone: 6 components using BaseAlert (10+ alerts consolidated)
- BaseModal Milestone: 16 components using BaseModal (2 baseline + 14 new, 19 modals consolidated)
- BasePanel Milestone: 8 components using BasePanel (0 baseline + 8 new, 57 panels consolidated)
📊 Final Assessment: Underutilized Reusable Components (January 2025):
During batch 14 final sweep, discovered several well-designed reusable components that exist but are significantly underutilized:
1. BaseButton.vue (autobot-frontend/src/components/base/)
- Current Usage: ✅ MIGRATION ONGOING - 31 components using BaseButton (batches 20-40, 66-67+)
- First batches (20-24): ErrorBoundary, AsyncErrorFallback, PhaseStatusIndicator, dialogs, settings, research browser
- Middle batches (25-40): Terminal, chat, knowledge, monitoring, phase progression
- Return to BaseButton (Batch 66-67): MCPDashboard refresh button, ConnectionStatus (toggle, actions, close)
- Features: 11 variants (primary/secondary/success/danger/warning/info/light/dark/outline/ghost/link), 5 sizes (xs-xl), loading states, icon support, flexible rendering (button/link/custom tag), ✅ Optional touch optimization (ripple effects, haptic feedback, 44px touch targets)
- Status: ✅ CONTINUED ADOPTION - 31 components, 207 buttons consolidated
- Results: ~1,819 lines saved (1,834 saved - 15 consistency gain) across 42 batches, 207 buttons consolidated across 31 components
- Touch Integration: ✅ COMPLETED - Extended with optional touchOptimized, touchFeedback, hapticFeedback props (backward compatible)
- Achievement: Successfully established BaseButton as the standard button pattern across entire frontend codebase
- Remaining: ~12 more buttons identified across 3 components (ErrorNotifications: 3, HistoryView: 3, LogViewer: 5, plus misc)
2. TouchFriendlyButton.vue (autobot-frontend/src/components/ui/)
- Current Usage: 0 components (no imports found)
- Features: Size variants (xs-xl), style variants (primary/secondary/outline/ghost/danger), loading states, touch feedback, haptic feedback, accessibility (dark mode, high contrast, reduced motion)
- Status: ✅ OVERLAP RESOLVED - All touch features integrated into BaseButton
- Recommendation:
⚠️ Deprecation candidate - Features now available in BaseButton via touchOptimized prop - Alternative: Convert to lightweight wrapper around
<BaseButton touchOptimized>for backward compatibility - Analysis: BaseButton now has all TouchFriendlyButton features (11 variants + touch optimization) making this component redundant
3. StatusBadge.vue (autobot-frontend/src/components/ui/)
- Current Usage: ✅ SUBSTANTIALLY COMPLETE - 15 instances across 11 components (batches 15-19 migrations)
- Original: VectorizationProgressModal, TreeNodeComponent
- Batches 15-19: KnowledgePersistenceDialog, HostsManager, ResearchBrowser, MonitoringDashboard, SecretsManager, CommandPermissionDialog, ElevationDialog, KnowledgeStats, NPUWorkersSettings
- Features: Variant styles (success/danger/warning/info/primary/secondary), sizes (small/medium/large), icon support, dark mode
- Recommendation: ✅ Enforcement complete - Law of diminishing returns reached
- Results: ~197 lines saved (batches 15-19), 650% usage increase (2 → 15 instances)
- Achievement: Successfully established as standard badge pattern across diverse contexts
3. useToast Composable (autobot-frontend/src/composables/useToast.js)
- Current Usage: 2 components (KnowledgePersistenceDialog + examples)
- Features: Global toast state, type variants (info/success/warning/error), auto-dismiss, toast management
- Recommendation: ✅ Good pattern but needs Toast UI component - Many components implement inline alert/notification patterns
- Estimated Potential: ~50-150 lines if adopted for user feedback patterns
Analysis: These components represent prior investment in reusability infrastructure that hasn't been fully leveraged. The challenge isn't creating new patterns - it's adopting existing ones.
Why Low Adoption?:
- Lack of awareness: Developers may not know these components exist
- Migration friction: Easier to copy existing inline patterns than refactor to use shared components
- Time constraints: Quick inline solutions prioritized over proper architecture
- Missing documentation: Components need usage examples and migration guides
Recommended Path Forward:
- ✅ Document existing components in this guide with clear usage examples
- ✅ Create migration guides showing before/after conversions
⚠️ Establish component adoption policy - require use of shared components in new code- 📋 Gradual migration - target high-value files first (forms, modals, status displays)
Revised Opportunity Assessment:
- Direct code savings from existing patterns: ~200-400 lines (batch 14 baseline)
- Additional savings from adopting existing components: ~200-450 lines
- Combined potential: ~400-850 lines (aggressive adoption scenario)
Priority 1: Leverage Existing Components (High ROI)
- 📋 Adopt TouchFriendlyButton.vue in forms and modals (~100-200 lines)
- 📋 Adopt StatusBadge.vue for status indicators (~50-100 lines)
- 📋 Create Toast UI component to pair with useToast composable
- 📋 Document component usage patterns and migration examples
Priority 2: New Presentational Components (Medium ROI)
- 📋 Create FormInput reusable component (if truly generic pattern found)
- 📋 Create Card/Panel variants (evaluate against batch 13 contextual variation principle)
Priority 3: Enforcement & Culture
- 📋 Add pre-commit checks for inline patterns that should use shared components
- 📋 Update component contribution guidelines
- 📋 Create "component showcase" documentation
Location: autobot-frontend/src/components/ui/TouchFriendlyButton.vue
Before (Inline button with custom styling):
<template>
<button
@click="handleSubmit"
:disabled="isSubmitting"
class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 disabled:opacity-50 transition-colors"
>
{{ isSubmitting ? 'Saving...' : 'Save Changes' }}
</button>
</template>After (Using TouchFriendlyButton):
<script setup>
import TouchFriendlyButton from '@/components/ui/TouchFriendlyButton.vue'
</script>
<template>
<TouchFriendlyButton
variant="primary"
size="md"
:loading="isSubmitting"
@click="handleSubmit"
>
Save Changes
</TouchFriendlyButton>
</template>Benefits:
- ✅ Touch feedback with ripple effect
- ✅ Haptic feedback on mobile
- ✅ Loading state with spinner
- ✅ Accessibility (dark mode, reduced motion)
- ✅ Consistent sizing (minimum 44px touch target)
All Variants:
<!-- Size variants -->
<TouchFriendlyButton size="xs">Extra Small</TouchFriendlyButton>
<TouchFriendlyButton size="sm">Small</TouchFriendlyButton>
<TouchFriendlyButton size="md">Medium</TouchFriendlyButton>
<TouchFriendlyButton size="lg">Large</TouchFriendlyButton>
<TouchFriendlyButton size="xl">Extra Large</TouchFriendlyButton>
<!-- Style variants -->
<TouchFriendlyButton variant="primary">Primary</TouchFriendlyButton>
<TouchFriendlyButton variant="secondary">Secondary</TouchFriendlyButton>
<TouchFriendlyButton variant="outline">Outline</TouchFriendlyButton>
<TouchFriendlyButton variant="ghost">Ghost</TouchFriendlyButton>
<TouchFriendlyButton variant="danger">Danger</TouchFriendlyButton>
<!-- With icon and loading -->
<TouchFriendlyButton :loading="true">
<template #icon>
<i class="fas fa-save"></i>
</template>
Save
</TouchFriendlyButton>Location: autobot-frontend/src/components/ui/StatusBadge.vue
Before (Inline badge):
<template>
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">
<i class="fas fa-check-circle mr-1"></i>
Active
</span>
</template>After (Using StatusBadge):
<script setup>
import StatusBadge from '@/components/ui/StatusBadge.vue'
</script>
<template>
<StatusBadge variant="success" icon="fas fa-check-circle">
Active
</StatusBadge>
</template>Benefits:
- ✅ Consistent status colors across application
- ✅ Dark mode support
- ✅ Size variants (small/medium/large)
- ✅ Optional icon integration
All Variants:
<!-- Variant styles -->
<StatusBadge variant="success">Success</StatusBadge>
<StatusBadge variant="danger">Danger</StatusBadge>
<StatusBadge variant="warning">Warning</StatusBadge>
<StatusBadge variant="info">Info</StatusBadge>
<StatusBadge variant="primary">Primary</StatusBadge>
<StatusBadge variant="secondary">Secondary</StatusBadge>
<!-- Sizes -->
<StatusBadge size="small" variant="success">Small</StatusBadge>
<StatusBadge size="medium" variant="success">Medium</StatusBadge>
<StatusBadge size="large" variant="success">Large</StatusBadge>
<!-- With icons -->
<StatusBadge variant="success" icon="fas fa-check-circle">Active</StatusBadge>
<StatusBadge variant="danger" icon="fas fa-times-circle">Failed</StatusBadge>
<StatusBadge variant="warning" icon="fas fa-exclamation-triangle">Pending</StatusBadge>Location: autobot-frontend/src/composables/useToast.js
Before (Inline alert/notification):
<template>
<div v-if="showSuccess" class="fixed top-4 right-4 bg-green-50 border border-green-200 rounded-lg p-4">
<p class="text-green-800">File uploaded successfully!</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const showSuccess = ref(false)
const handleUpload = async () => {
try {
await uploadFile()
showSuccess.value = true
setTimeout(() => { showSuccess.value = false }, 3000)
} catch (error) {
// Handle error
}
}
</script>After (Using useToast):
<script setup>
import { useToast } from '@/composables/useToast'
const { showToast } = useToast()
const handleUpload = async () => {
try {
await uploadFile()
showToast('File uploaded successfully!', 'success')
} catch (error) {
showToast('Upload failed. Please try again.', 'error')
}
}
</script>Benefits:
- ✅ Global toast management (no local state)
- ✅ Auto-dismiss after duration
- ✅ Type variants (info/success/warning/error)
- ✅ Stack multiple toasts
- ✅ Programmatic control
All Usage Patterns:
import { useToast } from '@/composables/useToast'
const { showToast, removeToast, clearAllToasts, toasts } = useToast()
// Show toast with auto-dismiss (3 seconds default)
showToast('Operation successful!', 'success')
// Show toast with custom duration
showToast('Processing...', 'info', 5000)
// Show toast that persists (no auto-dismiss)
const toastId = showToast('Critical error', 'error', 0)
// Manually dismiss specific toast
removeToast(toastId)
// Clear all toasts
clearAllToasts()
// Access all active toasts (reactive)
console.log(toasts.value)Note: Requires Toast UI component in App.vue or layout to display toasts. See KnowledgePersistenceDialog.vue for implementation example.
Component: DocumentChangeFeed.vue
Before (14 lines with custom CSS):
<template>
<div v-else class="empty-state">
<i class="fas fa-inbox fa-3x"></i>
<p>No recent changes detected</p>
<button class="btn btn-secondary" @click="handleScanNow">
Scan for Changes
</button>
</div>
</template>
<style scoped>
.empty-state {
text-align: center;
padding: 3rem 1rem;
color: #6b7280;
}
/* ... more CSS ... */
</style>After (4 lines, reusable component):
<script setup>
import EmptyState from '@/components/ui/EmptyState.vue'
</script>
<template>
<EmptyState
v-else
icon="fas fa-inbox"
message="No recent changes detected"
>
<template #actions>
<button class="btn btn-secondary" @click="handleScanNow">
Scan for Changes
</button>
</template>
</EmptyState>
</template>Result:
- ✅ 14 lines removed
- ✅ No custom CSS needed
- ✅ Consistent styling with other empty states
Component: KnowledgeCategories.vue
Before (58 lines with custom modal HTML + CSS):
<template>
<div v-if="showCreateDialog || showEditDialog" class="dialog-overlay" @click="closeDialogs">
<div class="dialog" @click.stop>
<div class="dialog-header">
<h3>{{ showEditDialog ? 'Edit Category' : 'Create Category' }}</h3>
<button @click="closeDialogs" class="close-btn">
<i class="fas fa-times"></i>
</button>
</div>
<div class="dialog-content">
<!-- Form fields here -->
</div>
<div class="dialog-actions">
<button @click="closeDialogs">Cancel</button>
<button @click="saveCategory">Save</button>
</div>
</div>
</div>
</template>
<style scoped>
.dialog-overlay { /* ... */ }
.dialog { /* ... */ }
.dialog-header { /* ... */ }
.dialog-content { /* ... */ }
.dialog-actions { /* ... */ }
.close-btn { /* ... */ }
</style>After (35 lines, reusable component with computed v-model):
<script setup>
import BaseModal from '@/components/ui/BaseModal.vue'
// Computed property for v-model binding
const showCategoryDialog = computed({
get: () => showCreateDialog.value || showEditDialog.value,
set: (val) => {
if (!val) {
showCreateDialog.value = false
showEditDialog.value = false
}
}
})
</script>
<template>
<BaseModal
v-model="showCategoryDialog"
:title="showEditDialog ? 'Edit Category' : 'Create Category'"
size="small"
@close="closeDialogs"
>
<!-- Form fields here -->
<template #actions>
<button @click="closeDialogs">Cancel</button>
<button @click="saveCategory">Save</button>
</template>
</BaseModal>
</template>Result:
- ✅ 23 lines removed from template
- ✅ 82 lines of CSS removed
- ✅ Total: ~105 lines saved
- ✅ Consistent modal behavior (transitions, overlay clicks, etc.)
- ✅ Dark mode support automatically included
Component: DeleteConversationDialog.vue
Before (Custom Teleport structure with ~80 lines of boilerplate):
<template>
<Teleport to="body">
<div v-if="visible" class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
<div class="bg-white rounded-lg shadow-xl w-full max-w-md mx-4">
<!-- Header -->
<div class="flex items-center justify-between p-4 border-b bg-red-50">
<h3>Delete Conversation</h3>
<button @click="handleCancel">
<i class="fas fa-times"></i>
</button>
</div>
<!-- Content with warning, file stats, action options -->
<div class="p-4 space-y-4">
<!-- Warning message, file information, action radio buttons -->
<!-- Transfer options (KB or shared storage) -->
<!-- Confirmation summary -->
</div>
<!-- Footer Actions -->
<div class="flex justify-end gap-3 p-4 border-t border-gray-200">
<button @click="handleCancel">Cancel</button>
<button @click="handleConfirm">Delete Conversation</button>
</div>
</div>
</div>
</Teleport>
</template>
<style scoped>
@keyframes fadeIn { /* ... */ }
@keyframes slideUp { /* ... */ }
.fixed.inset-0 { animation: fadeIn 0.2s; }
.bg-white.rounded-lg { animation: slideUp 0.3s; }
</style>After (Clean BaseModal implementation with ~30 lines):
<script setup lang="ts">
import BaseModal from '@/components/ui/BaseModal.vue'
</script>
<template>
<BaseModal
:model-value="visible"
title="Delete Conversation"
size="small"
@update:model-value="$emit('update:visible', $event)"
@close="handleCancel"
>
<template #default>
<!-- All content sections remain unchanged -->
<div class="p-4 space-y-4">
<!-- Warning message, file stats, action options -->
<!-- Transfer options, confirmation summary -->
</div>
</template>
<template #actions>
<button @click="handleCancel">Cancel</button>
<button @click="handleConfirm">Delete Conversation</button>
</template>
</BaseModal>
</template>Result:
- ✅ ~50 lines of custom modal HTML removed
- ✅ ~30 lines of CSS animations removed
- ✅ Total: ~80 lines saved
- ✅ All original functionality preserved (file actions, transfer options, validation)
- ✅ Consistent modal behavior with proper z-index, overlay, transitions
- ✅ No need to manage Teleport, overlay clicks, or animations manually
When migrating any component:
-
Identify the pattern to replace (empty state, modal, badge, table)
-
Import the reusable component:
import EmptyState from '@/components/ui/EmptyState.vue' import BaseModal from '@/components/ui/BaseModal.vue' import StatusBadge from '@/components/ui/StatusBadge.vue' import DataTable from '@/components/ui/DataTable.vue'
-
Replace custom HTML with reusable component
-
Remove duplicate CSS that is now handled by the reusable component
-
Test the component to ensure all functionality works
-
Sync to frontend VM:
./scripts/utilities/sync-to-vm.sh frontend autobot-frontend/src/components/YourComponent.vue /home/autobot/autobot-frontend/src/components/YourComponent.vue
-
Update GitHub issue #10894 to track completion
-
Always check for existing utilities before implementing custom logic
-
Use shared components for consistent UI patterns
-
Leverage composables for reusable logic
-
Import from centralized locations:
- CSS:
@/styles/ - Utils:
@/utils/ - UI Components:
@/components/ui/ - Base Components:
@/components/base/ - Composables:
@/composables/
- CSS:
-
Document new reusable patterns in this guide
- Format Helpers Source
- UI Components Directory
- Base Components Directory
- Composables Directory
- Shared Styles Directory
For questions or suggestions, contact the development team or open an issue in the repository.