model-selection-indicator.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. 'use client';
  2. import React from 'react';
  3. import { Badge } from '@/components/ui/badge';
  4. import { Button } from '@/components/ui/button';
  5. import {
  6. CheckCircle2,
  7. AlertCircle,
  8. XCircle,
  9. Zap,
  10. RotateCcw,
  11. Info,
  12. AlertTriangle
  13. } from 'lucide-react';
  14. import { cn } from '@/lib/utils';
  15. interface ModelSelectionIndicatorProps {
  16. modelName: string | null;
  17. isAutoSelected: boolean;
  18. isUserOverride: boolean;
  19. isLoaded?: boolean;
  20. onClearOverride?: () => void;
  21. onRevertToAuto?: () => void;
  22. className?: string;
  23. }
  24. export function ModelSelectionIndicator({
  25. modelName,
  26. isAutoSelected,
  27. isUserOverride,
  28. isLoaded = false,
  29. onClearOverride,
  30. onRevertToAuto,
  31. className
  32. }: ModelSelectionIndicatorProps) {
  33. if (!modelName) {
  34. return (
  35. <div className={cn("flex items-center gap-2 text-sm text-muted-foreground", className)}>
  36. <XCircle className="h-4 w-4" />
  37. <span>No model selected</span>
  38. </div>
  39. );
  40. }
  41. const getIndicatorColor = () => {
  42. if (isUserOverride) {
  43. return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200';
  44. }
  45. if (isAutoSelected) {
  46. return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200';
  47. }
  48. return 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-200';
  49. };
  50. const getIndicatorIcon = () => {
  51. if (isUserOverride) {
  52. return <CheckCircle2 className="h-3 w-3" />;
  53. }
  54. if (isAutoSelected) {
  55. return <Zap className="h-3 w-3" />;
  56. }
  57. return <Info className="h-3 w-3" />;
  58. };
  59. const getIndicatorText = () => {
  60. if (isUserOverride) {
  61. return 'Manual';
  62. }
  63. if (isAutoSelected) {
  64. return 'Auto';
  65. }
  66. return 'Selected';
  67. };
  68. return (
  69. <div className={cn("flex items-center gap-2", className)}>
  70. <Badge variant="secondary" className={getIndicatorColor()}>
  71. {getIndicatorIcon()}
  72. <span className="ml-1">{getIndicatorText()}</span>
  73. </Badge>
  74. <span className={cn(
  75. "text-sm",
  76. isLoaded ? "text-green-600 dark:text-green-400" : "text-muted-foreground"
  77. )}>
  78. {modelName}
  79. </span>
  80. {isUserOverride && onClearOverride && (
  81. <Button
  82. variant="ghost"
  83. size="sm"
  84. onClick={onClearOverride}
  85. className="h-6 w-6 p-0"
  86. title="Clear manual selection"
  87. >
  88. <RotateCcw className="h-3 w-3" />
  89. </Button>
  90. )}
  91. {isUserOverride && onRevertToAuto && (
  92. <Button
  93. variant="ghost"
  94. size="sm"
  95. onClick={onRevertToAuto}
  96. className="h-6 w-6 p-0"
  97. title="Revert to auto-selected model"
  98. >
  99. <Zap className="h-3 w-3" />
  100. </Button>
  101. )}
  102. </div>
  103. );
  104. }
  105. interface ModelSelectionWarningProps {
  106. warnings: string[];
  107. errors: string[];
  108. onClearWarnings?: () => void;
  109. className?: string;
  110. }
  111. export function ModelSelectionWarning({
  112. warnings,
  113. errors,
  114. onClearWarnings,
  115. className
  116. }: ModelSelectionWarningProps) {
  117. if (warnings.length === 0 && errors.length === 0) {
  118. return null;
  119. }
  120. return (
  121. <div className={cn("space-y-2", className)}>
  122. {errors.map((error, index) => (
  123. <div key={index} className="flex items-start gap-2 p-2 rounded-md bg-red-50 dark:bg-red-950/20 border border-red-200 dark:border-red-800">
  124. <XCircle className="h-4 w-4 text-red-500 mt-0.5 flex-shrink-0" />
  125. <p className="text-sm text-red-700 dark:text-red-300">{error}</p>
  126. </div>
  127. ))}
  128. {warnings.map((warning, index) => (
  129. <div key={index} className="flex items-start gap-2 p-2 rounded-md bg-yellow-50 dark:bg-yellow-950/20 border border-yellow-200 dark:border-yellow-800">
  130. <AlertTriangle className="h-4 w-4 text-yellow-500 mt-0.5 flex-shrink-0" />
  131. <p className="text-sm text-yellow-700 dark:text-yellow-300">{warning}</p>
  132. </div>
  133. ))}
  134. {onClearWarnings && warnings.length > 0 && (
  135. <Button
  136. variant="ghost"
  137. size="sm"
  138. onClick={onClearWarnings}
  139. className="text-xs"
  140. >
  141. Clear warnings
  142. </Button>
  143. )}
  144. </div>
  145. );
  146. }
  147. interface AutoSelectionStatusProps {
  148. isAutoSelecting: boolean;
  149. hasAutoSelection: boolean;
  150. onRetryAutoSelection?: () => void;
  151. className?: string;
  152. }
  153. export function AutoSelectionStatus({
  154. isAutoSelecting,
  155. hasAutoSelection,
  156. onRetryAutoSelection,
  157. className
  158. }: AutoSelectionStatusProps) {
  159. if (isAutoSelecting) {
  160. return (
  161. <div className={cn("flex items-center gap-2 text-sm text-blue-600 dark:text-blue-400", className)}>
  162. <div className="animate-spin">
  163. <Zap className="h-4 w-4" />
  164. </div>
  165. <span>Auto-selecting models...</span>
  166. </div>
  167. );
  168. }
  169. if (!hasAutoSelection) {
  170. return (
  171. <div className={cn("flex items-center gap-2 text-sm text-muted-foreground", className)}>
  172. <AlertCircle className="h-4 w-4" />
  173. <span>No automatic selection available</span>
  174. {onRetryAutoSelection && (
  175. <Button
  176. variant="ghost"
  177. size="sm"
  178. onClick={onRetryAutoSelection}
  179. className="h-6 px-2 text-xs"
  180. >
  181. Retry
  182. </Button>
  183. )}
  184. </div>
  185. );
  186. }
  187. return (
  188. <div className={cn("flex items-center gap-2 text-sm text-green-600 dark:text-green-400", className)}>
  189. <CheckCircle2 className="h-4 w-4" />
  190. <span>Models auto-selected</span>
  191. </div>
  192. );
  193. }