@takagaki/cortex-decisions-viewer 0.9.1 → 0.10.0
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 +98 -3
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -6,6 +6,8 @@ exports.livePending = livePending;
|
|
|
6
6
|
exports.nextCheckDelay = nextCheckDelay;
|
|
7
7
|
exports.settledPending = settledPending;
|
|
8
8
|
exports.sanitizeRegisteredNow = sanitizeRegisteredNow;
|
|
9
|
+
exports.sanitizeStateNow = sanitizeStateNow;
|
|
10
|
+
exports.overlayStateOnFleet = overlayStateOnFleet;
|
|
9
11
|
exports.chatRowsToAdd = chatRowsToAdd;
|
|
10
12
|
exports.devRowsToAdd = devRowsToAdd;
|
|
11
13
|
exports.designRowsToAdd = designRowsToAdd;
|
|
@@ -564,6 +566,66 @@ function sanitizeRegisteredNow(v) {
|
|
|
564
566
|
}
|
|
565
567
|
return any ? out : null;
|
|
566
568
|
}
|
|
569
|
+
/** 接続状態ストアの語彙(サーバ側 connection-state.mjs と同じ。増やさない) */
|
|
570
|
+
const STATE_STATUSES = {
|
|
571
|
+
reachable: ["ok", "not_in_channel", "missing_scope", "no_token", "unreachable", "unknown"],
|
|
572
|
+
ingested: ["ok", "failed", "skipped"],
|
|
573
|
+
};
|
|
574
|
+
const STATE_ROW_FIELDS = ["cap", "ref", "workspace", "question", "status", "at", "by", "needed", "lastOkAt", "lastFailAt"];
|
|
575
|
+
/** stateNow はライブ専用キーで build.ts の網にかからない。画面側でも許可リストを通す */
|
|
576
|
+
function sanitizeStateNow(v) {
|
|
577
|
+
if (!Array.isArray(v))
|
|
578
|
+
return null;
|
|
579
|
+
const out = [];
|
|
580
|
+
for (const r of v) {
|
|
581
|
+
if (out.length >= 500)
|
|
582
|
+
break;
|
|
583
|
+
if (r == null || typeof r !== "object" || Array.isArray(r))
|
|
584
|
+
continue;
|
|
585
|
+
const item = {};
|
|
586
|
+
for (const f of STATE_ROW_FIELDS) {
|
|
587
|
+
const fv = r[f];
|
|
588
|
+
if (typeof fv === "string" && fv !== "")
|
|
589
|
+
item[f] = fv;
|
|
590
|
+
}
|
|
591
|
+
const vocab = STATE_STATUSES[item.question];
|
|
592
|
+
if (!vocab || vocab.indexOf(item.status) < 0)
|
|
593
|
+
continue; // 知らない語は「不明」に化けさせず落とす
|
|
594
|
+
if (!item.cap || !item.ref || !item.at)
|
|
595
|
+
continue;
|
|
596
|
+
out.push(item);
|
|
597
|
+
}
|
|
598
|
+
return out.length ? out : null;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* ストアの「届くか」を行に重ねる。**まとめ表より新しいときだけ**——古い確認結果で
|
|
602
|
+
* 新しい実測を潰さない(時刻の比較は ISO 文字列の辞書順で足りる)。
|
|
603
|
+
* 対象はチャットの行だけ(段A。確認ボタンが書くのがチャットだけのため)。
|
|
604
|
+
*/
|
|
605
|
+
function overlayStateOnFleet(view, rows, generatedAt) {
|
|
606
|
+
const v = view || {};
|
|
607
|
+
if (!rows || !rows.length || !Array.isArray(v.externalSources))
|
|
608
|
+
return v;
|
|
609
|
+
const byKey = {};
|
|
610
|
+
for (const r of rows) {
|
|
611
|
+
if (r.cap !== "chat" || r.question !== "reachable")
|
|
612
|
+
continue;
|
|
613
|
+
byKey[String(r.workspace || "") + "\t" + String(r.ref)] = r;
|
|
614
|
+
}
|
|
615
|
+
let changed = false;
|
|
616
|
+
const externals = v.externalSources.map((s) => {
|
|
617
|
+
if (!s || s.type !== "slack" || !s.ref)
|
|
618
|
+
return s;
|
|
619
|
+
const hit = byKey[String(s.workspace || "") + "\t" + String(s.ref)];
|
|
620
|
+
if (!hit)
|
|
621
|
+
return s;
|
|
622
|
+
if (generatedAt && hit.at <= generatedAt)
|
|
623
|
+
return s;
|
|
624
|
+
changed = true;
|
|
625
|
+
return Object.assign({}, s, { gate: hit.status, gateAt: hit.at, gateBy: hit.by });
|
|
626
|
+
});
|
|
627
|
+
return changed ? Object.assign({}, v, { externalSources: externals }) : v;
|
|
628
|
+
}
|
|
567
629
|
/**
|
|
568
630
|
* チャットの行で、まとめ表がまだ知らないもの。
|
|
569
631
|
*
|
|
@@ -1830,6 +1892,7 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1830
1892
|
/* 全組織が接続済みのときに、トークン入力欄の代わりに出す1行(#118) */
|
|
1831
1893
|
.ds-all-connected { color: var(--muted); }
|
|
1832
1894
|
.ds-gate { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; font-weight: 600; flex: 0 0 auto; }
|
|
1895
|
+
.ds-gate-at { font-size: 11px; color: var(--muted); flex: 0 0 auto; }
|
|
1833
1896
|
.ds-gate::before { content: ""; width: 8px; height: 8px; border-radius: 999px; background: currentColor; }
|
|
1834
1897
|
.ds-gate-ok { color: #1f7a45; }
|
|
1835
1898
|
.ds-gate-warn { color: #b45309; }
|
|
@@ -2124,6 +2187,10 @@ ${internalOf.toString()}
|
|
|
2124
2187
|
${registeredRowsToAdd.toString()}
|
|
2125
2188
|
${unsettledRegisteredCount.toString()}
|
|
2126
2189
|
${mergeRegisteredFleet.toString()}
|
|
2190
|
+
var STATE_STATUSES = ${JSON.stringify(STATE_STATUSES)};
|
|
2191
|
+
var STATE_ROW_FIELDS = ${JSON.stringify(STATE_ROW_FIELDS)};
|
|
2192
|
+
${sanitizeStateNow.toString()}
|
|
2193
|
+
${overlayStateOnFleet.toString()}
|
|
2127
2194
|
${nextStateDelay.toString()}
|
|
2128
2195
|
// 「はじめに」セクションのチュートリアルデータ(ビルド時に埋め込み。ボタンURL・チャレンジ4の決定は解決済み)
|
|
2129
2196
|
var TUTORIAL = (function () {
|
|
@@ -3520,6 +3587,8 @@ ${nextStateDelay.toString()}
|
|
|
3520
3587
|
* 指すのか説明できなくなる(realtime を別に持っているのと同じ理由)。
|
|
3521
3588
|
*/
|
|
3522
3589
|
var LIVE_REGISTERED = null;
|
|
3590
|
+
// 接続状態ストアの行(届くか・取り込めたか)。op=state の stateNow から
|
|
3591
|
+
var LIVE_STATE = null;
|
|
3523
3592
|
/** マージ済みの3キー(作り直しは setLive* だけが行う) */
|
|
3524
3593
|
var MERGED = null;
|
|
3525
3594
|
/** マージの対象になるキー。これ以外は素の値をそのまま返す */
|
|
@@ -3547,8 +3616,16 @@ ${nextStateDelay.toString()}
|
|
|
3547
3616
|
* 足す場所を描画側に散らすと「タイルは1件・一覧は2件」のような食い違いが必ず出る。
|
|
3548
3617
|
*/
|
|
3549
3618
|
function fleetVal(key) {
|
|
3550
|
-
if (LIVE_REGISTERED && MERGE_KEYS[key]) {
|
|
3551
|
-
|
|
3619
|
+
if ((LIVE_REGISTERED || LIVE_STATE) && MERGE_KEYS[key]) {
|
|
3620
|
+
// 登録の追加 → 状態の上書き、の順で1回だけ合成する。
|
|
3621
|
+
// 状態ストアの答えは、まとめ表より新しいときだけ勝つ(overlayStateOnFleet が判定)
|
|
3622
|
+
if (!MERGED) {
|
|
3623
|
+
MERGED = overlayStateOnFleet(
|
|
3624
|
+
mergeRegisteredFleet(rawView(), LIVE_REGISTERED),
|
|
3625
|
+
LIVE_STATE,
|
|
3626
|
+
String(rawFleetVal("generatedAt") || ""),
|
|
3627
|
+
);
|
|
3628
|
+
}
|
|
3552
3629
|
return MERGED[key];
|
|
3553
3630
|
}
|
|
3554
3631
|
return rawFleetVal(key);
|
|
@@ -3599,10 +3676,19 @@ ${nextStateDelay.toString()}
|
|
|
3599
3676
|
* 変わったとき(例えば pending の語をやめたとき)に「接続OK」が復活しないようにする。
|
|
3600
3677
|
*/
|
|
3601
3678
|
function stateCtx() {
|
|
3679
|
+
// 🔴 **ストアの上書き(overlayStateOnFleet)だけは適用する。** 行の一覧は fleetVal
|
|
3680
|
+
// (上書き済み)で描くので、ここが素のままだと「行は接続OK・タイルは⚠️」という
|
|
3681
|
+
// 同じ画面での食い違いが出る(実装レビューで指摘)。registeredNow の**行の追加**を
|
|
3682
|
+
// 混ぜない、という上の注意はそのまま——追加はここでは適用しない
|
|
3683
|
+
var ov = overlayStateOnFleet(
|
|
3684
|
+
{ externalSources: rawFleetVal("externalSources") || [] },
|
|
3685
|
+
LIVE_STATE,
|
|
3686
|
+
String(rawFleetVal("generatedAt") || ""),
|
|
3687
|
+
);
|
|
3602
3688
|
return {
|
|
3603
3689
|
capabilities: rawFleetVal("capabilities") || {},
|
|
3604
3690
|
internals: rawFleetVal("internalSources") || [],
|
|
3605
|
-
externals:
|
|
3691
|
+
externals: ov.externalSources || [],
|
|
3606
3692
|
pipes: rawFleetVal("pipelines") || [],
|
|
3607
3693
|
};
|
|
3608
3694
|
}
|
|
@@ -5107,6 +5193,9 @@ ${nextStateDelay.toString()}
|
|
|
5107
5193
|
var v = probeVerdict(s, j);
|
|
5108
5194
|
gateEl.className = "ds-gate " + v.cls;
|
|
5109
5195
|
gateEl.textContent = v.text;
|
|
5196
|
+
// 古い「X分前に確認」を残さない(下に出るいまの結果と、時刻が2つ並ぶ)
|
|
5197
|
+
var oldAt = card.querySelector(".ds-gate-at");
|
|
5198
|
+
if (oldAt) oldAt.remove();
|
|
5110
5199
|
// 不足スコープは**状態の語のすぐ横**に出す(「権限が足りません:groups:read」)。
|
|
5111
5200
|
// 本文へ落とすと、いちばん要る情報が説明文に埋もれる
|
|
5112
5201
|
if (j.gate === "missing_scope") {
|
|
@@ -6530,6 +6619,10 @@ ${nextStateDelay.toString()}
|
|
|
6530
6619
|
// **「接続を確認」が押されたら、この要素を live の判定で置き換える**(probeSection)。
|
|
6531
6620
|
// 2つの判定を同じ行に並べないため、参照を持っておく
|
|
6532
6621
|
var gateEl = el("span", { class: "ds-gate " + gate.cls, text: gate.text });
|
|
6622
|
+
// 状態ストア由来の判定には「いつ確かめたか」を必ず添える
|
|
6623
|
+
var gateAtEl = s.gateAt
|
|
6624
|
+
? el("span", { class: "ds-gate-at", text: rtAgo(s.gateAt) + "に確認" })
|
|
6625
|
+
: null;
|
|
6533
6626
|
var card = el("div", { class: "ds-card" }, [
|
|
6534
6627
|
el("div", { class: "ds-card-main" }, [
|
|
6535
6628
|
el("span", { class: "ds-icon", text: meta.icon }),
|
|
@@ -6540,6 +6633,7 @@ ${nextStateDelay.toString()}
|
|
|
6540
6633
|
badges,
|
|
6541
6634
|
gateEl,
|
|
6542
6635
|
]);
|
|
6636
|
+
if (gateAtEl) card.appendChild(gateAtEl);
|
|
6543
6637
|
// チャンネルの登録解除。書き込み経路(intake Lambda)がある案件でだけ出す。
|
|
6544
6638
|
// **Slack だけ。** github は登録ファイルが別(dev-sources.json)で、下のトグルと
|
|
6545
6639
|
// 「登録から削除」が担う。
|
|
@@ -6849,6 +6943,7 @@ ${nextStateDelay.toString()}
|
|
|
6849
6943
|
// (=立ち上げ直後=この仕組みが一番効く案件)は下で throw するので、
|
|
6850
6944
|
// ここより後に置くと**その案件だけ素通り**する
|
|
6851
6945
|
LIVE_REGISTERED = sanitizeRegisteredNow(j && j.registeredNow);
|
|
6946
|
+
LIVE_STATE = sanitizeStateNow(j && j.stateNow);
|
|
6852
6947
|
MERGED = null;
|
|
6853
6948
|
if (!j || !j.fleet) throw new Error("no fleet");
|
|
6854
6949
|
LIVE_FLEET = normalizeFleet(j.fleet);
|