@aion0/forge 0.2.21 → 0.2.22
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/api/version/route.ts +19 -3
- package/components/Dashboard.tsx +17 -36
- package/package.json +1 -1
package/app/api/version/route.ts
CHANGED
|
@@ -12,9 +12,12 @@ const CURRENT_VERSION = (() => {
|
|
|
12
12
|
}
|
|
13
13
|
})();
|
|
14
14
|
|
|
15
|
-
// Cache npm version check for
|
|
15
|
+
// Cache npm version check for 10 minutes
|
|
16
16
|
let cachedLatest: { version: string; checkedAt: number } | null = null;
|
|
17
|
-
const CACHE_TTL = 10 * 60 * 1000;
|
|
17
|
+
const CACHE_TTL = 10 * 60 * 1000;
|
|
18
|
+
|
|
19
|
+
// Track which versions we already notified about (avoid duplicates)
|
|
20
|
+
let notifiedVersion = '';
|
|
18
21
|
|
|
19
22
|
async function getLatestVersion(force = false): Promise<string> {
|
|
20
23
|
if (!force && cachedLatest && Date.now() - cachedLatest.checkedAt < CACHE_TTL) {
|
|
@@ -52,7 +55,20 @@ export async function GET(req: Request) {
|
|
|
52
55
|
const force = searchParams.has('force');
|
|
53
56
|
const current = CURRENT_VERSION;
|
|
54
57
|
const latest = await getLatestVersion(force);
|
|
55
|
-
const hasUpdate = latest && compareVersions(current, latest) < 0;
|
|
58
|
+
const hasUpdate = !!(latest && compareVersions(current, latest) < 0);
|
|
59
|
+
|
|
60
|
+
// Create a notification when new version is detected (once per version)
|
|
61
|
+
if (hasUpdate && latest !== notifiedVersion) {
|
|
62
|
+
notifiedVersion = latest;
|
|
63
|
+
try {
|
|
64
|
+
const { addNotification } = require('@/lib/notifications');
|
|
65
|
+
addNotification(
|
|
66
|
+
'system',
|
|
67
|
+
`Update available: v${latest}`,
|
|
68
|
+
`Current: v${current}. Run: forge upgrade`,
|
|
69
|
+
);
|
|
70
|
+
} catch {}
|
|
71
|
+
}
|
|
56
72
|
|
|
57
73
|
return NextResponse.json({
|
|
58
74
|
current,
|
package/components/Dashboard.tsx
CHANGED
|
@@ -51,8 +51,6 @@ export default function Dashboard({ user }: { user: any }) {
|
|
|
51
51
|
const [projects, setProjects] = useState<ProjectInfo[]>([]);
|
|
52
52
|
const [onlineCount, setOnlineCount] = useState<{ total: number; remote: number }>({ total: 0, remote: 0 });
|
|
53
53
|
const [versionInfo, setVersionInfo] = useState<{ current: string; latest: string; hasUpdate: boolean } | null>(null);
|
|
54
|
-
const [upgrading, setUpgrading] = useState(false);
|
|
55
|
-
const [upgradeResult, setUpgradeResult] = useState<string | null>(null);
|
|
56
54
|
const [notifications, setNotifications] = useState<any[]>([]);
|
|
57
55
|
const [unreadCount, setUnreadCount] = useState(0);
|
|
58
56
|
const [showNotifications, setShowNotifications] = useState(false);
|
|
@@ -127,43 +125,26 @@ export default function Dashboard({ user }: { user: any }) {
|
|
|
127
125
|
{versionInfo && (
|
|
128
126
|
<span className="flex items-center gap-1.5">
|
|
129
127
|
<span className="text-[10px] text-[var(--text-secondary)]">v{versionInfo.current}</span>
|
|
130
|
-
{versionInfo.hasUpdate &&
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
setUpgrading(true);
|
|
135
|
-
try {
|
|
136
|
-
const res = await fetch('/api/upgrade', { method: 'POST' });
|
|
137
|
-
const data = await res.json();
|
|
138
|
-
setUpgradeResult(data.ok ? data.message : data.error);
|
|
139
|
-
if (data.ok) setVersionInfo(v => v ? { ...v, hasUpdate: false } : v);
|
|
140
|
-
} catch { setUpgradeResult('Upgrade failed'); }
|
|
141
|
-
setUpgrading(false);
|
|
142
|
-
}}
|
|
143
|
-
className="text-[9px] px-1.5 py-0.5 bg-[var(--accent)] text-white rounded hover:opacity-90 disabled:opacity-50"
|
|
144
|
-
title={`Update to v${versionInfo.latest}\nOr run: forge upgrade`}
|
|
128
|
+
{versionInfo.hasUpdate && (
|
|
129
|
+
<span
|
|
130
|
+
className="text-[9px] px-1.5 py-0.5 bg-[var(--accent)]/15 text-[var(--accent)] rounded cursor-default"
|
|
131
|
+
title="Run: forge upgrade"
|
|
145
132
|
>
|
|
146
|
-
|
|
147
|
-
</button>
|
|
148
|
-
)}
|
|
149
|
-
{!versionInfo.hasUpdate && !upgradeResult && (
|
|
150
|
-
<button
|
|
151
|
-
onClick={async () => {
|
|
152
|
-
const res = await fetch('/api/version?force=1');
|
|
153
|
-
const data = await res.json();
|
|
154
|
-
setVersionInfo(data);
|
|
155
|
-
}}
|
|
156
|
-
className="text-[9px] px-1 py-0.5 text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
|
|
157
|
-
title="Check for updates"
|
|
158
|
-
>
|
|
159
|
-
↻
|
|
160
|
-
</button>
|
|
161
|
-
)}
|
|
162
|
-
{upgradeResult && (
|
|
163
|
-
<span className="text-[9px] text-[var(--green)] max-w-[200px] truncate" title={upgradeResult}>
|
|
164
|
-
{upgradeResult}
|
|
133
|
+
v{versionInfo.latest} available
|
|
165
134
|
</span>
|
|
166
135
|
)}
|
|
136
|
+
<button
|
|
137
|
+
onClick={async () => {
|
|
138
|
+
const res = await fetch('/api/version?force=1');
|
|
139
|
+
const data = await res.json();
|
|
140
|
+
setVersionInfo(data);
|
|
141
|
+
if (data.hasUpdate) fetchNotifications();
|
|
142
|
+
}}
|
|
143
|
+
className="text-[9px] px-1 py-0.5 text-[var(--text-secondary)] hover:text-[var(--text-primary)]"
|
|
144
|
+
title="Check for updates"
|
|
145
|
+
>
|
|
146
|
+
↻
|
|
147
|
+
</button>
|
|
167
148
|
</span>
|
|
168
149
|
)}
|
|
169
150
|
|
package/package.json
CHANGED