groove-dev 0.27.188 → 0.27.189
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/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/gui/dist/assets/{index-fyGUwOq4.js → index-DTY0KsH9.js} +2 -2
- package/node_modules/@groove-dev/gui/dist/index.html +1 -1
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/App.jsx +51 -2
- package/node_modules/@groove-dev/gui/src/stores/groove.js +13 -0
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/gui/dist/assets/{index-fyGUwOq4.js → index-DTY0KsH9.js} +2 -2
- package/packages/gui/dist/index.html +1 -1
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/App.jsx +51 -2
- package/packages/gui/src/stores/groove.js +13 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
|
8
8
|
<title>Groove GUI</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-DTY0KsH9.js"></script>
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/vendor-26L3JoZv.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/reactflow-DoBZjiHE.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/codemirror-BYKpdS2W.js">
|
package/packages/gui/src/App.jsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// GROOVE GUI v2 — App Root
|
|
2
2
|
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
3
3
|
|
|
4
|
-
import React, { useEffect, useMemo } from 'react';
|
|
4
|
+
import React, { useEffect, useMemo, useState, useRef } from 'react';
|
|
5
5
|
import { useGrooveStore } from './stores/groove';
|
|
6
6
|
import { AppShell } from './components/layout/app-shell';
|
|
7
7
|
import { SetupWizard } from './components/onboarding/setup-wizard';
|
|
@@ -133,10 +133,59 @@ function TunneledFolderPicker() {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
function LoadingScreen() {
|
|
136
|
+
const connected = useGrooveStore((s) => s.connected);
|
|
137
|
+
const [slow, setSlow] = useState(false);
|
|
138
|
+
const [reconnecting, setReconnecting] = useState(false);
|
|
139
|
+
const triedRef = useRef(false);
|
|
140
|
+
|
|
141
|
+
// If we haven't come up within a few seconds, the connection (or the SSH
|
|
142
|
+
// tunnel behind it) is likely stalled — surface a reload rather than an
|
|
143
|
+
// endless pulse the user can't act on.
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
const t = setTimeout(() => setSlow(true), 6000);
|
|
146
|
+
return () => clearTimeout(t);
|
|
147
|
+
}, []);
|
|
148
|
+
|
|
149
|
+
// If the socket can't even open (not just un-hydrated), the tunnel behind it
|
|
150
|
+
// is probably dead — ask the desktop shell to re-establish it. Once only, and
|
|
151
|
+
// only when disconnected, so a merely-slow load isn't disturbed.
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (!slow || connected || triedRef.current) return;
|
|
154
|
+
if (!window.groove?.reconnect) return;
|
|
155
|
+
triedRef.current = true;
|
|
156
|
+
setReconnecting(true);
|
|
157
|
+
window.groove.reconnect().catch(() => {}).finally(() => setReconnecting(false));
|
|
158
|
+
}, [slow, connected]);
|
|
159
|
+
|
|
160
|
+
async function manualReconnect() {
|
|
161
|
+
if (window.groove?.reconnect) {
|
|
162
|
+
setReconnecting(true);
|
|
163
|
+
try { await window.groove.reconnect(); } catch { /* falls through to reload */ }
|
|
164
|
+
setReconnecting(false);
|
|
165
|
+
}
|
|
166
|
+
window.location.reload();
|
|
167
|
+
}
|
|
168
|
+
|
|
136
169
|
return (
|
|
137
170
|
<div className="h-screen bg-surface-0 flex flex-col items-center justify-center gap-4">
|
|
138
171
|
<img src="/favicon.png" alt="" className="w-10 h-10 opacity-60 animate-pulse" />
|
|
139
|
-
<p className="text-sm text-text-3 font-sans">
|
|
172
|
+
<p className="text-sm text-text-3 font-sans">
|
|
173
|
+
{reconnecting ? 'Re-establishing connection…' : connected ? 'Loading…' : 'Connecting to daemon…'}
|
|
174
|
+
</p>
|
|
175
|
+
{slow && (
|
|
176
|
+
<div className="flex flex-col items-center gap-2 mt-1">
|
|
177
|
+
<p className="text-xs text-text-4 font-sans max-w-xs text-center">
|
|
178
|
+
Still trying to reach the daemon. If you just woke your machine, the connection is re-establishing.
|
|
179
|
+
</p>
|
|
180
|
+
<button
|
|
181
|
+
onClick={manualReconnect}
|
|
182
|
+
disabled={reconnecting}
|
|
183
|
+
className="px-3 py-1.5 rounded-md text-xs font-medium font-sans border border-accent/40 bg-accent/10 text-accent hover:bg-accent/20 disabled:opacity-50 transition-colors cursor-pointer"
|
|
184
|
+
>
|
|
185
|
+
{reconnecting ? 'Reconnecting…' : 'Reconnect'}
|
|
186
|
+
</button>
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
140
189
|
</div>
|
|
141
190
|
);
|
|
142
191
|
}
|
|
@@ -1146,3 +1146,16 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
1146
1146
|
ws.onerror = () => ws.close();
|
|
1147
1147
|
},
|
|
1148
1148
|
}));
|
|
1149
|
+
|
|
1150
|
+
// Reconnect promptly when connectivity returns — laptop wake, network back, or
|
|
1151
|
+
// the window regaining focus — instead of waiting out the periodic 2s retry.
|
|
1152
|
+
// connect() no-ops if a socket already exists, so these are safe to fire often.
|
|
1153
|
+
if (typeof window !== 'undefined') {
|
|
1154
|
+
const kick = () => {
|
|
1155
|
+
const s = useGrooveStore.getState();
|
|
1156
|
+
if (!s.ws) s.connect();
|
|
1157
|
+
};
|
|
1158
|
+
window.addEventListener('online', kick);
|
|
1159
|
+
window.addEventListener('focus', kick);
|
|
1160
|
+
document.addEventListener('visibilitychange', () => { if (!document.hidden) kick(); });
|
|
1161
|
+
}
|