version-checker.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. 'use client';
  2. import { useState, useEffect } from 'react';
  3. import { AlertCircle, RefreshCw, Info } from 'lucide-react';
  4. import { Button } from '@/components/ui/button';
  5. import { getVersion, VersionInfo } from '@/lib/api';
  6. export function VersionChecker() {
  7. const [currentVersion, setCurrentVersion] = useState<string | null>(null);
  8. const [serverVersion, setServerVersion] = useState<VersionInfo | null>(null);
  9. const [showUpdate, setShowUpdate] = useState(false);
  10. const [loading, setLoading] = useState(true);
  11. useEffect(() => {
  12. // Get initial version from version.json
  13. const loadCurrentVersion = async () => {
  14. try {
  15. const response = await fetch('/ui/version.json', {
  16. cache: 'no-store' // Always fetch fresh version
  17. });
  18. if (response.ok) {
  19. const data = await response.json();
  20. setCurrentVersion(data.version);
  21. }
  22. } catch (error) {
  23. console.warn('Failed to load UI version:', error);
  24. } finally {
  25. setLoading(false);
  26. }
  27. };
  28. loadCurrentVersion();
  29. }, []);
  30. useEffect(() => {
  31. // Check server version periodically (every 5 minutes)
  32. const checkVersion = async () => {
  33. try {
  34. const versionInfo = await getVersion();
  35. setServerVersion(versionInfo);
  36. // If we have both versions and they don't match, show update notification
  37. if (currentVersion && versionInfo.version !== currentVersion) {
  38. setShowUpdate(true);
  39. }
  40. } catch (error) {
  41. console.warn('Failed to check server version:', error);
  42. }
  43. };
  44. // Initial check after 2 seconds
  45. const initialTimeout = setTimeout(checkVersion, 2000);
  46. // Periodic check every 5 minutes
  47. const interval = setInterval(checkVersion, 5 * 60 * 1000);
  48. return () => {
  49. clearTimeout(initialTimeout);
  50. clearInterval(interval);
  51. };
  52. }, [currentVersion]);
  53. const handleRefresh = () => {
  54. // Force reload to get new version
  55. window.location.reload();
  56. };
  57. if (loading || !serverVersion) {
  58. return null;
  59. }
  60. // Version badge display (always visible in footer/header)
  61. const VersionBadge = () => (
  62. <div className="flex items-center gap-2 text-xs text-muted-foreground">
  63. <Info className="h-3 w-3" />
  64. <span>v{serverVersion.version}</span>
  65. {!serverVersion.clean && <span className="text-amber-500">*</span>}
  66. </div>
  67. );
  68. // Update notification overlay
  69. if (showUpdate) {
  70. return (
  71. <>
  72. <VersionBadge />
  73. <div className="fixed top-4 left-1/2 transform -translate-x-1/2 z-50 animate-in slide-in-from-top duration-300">
  74. <div className="bg-amber-500 dark:bg-amber-600 text-white px-4 py-3 rounded-lg shadow-lg flex items-center gap-3 max-w-md">
  75. <AlertCircle className="h-5 w-5 flex-shrink-0" />
  76. <div className="flex-1">
  77. <p className="font-semibold">New UI Version Available</p>
  78. <p className="text-sm opacity-90">
  79. A new version of UI has been deployed. Current: {currentVersion}, Server: {serverVersion.version}.
  80. Refresh to get latest updates.
  81. </p>
  82. </div>
  83. <Button
  84. size="sm"
  85. variant="secondary"
  86. onClick={handleRefresh}
  87. className="flex-shrink-0"
  88. >
  89. <RefreshCw className="h-4 w-4 mr-1" />
  90. Refresh
  91. </Button>
  92. </div>
  93. </div>
  94. </>
  95. );
  96. }
  97. return <VersionBadge />;
  98. }