@geminilight/mindos 0.5.66 → 0.5.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/app/app/layout.tsx
CHANGED
|
@@ -7,7 +7,6 @@ import { TooltipProvider } from '@/components/ui/tooltip';
|
|
|
7
7
|
import { LocaleProvider } from '@/lib/LocaleContext';
|
|
8
8
|
import ErrorBoundary from '@/components/ErrorBoundary';
|
|
9
9
|
import RegisterSW from './register-sw';
|
|
10
|
-
import UpdateBanner from '@/components/UpdateBanner';
|
|
11
10
|
import UpdateOverlay from '@/components/UpdateOverlay';
|
|
12
11
|
import { cookies } from 'next/headers';
|
|
13
12
|
import type { Locale } from '@/lib/i18n';
|
|
@@ -107,7 +106,6 @@ export default async function RootLayout({
|
|
|
107
106
|
suppressHydrationWarning
|
|
108
107
|
>
|
|
109
108
|
<LocaleProvider ssrLocale={ssrLocale}>
|
|
110
|
-
<UpdateBanner />
|
|
111
109
|
<TooltipProvider delay={300}>
|
|
112
110
|
<ErrorBoundary>
|
|
113
111
|
<ShellLayout fileTree={fileTree}>
|
|
@@ -89,26 +89,48 @@ export default function ActivityBar({
|
|
|
89
89
|
const syncBtnRef = useRef<HTMLButtonElement>(null);
|
|
90
90
|
const { t } = useLocale();
|
|
91
91
|
|
|
92
|
-
// Update
|
|
93
|
-
const [hasUpdate, setHasUpdate] = useState(
|
|
94
|
-
|
|
92
|
+
// Update badge: Desktop → electron-updater IPC; Browser → npm registry check
|
|
93
|
+
const [hasUpdate, setHasUpdate] = useState(false);
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
const bridge = typeof window !== 'undefined'
|
|
96
|
+
? (window as unknown as { mindos?: { checkUpdate?: () => Promise<{ available: boolean }>; onUpdateAvailable?: (cb: () => void) => () => void } }).mindos
|
|
97
|
+
: undefined;
|
|
98
|
+
|
|
99
|
+
if (bridge?.checkUpdate) {
|
|
100
|
+
const doCheck = bridge.checkUpdate.bind(bridge);
|
|
101
|
+
const timer = setTimeout(async () => {
|
|
102
|
+
try {
|
|
103
|
+
const r = await doCheck();
|
|
104
|
+
if (r.available) setHasUpdate(true);
|
|
105
|
+
} catch { /* silent */ }
|
|
106
|
+
}, 10_000);
|
|
107
|
+
const cleanup = bridge.onUpdateAvailable?.(() => setHasUpdate(true));
|
|
108
|
+
return () => { clearTimeout(timer); cleanup?.(); };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Browser/CLI: check npm registry
|
|
95
112
|
const dismissed = localStorage.getItem('mindos_update_dismissed');
|
|
96
113
|
const latest = localStorage.getItem('mindos_update_latest');
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
114
|
+
if (latest && latest !== dismissed) { setHasUpdate(true); return; }
|
|
115
|
+
const timer = setTimeout(async () => {
|
|
116
|
+
try {
|
|
117
|
+
const res = await fetch('/api/update-check');
|
|
118
|
+
if (!res.ok) return;
|
|
119
|
+
const data = await res.json();
|
|
120
|
+
if (!data.hasUpdate) {
|
|
121
|
+
localStorage.removeItem('mindos_update_latest');
|
|
122
|
+
localStorage.removeItem('mindos_update_dismissed');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const d = localStorage.getItem('mindos_update_dismissed');
|
|
126
|
+
if (data.latest === d) return;
|
|
127
|
+
localStorage.setItem('mindos_update_latest', data.latest);
|
|
128
|
+
setHasUpdate(true);
|
|
129
|
+
} catch { /* silent */ }
|
|
130
|
+
}, 5000);
|
|
105
131
|
const onDismiss = () => setHasUpdate(false);
|
|
106
|
-
window.addEventListener('mindos:update-available', onAvail);
|
|
107
132
|
window.addEventListener('mindos:update-dismissed', onDismiss);
|
|
108
|
-
return () => {
|
|
109
|
-
window.removeEventListener('mindos:update-available', onAvail);
|
|
110
|
-
window.removeEventListener('mindos:update-dismissed', onDismiss);
|
|
111
|
-
};
|
|
133
|
+
return () => { clearTimeout(timer); window.removeEventListener('mindos:update-dismissed', onDismiss); };
|
|
112
134
|
}, []);
|
|
113
135
|
|
|
114
136
|
/** Debounce rapid clicks (300ms) — shared across all Rail buttons */
|
package/package.json
CHANGED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useState, useEffect } from 'react';
|
|
4
|
-
import { X } from 'lucide-react';
|
|
5
|
-
import { useLocale } from '@/lib/LocaleContext';
|
|
6
|
-
import { apiFetch } from '@/lib/api';
|
|
7
|
-
|
|
8
|
-
interface UpdateInfo {
|
|
9
|
-
current: string;
|
|
10
|
-
latest: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default function UpdateBanner() {
|
|
14
|
-
const { t } = useLocale();
|
|
15
|
-
const [info, setInfo] = useState<UpdateInfo | null>(null);
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
if (typeof window !== 'undefined') {
|
|
19
|
-
const path = window.location.pathname;
|
|
20
|
-
if (path === '/setup' || path === '/login') return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const timer = setTimeout(async () => {
|
|
24
|
-
try {
|
|
25
|
-
const data = await apiFetch<{ hasUpdate: boolean; latest: string; current: string }>('/api/update-check');
|
|
26
|
-
if (!data.hasUpdate) {
|
|
27
|
-
// Clean up stale badge state from a previous update cycle
|
|
28
|
-
if (localStorage.getItem('mindos_update_latest')) {
|
|
29
|
-
localStorage.removeItem('mindos_update_latest');
|
|
30
|
-
localStorage.removeItem('mindos_update_dismissed');
|
|
31
|
-
window.dispatchEvent(new Event('mindos:update-dismissed'));
|
|
32
|
-
}
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const dismissed = localStorage.getItem('mindos_update_dismissed');
|
|
37
|
-
if (data.latest === dismissed) return;
|
|
38
|
-
|
|
39
|
-
setInfo({ latest: data.latest, current: data.current });
|
|
40
|
-
// Broadcast for ActivityBar & Settings tab badges
|
|
41
|
-
window.dispatchEvent(new CustomEvent('mindos:update-available', { detail: { latest: data.latest } }));
|
|
42
|
-
} catch {
|
|
43
|
-
// Network error / API failure — silent
|
|
44
|
-
}
|
|
45
|
-
}, 3000);
|
|
46
|
-
|
|
47
|
-
return () => clearTimeout(timer);
|
|
48
|
-
}, []);
|
|
49
|
-
|
|
50
|
-
if (!info) return null;
|
|
51
|
-
|
|
52
|
-
const handleDismiss = () => {
|
|
53
|
-
localStorage.setItem('mindos_update_dismissed', info.latest);
|
|
54
|
-
setInfo(null);
|
|
55
|
-
window.dispatchEvent(new Event('mindos:update-dismissed'));
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const handleOpenUpdate = () => {
|
|
59
|
-
window.dispatchEvent(new CustomEvent('mindos:open-settings', { detail: { tab: 'update' } }));
|
|
60
|
-
localStorage.setItem('mindos_update_dismissed', info.latest);
|
|
61
|
-
setInfo(null);
|
|
62
|
-
window.dispatchEvent(new Event('mindos:update-dismissed'));
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const u = t.updateBanner;
|
|
66
|
-
|
|
67
|
-
return (
|
|
68
|
-
<div className="flex items-center justify-between gap-3 px-4 py-2 text-xs bg-[var(--amber-subtle)] border-b border-border">
|
|
69
|
-
<div className="flex items-center gap-2 min-w-0 flex-wrap">
|
|
70
|
-
<span className="font-medium text-[var(--amber)]">
|
|
71
|
-
{u?.newVersion
|
|
72
|
-
? u.newVersion(info.latest, info.current)
|
|
73
|
-
: `MindOS v${info.latest} available (current: v${info.current})`}
|
|
74
|
-
</span>
|
|
75
|
-
<button
|
|
76
|
-
onClick={handleOpenUpdate}
|
|
77
|
-
className="px-2 py-0.5 rounded-md text-xs font-medium bg-[var(--amber)] text-white transition-colors hover:opacity-90"
|
|
78
|
-
>
|
|
79
|
-
{u?.updateNow ?? 'Update'}
|
|
80
|
-
</button>
|
|
81
|
-
<a
|
|
82
|
-
href="https://github.com/GeminiLight/mindos/releases"
|
|
83
|
-
target="_blank"
|
|
84
|
-
rel="noopener noreferrer"
|
|
85
|
-
className="text-muted-foreground underline hover:text-foreground transition-colors hidden sm:inline"
|
|
86
|
-
>
|
|
87
|
-
{u?.releaseNotes ?? 'Release notes'}
|
|
88
|
-
</a>
|
|
89
|
-
</div>
|
|
90
|
-
<button
|
|
91
|
-
onClick={handleDismiss}
|
|
92
|
-
className="p-0.5 rounded hover:bg-muted transition-colors shrink-0 text-muted-foreground"
|
|
93
|
-
title="Dismiss"
|
|
94
|
-
>
|
|
95
|
-
<X size={14} />
|
|
96
|
-
</button>
|
|
97
|
-
</div>
|
|
98
|
-
);
|
|
99
|
-
}
|