@takagaki/cortex-decisions-viewer 0.4.68 → 0.4.69

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.
Files changed (2) hide show
  1. package/dist/render.js +83 -7
  2. package/package.json +1 -1
package/dist/render.js CHANGED
@@ -1095,6 +1095,20 @@ a.ds-name:hover { text-decoration: underline; }
1095
1095
  /* URLは長いので、入力欄を伸ばしてボタンを右に置く(折り返しても崩れないように wrap) */
1096
1096
  .rt-url-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
1097
1097
  .rt-url { flex: 1 1 260px; margin-bottom: 0; font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 12px; }
1098
+ /* 稼働中の表示(#123)。緑は「動いている」の合図で、見出しの右に置いて先に目に入れる */
1099
+ .rt-live-badge {
1100
+ margin-left: auto; flex: 0 0 auto; padding: 3px 10px; border-radius: 999px;
1101
+ background: #e8f6ed; border: 1px solid #b7e0c6; color: #1c7a43;
1102
+ font-size: 12px; font-weight: 700; white-space: nowrap;
1103
+ }
1104
+ .rt-live-lines { display: flex; flex-direction: column; gap: 4px; }
1105
+ .rt-live-line { margin: 0; color: var(--text); font-size: 13px; font-weight: 600; }
1106
+ /* まだ受信していない接続先(複数接続のとき混在する)。稼働中の行と見分けが付く濃さに落とす */
1107
+ .rt-live-line.is-waiting { color: var(--muted); font-weight: 500; }
1108
+ /* 手順は畳んで残す(張り替え・再確認用)。開いたときだけ間隔を空ける */
1109
+ .rt-steps-fold > summary { cursor: pointer; color: var(--muted); font-size: 12px; }
1110
+ .rt-steps-fold[open] > summary { margin-bottom: 10px; }
1111
+ .rt-steps-fold[open] > *:not(summary) { margin-top: 10px; }
1098
1112
  .ops-card-head { display: flex; align-items: center; gap: 10px; }
1099
1113
  .ops-card-icon { font-size: 22px; line-height: 1; }
1100
1114
  .ops-card-title { font-size: 15px; font-weight: 700; color: var(--text); margin: 0; }
@@ -1704,6 +1718,22 @@ ${capabilityState.toString()}
1704
1718
  var mm = ("0" + d.getMinutes()).slice(-2);
1705
1719
  return (d.getMonth() + 1) + "/" + d.getDate() + " " + hh + ":" + mm;
1706
1720
  }
1721
+ /**
1722
+ * 「いつだったか」を相対で言う(#123)。読めない値は空文字(呼び側が出し分けを切る)。
1723
+ *
1724
+ * **1日以上前は絶対時刻に切り替える。** 「32日前」は数えないと日付にならないし、
1725
+ * そこまで空いていれば知りたいのは「いつ止まったか」のほう。
1726
+ * 未来の時刻(端末とサーバの時計ずれ)は「たった今」に丸める——「-3分前」を出さない。
1727
+ */
1728
+ function rtAgo(iso) {
1729
+ var d = new Date(iso);
1730
+ if (isNaN(d.getTime())) return "";
1731
+ var min = Math.floor((Date.now() - d.getTime()) / 60000);
1732
+ if (min < 1) return "たった今";
1733
+ if (min < 60) return min + "分前";
1734
+ if (min < 60 * 24) return Math.floor(min / 60) + "時間前";
1735
+ return dsFmtTime(iso);
1736
+ }
1707
1737
  // 名前表示: url があれば新しいタブで正本を開くリンクにする
1708
1738
  function dsNameEl(text, url) {
1709
1739
  if (url) return el("a", { class: "ds-name", href: url, target: "_blank", rel: "noopener", text: text });
@@ -3433,6 +3463,10 @@ ${capabilityState.toString()}
3433
3463
  *
3434
3464
  * **URLに載せるトークンは案件別**(SITE.backlogWebhook)。艦隊共通トークンを載せると、
3435
3465
  * この画面を見られる人が全案件ぶんの偽イベントを投げられる(types.ts の backlogWebhook 参照)。
3466
+ *
3467
+ * **既に回っている案件には、手順より先に「動いている」ことを出す(#123)。** 設定手順は
3468
+ * まだ繋いでいない人のためのもので、繋ぎ終わった案件の担当者が知りたいのは
3469
+ * 「ちゃんと届いているか」。手順は畳んで残す(URLの再確認・張り替えに要る)。
3436
3470
  */
3437
3471
  function realtimeSyncCard() {
3438
3472
  var rt = LIVE_REALTIME;
@@ -3446,6 +3480,13 @@ ${capabilityState.toString()}
3446
3480
  var wh = SITE.backlogWebhook;
3447
3481
  if (!rt.ready || !wh || !wh.url || !wh.token) return null;
3448
3482
  var url = wh.url + (wh.url.indexOf("?") === -1 ? "?" : "&") + "t=" + encodeURIComponent(wh.token);
3483
+ // 接続先ごとの受信実績(#123)。**配列で受ける**——1案件=複数 Backlog プロジェクトは
3484
+ // 確定した将来要件(#107)で、今日は必ず1件。**時刻が読めない値は稼働中に数えない**
3485
+ // ——「最終受信: NaN分前」を出すくらいなら、未設定と同じ手順の画面のほうがまだ読める
3486
+ var targets = (rt.targets || []).map(function (t) {
3487
+ return { projectKey: t && t.projectKey ? String(t.projectKey) : "", ago: t && t.lastEventAt ? rtAgo(t.lastEventAt) : "" };
3488
+ });
3489
+ var live = targets.some(function (t) { return t.ago; });
3449
3490
 
3450
3491
  // URLは**選択できる形**で出す(コピーボタンが使えない環境でも手で取れるように)
3451
3492
  var field = el("input", { class: "sec-input rt-url", type: "text", readonly: "readonly", spellcheck: "false" });
@@ -3472,12 +3513,8 @@ ${capabilityState.toString()}
3472
3513
  } catch (e) { fallback(); }
3473
3514
  });
