@takagaki/cortex-decisions-viewer 0.4.44 → 0.4.45
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/dist/build.js +7 -2
- package/dist/render.js +51 -6
- package/package.json +1 -1
package/dist/build.js
CHANGED
|
@@ -135,6 +135,9 @@ async function readFleetSources(repoRoot) {
|
|
|
135
135
|
ref: s.ref != null ? String(s.ref) : undefined,
|
|
136
136
|
url: s.url != null ? String(s.url) : undefined,
|
|
137
137
|
gold: typeof s.gold === "boolean" ? s.gold : undefined,
|
|
138
|
+
// goldState は gold の理由。`gold: false` だけだと「意図的に外した」「宣言し忘れ」
|
|
139
|
+
// 「exclude による除外」が同じ値になり、**正常な除外にまで警告を出して麻痺する**。
|
|
140
|
+
goldState: s.goldState != null ? String(s.goldState) : undefined,
|
|
138
141
|
notify: typeof s.notify === "boolean" ? s.notify : undefined,
|
|
139
142
|
gate: s.gate != null ? String(s.gate) : undefined,
|
|
140
143
|
}))
|
|
@@ -178,7 +181,8 @@ async function readFleetSources(repoRoot) {
|
|
|
178
181
|
if (!Object.keys(tools).length)
|
|
179
182
|
tools = undefined;
|
|
180
183
|
}
|
|
181
|
-
|
|
184
|
+
const fleetGeneratedAt = typeof obj.generatedAt === "string" ? obj.generatedAt : undefined;
|
|
185
|
+
return { externalSources, internalSources, pipelines, tools, fleetGeneratedAt };
|
|
182
186
|
}
|
|
183
187
|
/** パスがディレクトリとして存在するか */
|
|
184
188
|
async function isDirectory(dirAbs) {
|
|
@@ -667,7 +671,7 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
|
|
|
667
671
|
const deduped = edges.filter((e) => {
|
|
668
672
|
if (e.from === e.to)
|
|
669
673
|
return false;
|
|
670
|
-
const key = `${e.from}
|
|
674
|
+
const key = `${e.from}\u0000${e.to}\u0000${e.rel}`;
|
|
671
675
|
if (seen.has(key))
|
|
672
676
|
return false;
|
|
673
677
|
seen.add(key);
|
|
@@ -979,6 +983,7 @@ async function build(opts) {
|
|
|
979
983
|
}
|
|
980
984
|
: undefined,
|
|
981
985
|
externalSources: fleet.externalSources,
|
|
986
|
+
fleetGeneratedAt: fleet.fleetGeneratedAt,
|
|
982
987
|
internalSources: fleet.internalSources,
|
|
983
988
|
pipelines: fleet.pipelines,
|
|
984
989
|
tools: fleet.tools,
|
package/dist/render.js
CHANGED
|
@@ -91,6 +91,23 @@ const CM_TOOL_LABEL = {
|
|
|
91
91
|
* 状態: 健全=色付き+流れるアニメーション / 問題あり=黄+⚠️ / 未使用=グレー。
|
|
92
92
|
* fleet-status由来の情報が何も無ければ null(マップを出さない・後方互換)。
|
|
93
93
|
*/
|
|
94
|
+
/**
|
|
95
|
+
* このソースが「注意が必要」か。接続マップ(ビルド時生成)とデータソース一覧(クライアント側)で
|
|
96
|
+
* **同じ判定を使う**ためにここに置く。片方だけ直すと、同じ画面でマップが⚠️・直下が「接続OK」になる。
|
|
97
|
+
*
|
|
98
|
+
* 判定の考え方:
|
|
99
|
+
* - 明示的に Gold 対象から外したもの(`gold === false`)は、読めなくて当たり前なので警告しない。
|
|
100
|
+
* ただし通知先(`notify`)に使っているなら、届いていないこと自体が問題なので拾う。
|
|
101
|
+
* - `gold` が無い(旧 fleet-status.json)ときは**警告する側に倒す**。「不明」を「対象外」と扱うと、
|
|
102
|
+
* 本当に壊れているものが黙って隠れる(フェイルオープン)。
|
|
103
|
+
*/
|
|
104
|
+
function sourceNeedsAttention(s) {
|
|
105
|
+
if (s.gate === "ok")
|
|
106
|
+
return false;
|
|
107
|
+
if (s.gold === false && s.notify !== true)
|
|
108
|
+
return false;
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
94
111
|
function renderConnectionMap(site) {
|
|
95
112
|
const internals = site.internalSources ?? [];
|
|
96
113
|
const externals = site.externalSources ?? [];
|
|
@@ -119,7 +136,9 @@ function renderConnectionMap(site) {
|
|
|
119
136
|
// 問題あり: ライブ参照はgate≠okが1件以上、同期ソースは対応パイプラインの直近runがfailure
|
|
120
137
|
const warn = !off &&
|
|
121
138
|
(isLive
|
|
122
|
-
|
|
139
|
+
// カード側の集計(sourceNeedsAttention)と同じ判定にする。ここだけ接続状態だけを見ていると、
|
|
140
|
+
// マップが⚠️なのに直下のグループが「接続OK」という矛盾が同じ画面に出る。
|
|
141
|
+
? liveExts.some((s) => sourceNeedsAttention(s))
|
|
123
142
|
: pipes.some((p) => c.pipe != null && c.pipe.test(p.id) && p.applicable !== false && p.lastConclusion === "failure"));
|
|
124
143
|
const state = off ? "cm-off" : warn ? "cm-warn" : "cm-ok";
|
|
125
144
|
const toolName = toolVal && toolVal !== "none"
|
|
@@ -657,7 +676,8 @@ a:hover { text-decoration: underline; }
|
|
|
657
676
|
/* ---- データソースと自動化 ---- */
|
|
658
677
|
.datasources { margin-top: 34px; }
|
|
659
678
|
.datasources-head { font-size: 18px; font-weight: 700; color: var(--text); margin: 0 0 4px; }
|
|
660
|
-
.datasources-intro { color: var(--muted); font-size: 13.5px; line-height: 1.8; margin: 0 0
|
|
679
|
+
.datasources-intro { color: var(--muted); font-size: 13.5px; line-height: 1.8; margin: 0 0 6px; }
|
|
680
|
+
.datasources-asof { color: var(--muted); font-size: 12.5px; line-height: 1.7; margin: 0 0 14px; }
|
|
661
681
|
.ds-sub { font-size: 13px; font-weight: 700; color: var(--muted); margin: 20px 0 8px; }
|
|
662
682
|
.ds-list { display: flex; flex-direction: column; gap: 10px; }
|
|
663
683
|
.ds-card {
|
|
@@ -722,6 +742,7 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
722
742
|
.ds-badges { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; flex: 0 0 auto; }
|
|
723
743
|
.badge.ds-gold { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
|
|
724
744
|
.badge.ds-excluded { background: #eceef1; color: #6b7280; }
|
|
745
|
+
.badge.ds-undeclared { background: #fff4e5; color: #9a6700; }
|
|
725
746
|
.badge.ds-notify { background: #eff6ff; color: #1e40af; border: 1px solid #bfdbfe; }
|
|
726
747
|
.ds-gate { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; font-weight: 600; flex: 0 0 auto; }
|
|
727
748
|
.ds-gate::before { content: ""; width: 8px; height: 8px; border-radius: 999px; background: currentColor; }
|
|
@@ -1348,6 +1369,14 @@ const CLIENT_JS = `
|
|
|
1348
1369
|
var sec = el("section", { class: "datasources" });
|
|
1349
1370
|
sec.appendChild(el("h2", { class: "datasources-head", text: "データソースと自動化" }));
|
|
1350
1371
|
sec.appendChild(el("p", { class: "datasources-intro", text: "このCortexが接続している情報源と、毎晩自動でGoldに昇格する処理の一覧です。" }));
|
|
1372
|
+
// **いつ時点の情報かを必ず出す。** この節は夜間バッチが作るスナップショットを読んでいるので、
|
|
1373
|
+
// 設定を変えても次の生成までは古い値のまま。時刻が無いと「変えたのに反映されない」ではなく
|
|
1374
|
+
// 「変えたはずなのに違う値が出ている」と読まれてしまう(実際に設定変更直後にそうなった)。
|
|
1375
|
+
var asOf = SITE.fleetGeneratedAt ? dsFmtTime(SITE.fleetGeneratedAt) : "";
|
|
1376
|
+
if (asOf) {
|
|
1377
|
+
sec.appendChild(el("p", { class: "datasources-asof",
|
|
1378
|
+
text: "接続状況は " + asOf + " 時点の自動チェック結果です。設定を変えた場合、ここに反映されるのは次回の実行後になります。" }));
|
|
1379
|
+
}
|
|
1351
1380
|
|
|
1352
1381
|
if (internals.length) {
|
|
1353
1382
|
sec.appendChild(el("div", { class: "ds-sub", text: "リポジトリ内の情報源(自動同期)" }));
|
|
@@ -1414,14 +1443,27 @@ const CLIENT_JS = `
|
|
|
1414
1443
|
var cards = el("div", { class: "ds-list" });
|
|
1415
1444
|
g.items.forEach(function (s) { cards.appendChild(extSourceCard(s, meta)); });
|
|
1416
1445
|
if (g.items.length >= 4) {
|
|
1417
|
-
// 折りたたみ(既定は閉)。summary
|
|
1446
|
+
// 折りたたみ(既定は閉)。summaryに件数と状態の要約を出す。
|
|
1447
|
+
// 判定は接続マップ側の sourceNeedsAttention と揃える(片方だけ直すと同じ画面で矛盾する)。
|
|
1448
|
+
// 意図的に外したソースが接続できないのは当たり前なので数えない。ただし通知先に
|
|
1449
|
+
// 使っているなら届いていないこと自体が問題なので拾う。gold 不明は警告する側に倒す。
|
|
1418
1450
|
var bad = 0;
|
|
1419
|
-
|
|
1451
|
+
var noToken = 0;
|
|
1452
|
+
g.items.forEach(function (s) {
|
|
1453
|
+
if (s.gate === "ok") return;
|
|
1454
|
+
if (s.gold === false && s.notify !== true) return;
|
|
1455
|
+
bad++;
|
|
1456
|
+
if (s.gate === "no_token") noToken++;
|
|
1457
|
+
});
|
|
1420
1458
|
var sum = el("summary", {}, [
|
|
1421
1459
|
el("span", { text: meta.icon + " " + meta.label + "(" + g.items.length + (UNIT[g.type] || "件") + ")" }),
|
|
1422
1460
|
bad === 0
|
|
1423
1461
|
? el("span", { class: "badge ds-sum-ok", text: "接続OK" })
|
|
1424
|
-
|
|
1462
|
+
// 原因が1つに集約できるときは原因を書く。「19件に問題」より「トークンが未設定」の方が、
|
|
1463
|
+
// 読んだ人が次に何をすればよいか分かる(実際、19件の原因がトークン1本ということがあった)。
|
|
1464
|
+
: el("span", { class: "badge ds-sum-warn", text: noToken === bad
|
|
1465
|
+
? "⚠️ " + bad + "件が読めていません(トークン未設定)"
|
|
1466
|
+
: "⚠️ " + bad + "件に問題" }),
|
|
1425
1467
|
]);
|
|
1426
1468
|
var det = el("details", { class: "ds-group" }, [sum, cards]);
|
|
1427
1469
|
if (anchorId) det.id = anchorId;
|
|
@@ -1439,7 +1481,7 @@ const CLIENT_JS = `
|
|
|
1439
1481
|
// 注記は内部・外部の両グループの後ろに1つ(内部の直下だけに置くと外部ソースが
|
|
1440
1482
|
// Gold昇格の対象外に見えるため)。除外の方法もここで案内する。
|
|
1441
1483
|
if (internals.length || sources.length || chatOff || devOff) {
|
|
1442
|
-
sec.appendChild(el("p", { class: "ds-note", text: "
|
|
1484
|
+
sec.appendChild(el("p", { class: "ds-note", text: "「Gold昇格の読み取り対象」のものだけを毎晩の Gold 昇格が読み取ります。「除外」は意図的に外したもの、「未宣言(対象外)」はまだ判断されていないもので、どちらも読み取りません(チャンネル・リポジトリ単位で切り替えられます)。" }));
|
|
1443
1485
|
}
|
|
1444
1486
|
|
|
1445
1487
|
if (pipes.length) {
|
|
@@ -1485,7 +1527,10 @@ const CLIENT_JS = `
|
|
|
1485
1527
|
// 外部ソース1件のカード(グループ化表示・展開表示の両方から使う)
|
|
1486
1528
|
function extSourceCard(s, meta) {
|
|
1487
1529
|
var badges = el("div", { class: "ds-badges" });
|
|
1530
|
+
// 「意図的に外した」と「宣言し忘れ」を分けて出す。同じ「除外」と書くと、
|
|
1531
|
+
// 判断されていないだけのものが「判断済み」に見えてしまう。
|
|
1488
1532
|
if (s.gold === true) badges.appendChild(el("span", { class: "badge ds-gold", text: "Gold昇格の読み取り対象" }));
|
|
1533
|
+
else if (s.goldState === "undeclared") badges.appendChild(el("span", { class: "badge ds-undeclared", text: "未宣言(対象外)" }));
|
|
1489
1534
|
else if (s.gold === false) badges.appendChild(el("span", { class: "badge ds-excluded", text: "除外" }));
|
|
1490
1535
|
if (s.notify === true) badges.appendChild(el("span", { class: "badge ds-notify", text: "通知先" }));
|
|
1491
1536
|
var gate = DS_GATE[s.gate] || DS_GATE["unknown"];
|
package/package.json
CHANGED