cicy-desktop 2.1.53 → 2.1.55
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/package.json +1 -1
- package/src/backends/homepage-preload.js +1 -0
- package/src/backends/homepage-react/assets/{index-BN_rniiJ.css → index-6bY2jB5R.css} +1 -1
- package/src/backends/homepage-react/assets/{index-BgapmfYp.js → index-DO5fg2xj.js} +7 -7
- package/src/backends/homepage-react/index.html +2 -2
- package/src/backends/local-teams.js +42 -6
- package/src/main.js +1 -0
- package/workers/render/src/App.css +11 -2
- package/workers/render/src/App.jsx +13 -10
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<title>CiCy Desktop</title>
|
|
7
|
-
<script type="module" crossorigin src="./assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
7
|
+
<script type="module" crossorigin src="./assets/index-DO5fg2xj.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="./assets/index-6bY2jB5R.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
|
@@ -175,6 +175,35 @@ function stripVolatile(u) {
|
|
|
175
175
|
} catch { return u; }
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
// Reload the web content of this team's already-open window (the homepage's
|
|
179
|
+
// 刷新 action). Matches the window the same way openTeam reuses one — by
|
|
180
|
+
// origin+pathname. No-op-with-error if no window is open for the team.
|
|
181
|
+
function reloadTeam(id) {
|
|
182
|
+
const g = readGlobal();
|
|
183
|
+
const node = g?.cicyDesktopNodes?.[id];
|
|
184
|
+
if (!node) return { ok: false, error: "team not found" };
|
|
185
|
+
const baseUrl = (node.base_url || "").replace(/\/$/, "");
|
|
186
|
+
if (!baseUrl) return { ok: false, error: "no base_url" };
|
|
187
|
+
const token = node.api_token || "";
|
|
188
|
+
const url = token ? `${baseUrl}/?token=${encodeURIComponent(token)}` : baseUrl;
|
|
189
|
+
const targetKey = stripVolatile(url);
|
|
190
|
+
const win = BrowserWindow.getAllWindows().find((w) => {
|
|
191
|
+
if (!w || w.isDestroyed()) return false;
|
|
192
|
+
try { return stripVolatile(w.webContents.getURL()) === targetKey; }
|
|
193
|
+
catch { return false; }
|
|
194
|
+
});
|
|
195
|
+
if (!win) return { ok: false, error: "no_open_window" };
|
|
196
|
+
try {
|
|
197
|
+
win.webContents.reload();
|
|
198
|
+
if (win.isMinimized()) win.restore();
|
|
199
|
+
win.show(); win.focus();
|
|
200
|
+
log.info(`[local-teams] reload ${id} → win.id=${win.id}`);
|
|
201
|
+
return { ok: true, windowId: win.id };
|
|
202
|
+
} catch (e) {
|
|
203
|
+
return { ok: false, error: e.message };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
178
207
|
// ── mutations ──────────────────────────────────────────────────────────
|
|
179
208
|
//
|
|
180
209
|
// add/remove/upgrade let an external caller (currently the cloud Team
|
|
@@ -211,13 +240,15 @@ async function writeGlobal(updater) {
|
|
|
211
240
|
return next;
|
|
212
241
|
}
|
|
213
242
|
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
//
|
|
243
|
+
// Dedupe key for a team: host:port only. The same cicy-code node is the same
|
|
244
|
+
// node across platforms/protocols, so protocol, path and token never affect
|
|
245
|
+
// identity — one host:port = one team. (Was protocol+host+port+path, which
|
|
246
|
+
// treated http vs https or /a vs /b as different teams.)
|
|
217
247
|
function normaliseUrl(u) {
|
|
218
248
|
try {
|
|
219
249
|
const p = new URL(String(u || "").trim());
|
|
220
|
-
|
|
250
|
+
const port = p.port || (p.protocol === "https:" ? "443" : "80");
|
|
251
|
+
return `${p.hostname.toLowerCase()}:${port}`;
|
|
221
252
|
} catch { return ""; }
|
|
222
253
|
}
|
|
223
254
|
|
|
@@ -262,9 +293,14 @@ async function addTeam(spec) {
|
|
|
262
293
|
if (normaliseUrl(v?.base_url || "") === baseUrlKey) { existingId = k; break; }
|
|
263
294
|
}
|
|
264
295
|
|
|
296
|
+
// Derive the id from the host:port key so it CAN'T collide: two different
|
|
297
|
+
// nodes never share an id (different host:port → different slug), and the
|
|
298
|
+
// same node always hits existingId above. (Was spec.name || local-<port>,
|
|
299
|
+
// which made two hosts on the same port — or same name — overwrite each
|
|
300
|
+
// other.) An explicit spec.id still wins for callers that want to pin one.
|
|
265
301
|
const id = existingId
|
|
266
302
|
? existingId
|
|
267
|
-
: slugifyId(spec.id ||
|
|
303
|
+
: slugifyId(spec.id || baseUrlKey || (port ? `local-${port}` : "local"));
|
|
268
304
|
if (!id) return { ok: false, error: "could not derive id" };
|
|
269
305
|
|
|
270
306
|
const now = new Date().toISOString();
|
|
@@ -627,4 +663,4 @@ async function upgradeTeam(id) {
|
|
|
627
663
|
return result;
|
|
628
664
|
}
|
|
629
665
|
|
|
630
|
-
module.exports = { list, openTeam, addTeam, removeTeam, updateTeam, upgradeTeam };
|
|
666
|
+
module.exports = { list, openTeam, reloadTeam, addTeam, removeTeam, updateTeam, upgradeTeam };
|
package/src/main.js
CHANGED
|
@@ -793,6 +793,7 @@ electronApp.whenReady().then(async () => {
|
|
|
793
793
|
const { ipcMain: __ipcLT } = require("electron");
|
|
794
794
|
__ipcLT.handle("localTeams:list", (_e, opts) => lt.list(opts || {}));
|
|
795
795
|
__ipcLT.handle("localTeams:open", (_e, id) => lt.openTeam(id));
|
|
796
|
+
__ipcLT.handle("localTeams:reload", (_e, id) => lt.reloadTeam(id));
|
|
796
797
|
__ipcLT.handle("localTeams:add", (_e, spec) => lt.addTeam(spec || {}));
|
|
797
798
|
__ipcLT.handle("localTeams:remove", (_e, id) => lt.removeTeam(id));
|
|
798
799
|
__ipcLT.handle("localTeams:update", (_e, payload) => lt.updateTeam(payload?.id, payload?.patch || {}));
|
|
@@ -498,8 +498,9 @@ body {
|
|
|
498
498
|
display: flex; flex-direction: column;
|
|
499
499
|
overflow: hidden;
|
|
500
500
|
transition: transform 180ms ease, border-color 180ms ease, box-shadow 180ms ease;
|
|
501
|
-
--brand: #5b8df7;
|
|
502
|
-
--accent-cloud: #f59e0b;
|
|
501
|
+
--brand: #5b8df7; /* 本地 local */
|
|
502
|
+
--accent-cloud: #f59e0b; /* 云端 cloud */
|
|
503
|
+
--accent-custom: #8b5cf6;/* 自定义 custom (deeplink 远程节点) */
|
|
503
504
|
}
|
|
504
505
|
.bcard:hover {
|
|
505
506
|
transform: translateY(-2px);
|
|
@@ -514,6 +515,7 @@ body {
|
|
|
514
515
|
opacity: .9;
|
|
515
516
|
}
|
|
516
517
|
.bcard--cloud .bcard__accent { background: var(--accent-cloud); }
|
|
518
|
+
.bcard--custom .bcard__accent { background: var(--accent-custom); }
|
|
517
519
|
|
|
518
520
|
.bcard--online::before {
|
|
519
521
|
content: "";
|
|
@@ -527,6 +529,9 @@ body {
|
|
|
527
529
|
.bcard--cloud.bcard--online::before {
|
|
528
530
|
background: radial-gradient(circle at center, rgba(245,158,11,.22) 0%, transparent 60%);
|
|
529
531
|
}
|
|
532
|
+
.bcard--custom.bcard--online::before {
|
|
533
|
+
background: radial-gradient(circle at center, rgba(139,92,246,.22) 0%, transparent 60%);
|
|
534
|
+
}
|
|
530
535
|
|
|
531
536
|
.bcard__top {
|
|
532
537
|
display: flex; align-items: center; justify-content: space-between;
|
|
@@ -615,6 +620,10 @@ body {
|
|
|
615
620
|
background: var(--accent-cloud);
|
|
616
621
|
box-shadow: 0 4px 12px -2px rgba(245,158,11,.45);
|
|
617
622
|
}
|
|
623
|
+
.bcard--custom .bcard__cta {
|
|
624
|
+
background: var(--accent-custom);
|
|
625
|
+
box-shadow: 0 4px 12px -2px rgba(139,92,246,.45);
|
|
626
|
+
}
|
|
618
627
|
.bcard__cta:hover { filter: brightness(1.08); }
|
|
619
628
|
.bcard__cta:active { transform: translateY(1px); }
|
|
620
629
|
.bcard__cta:disabled {
|
|
@@ -548,7 +548,7 @@ function LocalTeamCard({ team, onOpen, onRename, onRefresh }) {
|
|
|
548
548
|
? tr("localTeams.startOpen", "启动并打开") // only the local sidecar can be started from here
|
|
549
549
|
: tr("localTeams.open", "打开"); // custom/remote: 探活-only, just open
|
|
550
550
|
return (
|
|
551
|
-
<div data-id="LocalTeamCard" className={`bcard bcard--local${tone === "ok" ? " bcard--online" : ""}`}>
|
|
551
|
+
<div data-id="LocalTeamCard" className={`bcard ${local ? "bcard--local" : "bcard--custom"}${tone === "ok" ? " bcard--online" : ""}`}>
|
|
552
552
|
<div className="bcard__accent" />
|
|
553
553
|
<div className="bcard__top">
|
|
554
554
|
<div className="bcard__pill">
|
|
@@ -581,6 +581,18 @@ function LocalTeamCard({ team, onOpen, onRename, onRefresh }) {
|
|
|
581
581
|
)}
|
|
582
582
|
{local && running && (
|
|
583
583
|
<>
|
|
584
|
+
<button
|
|
585
|
+
type="button"
|
|
586
|
+
data-id="LocalTeamCard-reload"
|
|
587
|
+
className="bcard__menu-item"
|
|
588
|
+
onClick={() => runOp("reload", async () => {
|
|
589
|
+
const r = await window.cicy.localTeams.reload(team.id);
|
|
590
|
+
// not open yet → open it (still a "refresh" of the team)
|
|
591
|
+
return (!r?.ok && r?.error === "no_open_window") ? window.cicy.localTeams.open(team.id) : r;
|
|
592
|
+
}, tr("localTeams.reloaded", "已刷新窗口"))}
|
|
593
|
+
>
|
|
594
|
+
{tr("localTeams.reloadWindow", "刷新窗口")}
|
|
595
|
+
</button>
|
|
584
596
|
<button
|
|
585
597
|
type="button"
|
|
586
598
|
data-id="LocalTeamCard-restart"
|
|
@@ -645,15 +657,6 @@ function LocalTeamCard({ team, onOpen, onRename, onRefresh }) {
|
|
|
645
657
|
{team.version && (
|
|
646
658
|
<span className="bcard__ver" data-id="LocalTeamCard-version">v{team.version}</span>
|
|
647
659
|
)}
|
|
648
|
-
{updateAvailable && (
|
|
649
|
-
<span
|
|
650
|
-
className="bcard__chip bcard__chip--new"
|
|
651
|
-
data-id="LocalTeamCard-newbadge"
|
|
652
|
-
title={`${tr("sidecar.updateTo", "更新到")} v${latest}`}
|
|
653
|
-
>
|
|
654
|
-
{tr("sidecar.newVersion", "新版")} v{latest}
|
|
655
|
-
</span>
|
|
656
|
-
)}
|
|
657
660
|
</div>
|
|
658
661
|
</div>
|
|
659
662
|
<button
|