3474
3515
 
3475
- return el("div", { class: "ops-card rt-card" }, [
3476
- el("div", { class: "ops-card-head" }, [
3477
- el("span", { class: "ops-card-icon", text: "⚡" }),
3478
- el("h3", { class: "ops-card-title", text: "リアルタイム同期" }),
3479
- ]),
3480
- el("p", { class: "ops-card-desc", text: "Backlog で課題やコメントが変わったときに、その内容をすぐ取り込みます(毎晩の同期を待たずに反映されます)。Backlog 側で一度だけ設定してください。" }),
3516
+ // 手順ひとそろい(貼り付け先・URL・注意書き)。稼働中の案件ではこれを畳む
3517
+ var steps = [
3481
3518
  el("ol", { class: "rt-steps" }, [
3482
3519
  el("li", { text: "Backlog のプロジェクト設定 → インテグレーション → Webhook を開く" }),
3483
3520
  el("li", { text: "「WebHook URL」に下の案件専用URLを貼り付ける" }),
@@ -3488,7 +3525,46 @@ ${capabilityState.toString()}
3488
3525
  // **この画面は顧客も見る。** URLに秘密が入っていることと、その扱いを書いておく
3489
3526
  el("p", { class: "sec-note", text: "このURLはこの案件専用です(他の案件には届きません)。秘密のトークンを含むので、貼り付け先は Backlog のこのプロジェクトの設定欄だけにしてください。" }),
3490
3527
  el("p", { class: "sec-how", text: "反映は受信から約1分後です(1分ごとのミニバッチでまとめて取り込みます)。初回は上の接続先の設定と、夜間同期が一度済んでいることが前提になります。" }),
3491
- ]);
3528
+ ];
3529
+
3530
+ if (live) {
3531
+ // 稼働中。**先頭は状態、手順は畳む。**「畳んである中に何があるか」を summary に書く
3532
+ // ——ただの「詳細」だと、URLを張り替えたい人がここを開く手掛かりを持てない
3533
+ var det = el("details", { class: "rt-steps-fold" }, [
3534
+ el("summary", { text: "設定手順と案件専用URLを表示(URLの再確認・張り替え用)" }),
3535
+ ]);
3536
+ for (var i = 0; i < steps.length; i++) det.appendChild(steps[i]);
3537
+ // 接続先ごとに1行。**1件のときはプロジェクトキーを出さない**——どれのことかは
3538
+ // 自明なので、キーを添えると「他にもあるのか」と読ませる余計な情報になる。
3539
+ // 複数のときは、どの接続先の話かが分からないと行が読めないので必ず添える
3540
+ var lines = el("div", { class: "rt-live-lines" }, targets.map(function (t) {
3541
+ var label = targets.length > 1 && t.projectKey ? t.projectKey + ": " : "";
3542
+ // 受信実績がまだ無い接続先も**黙って落とさない**。1つでも動いていれば
3543
+ // カードは稼働中の形になるので、落とすと「増やした接続先が来ていない」に気づけない
3544
+ return el("p", {
3545
+ class: t.ago ? "rt-live-line" : "rt-live-line is-waiting",
3546
+ text: t.ago ? label + "最終受信: " + t.ago : label + "まだ受信していません",
3547
+ });
3548
+ }));
3549
+ return el("div", { class: "ops-card rt-card is-live" }, [
3550
+ el("div", { class: "ops-card-head" }, [
3551
+ el("span", { class: "ops-card-icon", text: "⚡" }),
3552
+ el("h3", { class: "ops-card-title", text: "リアルタイム同期" }),
3553
+ el("span", { class: "rt-live-badge", text: "✓ 稼働中" }),
3554
+ ]),
3555
+ lines,
3556
+ el("p", { class: "ops-card-desc", text: "Backlog の変更をすぐ取り込んでいます(毎晩の同期を待ちません)。設定は済んでいるので、このままお使いください。" }),
3557
+ det,
3558
+ ]);
3559
+ }
3560
+
3561
+ return el("div", { class: "ops-card rt-card" }, [
3562
+ el("div", { class: "ops-card-head" }, [
3563
+ el("span", { class: "ops-card-icon", text: "⚡" }),
3564
+ el("h3", { class: "ops-card-title", text: "リアルタイム同期" }),
3565
+ ]),
3566
+ el("p", { class: "ops-card-desc", text: "Backlog で課題やコメントが変わったときに、その内容をすぐ取り込みます(毎晩の同期を待たずに反映されます)。Backlog 側で一度だけ設定してください。" }),
3567
+ ].concat(steps));
3492
3568
  }
3493
3569
 
3494
3570
  /** 鍵の入力欄に出す説明。kind は Lambda 側(resolveSecretTarget)と綴りを合わせること */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.4.68",
3
+ "version": "0.4.69",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,