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.
@@ -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-BgapmfYp.js"></script>
8
- <link rel="stylesheet" crossorigin href="./assets/index-BN_rniiJ.css">
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
- // Normalise a base_url for dedupe comparison. Strips trailing slash and
215
- // folds case on the host. Keeps the port as-is because two distinct
216
- // daemons can run on different ports.
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
- return `${p.protocol}//${p.hostname.toLowerCase()}${p.port ? `:${p.port}` : ""}${p.pathname.replace(/\/$/, "")}`;
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 || spec.name || (port ? `local-${port}` : "local"));
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