@takagaki/cortex-decisions-viewer 0.11.0 → 0.11.1
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/render.js +152 -5
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -26,6 +26,7 @@ exports.sanitizeCapabilitiesNow = sanitizeCapabilitiesNow;
|
|
|
26
26
|
exports.sanitizeGithubOwnersNow = sanitizeGithubOwnersNow;
|
|
27
27
|
exports.splitNeededParts = splitNeededParts;
|
|
28
28
|
exports.ingestedAtOf = ingestedAtOf;
|
|
29
|
+
exports.usageFactMissing = usageFactMissing;
|
|
29
30
|
exports.renderConnectionMap = renderConnectionMap;
|
|
30
31
|
/** SiteDataを単一の自己完結HTML(埋め込みデータ+CSS+JS)にレンダリングする */
|
|
31
32
|
function renderSite(site) {
|
|
@@ -1291,6 +1292,47 @@ function ingestedAtOf(rows, capId) {
|
|
|
1291
1292
|
}
|
|
1292
1293
|
return best;
|
|
1293
1294
|
}
|
|
1295
|
+
/**
|
|
1296
|
+
* 「取り込みの事実」でタイルと線を決める能力(画面の能力名 → ストアの能力名)。
|
|
1297
|
+
*
|
|
1298
|
+
* **この2つだけ。** 会議と共有資料は中央 Apps Script が取り込むので、設定が済んでいても
|
|
1299
|
+
* (capabilities が `on` でも)**一度も取り込まれていない**ことが普通に起きる。他の4能力は
|
|
1300
|
+
* 判定の材料が違う(夜間の reachable・パイプラインの成否)ので、ここに足さないこと——
|
|
1301
|
+
* 足した瞬間、実績の無い案件が一斉に「未使用」になる。
|
|
1302
|
+
*/
|
|
1303
|
+
const FACT_CAPS = { "会議": "meetings", "共有資料": "materials" };
|
|
1304
|
+
/**
|
|
1305
|
+
* その能力が「設定は済んでいるのに、まだ一度も取り込めていない」か(#235 の表示層)。
|
|
1306
|
+
*
|
|
1307
|
+
* 🔴 **`seen`(応答に `stateNow` の欄があったか)と `rows`(その中身)は別物。**
|
|
1308
|
+
* サーバは**読めたなら0件でも欄を付ける**ので、この2つで3つの状態が区別できる:
|
|
1309
|
+
*
|
|
1310
|
+
* - `seen === false` … 分からない(古い Lambda・ストアの読み取りに失敗)→ **偽**。
|
|
1311
|
+
* 従来表示のままにする。分からないことを「未使用」と言い切らない
|
|
1312
|
+
* - `seen === true` かつ行が0件 … 読めて空=**まだ一度も取り込めていない**→ 真。
|
|
1313
|
+
* 初期化直後の案件がここに来る(この機能が一番効いてほしい案件)
|
|
1314
|
+
* - `seen === true` かつ行がある … その能力の取り込み実績で決める
|
|
1315
|
+
*
|
|
1316
|
+
* **`rows` の空と `seen` を混ぜないこと。** `sanitizeStateNow` は0件を `null` に畳むので、
|
|
1317
|
+
* `rows` だけを見ると「読めて空」が「分からない」に化け、**まさに未使用の案件でだけ
|
|
1318
|
+
* 機能しない**(サーバ側を直した意味が消える)。
|
|
1319
|
+
*
|
|
1320
|
+
* **成功の事実は `ingestedAtOf` に一本化する。** あちらは `lastOkAt` も見るので、
|
|
1321
|
+
* 「一度取り込めた後に失敗した」能力を未使用に落とさない。判定を写経すると、そこがずれる。
|
|
1322
|
+
*
|
|
1323
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す。
|
|
1324
|
+
* `FACT_CAPS` は CLIENT_JS 側にも `var` で流し込んである)。
|
|
1325
|
+
*/
|
|
1326
|
+
function usageFactMissing(cap, rows, seen) {
|
|
1327
|
+
var capId = FACT_CAPS[cap];
|
|
1328
|
+
if (!capId)
|
|
1329
|
+
return false;
|
|
1330
|
+
if (!seen)
|
|
1331
|
+
return false;
|
|
1332
|
+
if (!Array.isArray(rows) || !rows.length)
|
|
1333
|
+
return true;
|
|
1334
|
+
return ingestedAtOf(rows, capId) === "";
|
|
1335
|
+
}
|
|
1294
1336
|
function capabilityState(cap, ctx) {
|
|
1295
1337
|
// **能力→パイプラインの対応はここに持つ。** 呼び出し側に渡させると、
|
|
1296
1338
|
// クライアント側(この関数を .toString() で受け取る側)が同じ表を書き写すことになり、
|
|
@@ -1536,8 +1578,19 @@ function renderConnectionMap(site) {
|
|
|
1536
1578
|
//
|
|
1537
1579
|
// cm-warn は引く。**壊れているのは「繋がったうえで失敗している」状態**で、
|
|
1538
1580
|
// 経路自体は存在する(線を消すと、設定が無いのと区別が付かなくなる)。
|
|
1581
|
+
//
|
|
1582
|
+
// **`data-cm-cap` は線を後から取り消すための取っ手(#235 の表示層)。** この図は
|
|
1583
|
+
// ビルド時に焼くので、**取り込みの事実(stateNow)はここでは分からない**——分かるのは
|
|
1584
|
+
// ライブ応答が届いた後だけ。届いてから会議・共有資料の線を外せるように、線に
|
|
1585
|
+
// 能力名を持たせておく(外す側は applyUsageFactToConnMap)。
|
|
1586
|
+
// 位置で数えさせないこと——線は ok/warn の能力ぶんしか積まれないので、
|
|
1587
|
+
// 並び順は案件ごとに変わる。
|
|
1588
|
+
//
|
|
1589
|
+
// 🔴 **`data-cap` は使わない。** あちらは能力ブロック(`.datasources` の中)が
|
|
1590
|
+
// 既に名乗っていて、図はページの**上**にあるので `[data-cap="会議"]` で引くと
|
|
1591
|
+
// 図の線のほうが先に当たる。実際、最初にそう書いてテストが12件落ちた。
|
|
1539
1592
|
if (state === "cm-ok" || state === "cm-warn") {
|
|
1540
|
-
links.push(`<path class="cm-link ${state}" d="M ${cx} 78 C ${cx} 152, ${REPO_X} 162, ${REPO_X} 238"></path>`);
|
|
1593
|
+
links.push(`<path class="cm-link ${state}" data-cm-cap="${escapeHtml(c.cap)}" d="M ${cx} 78 C ${cx} 152, ${REPO_X} 162, ${REPO_X} 238"></path>`);
|
|
1541
1594
|
}
|
|
1542
1595
|
});
|
|
1543
1596
|
// **中央ノードは GitHub のリポジトリ名そのもの(オーナー指示・2026-08-12)。**
|
|
@@ -2631,6 +2684,8 @@ ${sanitizeCapabilitiesNow.toString()}
|
|
|
2631
2684
|
${sanitizeGithubOwnersNow.toString()}
|
|
2632
2685
|
${splitNeededParts.toString()}
|
|
2633
2686
|
${ingestedAtOf.toString()}
|
|
2687
|
+
var FACT_CAPS = ${JSON.stringify(FACT_CAPS)};
|
|
2688
|
+
${usageFactMissing.toString()}
|
|
2634
2689
|
// 「はじめに」セクションのチュートリアルデータ(ビルド時に埋め込み。ボタンURL・チャレンジ4の決定は解決済み)
|
|
2635
2690
|
var TUTORIAL = (function () {
|
|
2636
2691
|
var elx = document.getElementById("tutorial-data");
|
|
@@ -4075,6 +4130,15 @@ ${ingestedAtOf.toString()}
|
|
|
4075
4130
|
var LIVE_REGISTERED = null;
|
|
4076
4131
|
// 接続状態ストアの行(届くか・取り込めたか)。op=state の stateNow から
|
|
4077
4132
|
var LIVE_STATE = null;
|
|
4133
|
+
/**
|
|
4134
|
+
* 応答に 「stateNow」 の欄があったか(=サーバがストアを読めたか)。
|
|
4135
|
+
*
|
|
4136
|
+
* 🔴 **LIVE_STATE が null かどうかでは代用できない。** sanitize は0件を null に畳むので、
|
|
4137
|
+
* 「読めて0件」と「そもそも読めていない」が同じ値になる。サーバは**読めたなら0件でも
|
|
4138
|
+
* 欄を付ける**ので、区別できるのはこの旗だけ——潰すと、初期化直後の案件
|
|
4139
|
+
* (=会議・共有資料の「未使用」表示が一番効いてほしい案件)でだけ機能が死ぬ。
|
|
4140
|
+
*/
|
|
4141
|
+
var LIVE_STATE_SEEN = false;
|
|
4078
4142
|
/**
|
|
4079
4143
|
* 鍵がいま登録されているか(op=state の secretsNow・列2)。取得前・取得失敗時は null。
|
|
4080
4144
|
*
|
|
@@ -5364,15 +5428,30 @@ ${ingestedAtOf.toString()}
|
|
|
5364
5428
|
* 節を作り直せない場面(モーダルを開いたまま)でも、**届いた一覧で
|
|
5365
5429
|
* 引き直す**ために同じ関数を使う——写経すると片方だけ古くなる
|
|
5366
5430
|
*/
|
|
5367
|
-
|
|
5431
|
+
/**
|
|
5432
|
+
* @param noFact 「設定は済んでいるが、まだ一度も取り込めていない」と言い切れるか
|
|
5433
|
+
* (#235 の表示層)。**呼び出し側が渡す**——ここで LIVE_STATE から引き直すと、
|
|
5434
|
+
* タイルの色(st)を決めた材料と 2 回引くことになり、片方だけずれる余地ができる
|
|
5435
|
+
*/
|
|
5436
|
+
function tileSub(cap, st, derived, adapter, ins, srcs, noFact) {
|
|
5368
5437
|
var internal = ins.filter(function (s) { return s.kind === cap; })[0];
|
|
5369
5438
|
var live = srcs.filter(function (s) { return externalCapability(s.type) === cap; });
|
|
5370
5439
|
var parts = [];
|
|
5440
|
+
// 🔴 **取り込みの実績が無いなら、まずそれを言う(#235 の表示層)。**
|
|
5441
|
+
// 設定は済んでいる(capabilities は on)ので「未接続」ではないし、設定ミスでもないので
|
|
5442
|
+
// 警告色にもしない(#230 の決定どおり中立表示)。ここを通るのは会議・共有資料だけで、
|
|
5443
|
+
// しかも呼び出し側が st === "ok" のときにしか立てない——OFF・設定異常・同期失敗の
|
|
5444
|
+
// 語を、この一文で上書きしないため。
|
|
5445
|
+
//
|
|
5446
|
+
// 実績が無い= st は "idle" に降りているので、下の「件数」「最終同期」は自動で消える
|
|
5447
|
+
// (繋がっていないものに読み取り範囲と同期時刻を並べない、という既存の規律に乗る)
|
|
5448
|
+
if (noFact) {
|
|
5449
|
+
parts.push((CAP_STATE_MARK[st] || "") + "未使用(まだ取り込みがありません)");
|
|
5371
5450
|
// **導出が on 以外なら、導出の語を優先する(#125②)。** broken は状態としては
|
|
5372
5451
|
// 警告(⚠️)だが、原因は「設定そのものが壊れている」であって同期の失敗ではない。
|
|
5373
5452
|
// 下の warn の文(同期が失敗しています/N件が読めていません)を出すと、
|
|
5374
5453
|
// 直す場所が違うところを指す
|
|
5375
|
-
if (derived && derived !== "on") {
|
|
5454
|
+
} else if (derived && derived !== "on") {
|
|
5376
5455
|
parts.push((CAP_STATE_MARK[st] || "") + (CAP_STATE_TEXT[derived] || "状態が判定できません"));
|
|
5377
5456
|
} else if (st === "warn") {
|
|
5378
5457
|
if (live.length) {
|
|
@@ -5489,6 +5568,15 @@ ${ingestedAtOf.toString()}
|
|
|
5489
5568
|
// カタログにあるが導出が答えていないアダプタ(今日は発生しない。#107 の前方互換)
|
|
5490
5569
|
? "idle"
|
|
5491
5570
|
: capabilityState(cap, stateCtx());
|
|
5571
|
+
// 🔴 **「接続OK」と言うのは、取り込めた事実があるときだけ(#235 の表示層)。**
|
|
5572
|
+
// 会議・共有資料は中央 Apps Script が取り込むので、設定が済んでいるのに一度も
|
|
5573
|
+
// 取り込まれていない案件が普通にある。そこへ「● 接続OK」と出すと、**画面が
|
|
5574
|
+
// 動いていないものを動いていると言う**——顧客がそれを信じて資料を置かなくなる。
|
|
5575
|
+
//
|
|
5576
|
+
// **降ろすのは ok からだけ。** warn(繋がったうえで失敗している)は隠さないし、
|
|
5577
|
+
// idle / off はもともと繋がっていると言っていない。
|
|
5578
|
+
var noFact = st === "ok" && usageFactMissing(cap, LIVE_STATE, LIVE_STATE_SEEN);
|
|
5579
|
+
if (noFact) st = "idle";
|
|
5492
5580
|
// **ロゴはタイルの左に独立して置く。** 名前の行に入れると名前の高さに
|
|
5493
5581
|
// 縛られて小さくなる。ロゴで能力を見分けられるのが一覧の主な用途
|
|
5494
5582
|
var logo = ADAPTER_ICONS[adapter];
|
|
@@ -5506,7 +5594,7 @@ ${ingestedAtOf.toString()}
|
|
|
5506
5594
|
var pend = capPending(cap);
|
|
5507
5595
|
var subEl = el("div", {
|
|
5508
5596
|
class: "ds-tile-sub " + (pend ? DS_GATE_PENDING.cls : "ds-gate-" + st),
|
|
5509
|
-
text: pend ? DS_GATE_PENDING.text : tileSub(cap, st, derived, adapter, internals, sources),
|
|
5597
|
+
text: pend ? DS_GATE_PENDING.text : tileSub(cap, st, derived, adapter, internals, sources, noFact),
|
|
5510
5598
|
});
|
|
5511
5599
|
// **反映が届いたら、届いたスナップショットから引き直す。** 下地へ戻すと
|
|
5512
5600
|
// 「⏳ 反映中」→「⦿ 未接続」になる——データが正しくなったあとに嘘をつく。
|
|
@@ -5519,10 +5607,14 @@ ${ingestedAtOf.toString()}
|
|
|
5519
5607
|
var stNow = dNow === "unset" && capabilityDisplayState(cap, capsNow) !== "unset"
|
|
5520
5608
|
? "idle"
|
|
5521
5609
|
: capabilityState(cap, stateCtx());
|
|
5610
|
+
// 実績の判定も、タイルを作るときと同じ式で引き直す(#235 の表示層)。
|
|
5611
|
+
// ここを省くと、反映が届いた瞬間だけ「● 接続OK」へ戻る
|
|
5612
|
+
var noFactNow = stNow === "ok" && usageFactMissing(cap, LIVE_STATE, LIVE_STATE_SEEN);
|
|
5613
|
+
if (noFactNow) stNow = "idle";
|
|
5522
5614
|
var pendNow = capPending(cap);
|
|
5523
5615
|
n.className = "ds-tile-sub " + (pendNow ? DS_GATE_PENDING.cls : "ds-gate-" + stNow);
|
|
5524
5616
|
return {
|
|
5525
|
-
text: pendNow ? DS_GATE_PENDING.text : tileSub(cap, stNow, dNow, adapter, insNow, srcsNow),
|
|
5617
|
+
text: pendNow ? DS_GATE_PENDING.text : tileSub(cap, stNow, dNow, adapter, insNow, srcsNow, noFactNow),
|
|
5526
5618
|
hidden: false,
|
|
5527
5619
|
};
|
|
5528
5620
|
});
|
|
@@ -7958,6 +8050,8 @@ ${ingestedAtOf.toString()}
|
|
|
7958
8050
|
// ここより後に置くと**その案件だけ素通り**する
|
|
7959
8051
|
LIVE_REGISTERED = sanitizeRegisteredNow(j && j.registeredNow);
|
|
7960
8052
|
LIVE_STATE = sanitizeStateNow(j && j.stateNow);
|
|
8053
|
+
// **欄の有無をそのまま覚える。** sanitize を通した後では「読めて0件」が消える
|
|
8054
|
+
LIVE_STATE_SEEN = !!(j && Array.isArray(j.stateNow));
|
|
7961
8055
|
// 🔴 **鍵・能力・組織も fleet より先に読む(工程1.5)。** まとめ表を
|
|
7962
8056
|
// まだ持たない案件は下で throw するので、ここより後に置くと
|
|
7963
8057
|
// **立ち上げ直後の案件=この修正が一番効く案件**だけ素通りする
|
|
@@ -7971,6 +8065,10 @@ ${ingestedAtOf.toString()}
|
|
|
7971
8065
|
liveFleetRequested = false;
|
|
7972
8066
|
MERGED = null;
|
|
7973
8067
|
refreshDataSources();
|
|
8068
|
+
// 🔴 **図の降格は refreshDataSources の外で呼ぶ(#235 の表示層)。** あちらは
|
|
8069
|
+
// モーダルが開いている間・入力中は何もせずに戻るので、中に入れると
|
|
8070
|
+
// **モーダルを開いたまま最初の応答が届いた回だけ、図が「接続OK」のまま残る**
|
|
8071
|
+
applyUsageFactToConnMap();
|
|
7974
8072
|
// **モーダルを開いたままでも「反映中」だけは追いつかせる。** refreshDataSources は
|
|
7975
8073
|
// モーダルが開いている間・入力中は何もしない(下地を入れ替えると開いているモーダルの
|
|
7976
8074
|
// 中身が切り離される)ので、局所的に差し替える口をここに置く
|
|
@@ -8485,6 +8583,55 @@ ${ingestedAtOf.toString()}
|
|
|
8485
8583
|
});
|
|
8486
8584
|
app.appendChild(wrap);
|
|
8487
8585
|
updateConnMapAsOf();
|
|
8586
|
+
applyUsageFactToConnMap();
|
|
8587
|
+
}
|
|
8588
|
+
|
|
8589
|
+
/**
|
|
8590
|
+
* 取り込みの実績が無い能力を、接続マップから降ろす(#235 の表示層)。
|
|
8591
|
+
*
|
|
8592
|
+
* **図はビルド時に焼かれている。** 焼いた時点では 「stateNow」 を持っていないので、
|
|
8593
|
+
* 会議・共有資料は capabilities が 「on」 なだけで「● 接続OK・線あり」になる。
|
|
8594
|
+
* ライブ応答が届いてから、実績の無い2能力だけを**その場で**降ろす。
|
|
8595
|
+
*
|
|
8596
|
+
* - 線は消す(「data-cm-cap」 で引く。位置で数えると案件ごとに並びが変わる)
|
|
8597
|
+
* - ノードは 「cm-off」(灰・破線)にして、3行目を「未使用」にする。図の語彙は
|
|
8598
|
+
* renderConnectionMap の off と同じにする——同じ画面で図とタイルの語を割らない
|
|
8599
|
+
*
|
|
8600
|
+
* **降ろすのは 「cm-ok」 からだけ**(タイル側と同じ規律。「cm-warn」 は隠さない)。
|
|
8601
|
+
*
|
|
8602
|
+
* ⚠ **戻す道は無い。** 画面を開いたまま初回の取り込みが完走した場合、下の一覧だけが
|
|
8603
|
+
* 「接続OK」に変わり、図は次に開くまで「未使用」のまま。図の遅れは
|
|
8604
|
+
* 「この図は◯◯時点です(下の一覧は最新)」で既に断ってあるので、ここでは受け入れる
|
|
8605
|
+
* ——「cm-ok」 を条件にしているので、何度呼んでも二重に降ろすことはない。
|
|
8606
|
+
*/
|
|
8607
|
+
function applyUsageFactToConnMap() {
|
|
8608
|
+
var wrap = app.querySelector(".conn-map");
|
|
8609
|
+
if (!wrap) return;
|
|
8610
|
+
for (var cap in FACT_CAPS) {
|
|
8611
|
+
if (!Object.prototype.hasOwnProperty.call(FACT_CAPS, cap)) continue;
|
|
8612
|
+
if (!usageFactMissing(cap, LIVE_STATE, LIVE_STATE_SEEN)) continue;
|
|
8613
|
+
var node = wrap.querySelector('[data-target="ds-' + cap + '"]');
|
|
8614
|
+
if (!node || node.getAttribute("class").indexOf("cm-ok") < 0) continue;
|
|
8615
|
+
node.setAttribute("class", "cm-node cm-off");
|
|
8616
|
+
var sync = node.querySelector(".cm-sync");
|
|
8617
|
+
if (!sync) {
|
|
8618
|
+
// 3行目そのものが無いノード(最終同期を持たないまま ok になっていた)。
|
|
8619
|
+
// **状態を書く場所を作る**——灰色になっただけで理由が読めないのは、
|
|
8620
|
+
// 「名前だけ出て状態が出ない」という #124 の症状に戻ること
|
|
8621
|
+
var label = node.querySelector(".cm-label");
|
|
8622
|
+
sync = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
8623
|
+
sync.setAttribute("class", "cm-sync");
|
|
8624
|
+
sync.setAttribute("x", label ? label.getAttribute("x") : "0");
|
|
8625
|
+
sync.setAttribute("y", "67");
|
|
8626
|
+
sync.setAttribute("text-anchor", "middle");
|
|
8627
|
+
node.appendChild(sync);
|
|
8628
|
+
}
|
|
8629
|
+
// 時刻の整形(renderConnMap の [data-ts])が後から書き戻さないよう、印ごと外す
|
|
8630
|
+
sync.removeAttribute("data-ts");
|
|
8631
|
+
sync.textContent = "未使用";
|
|
8632
|
+
var link = wrap.querySelector('.cm-link[data-cm-cap="' + cap + '"]');
|
|
8633
|
+
if (link && link.parentNode) link.parentNode.removeChild(link);
|
|
8634
|
+
}
|
|
8488
8635
|
}
|
|
8489
8636
|
|
|
8490
8637
|
/**
|
package/package.json
CHANGED