@takagaki/cortex-decisions-viewer 0.12.54 → 0.12.56
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 +411 -48
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -37,6 +37,10 @@ exports.sanitizeCapabilitiesNow = sanitizeCapabilitiesNow;
|
|
|
37
37
|
exports.sanitizeGithubOwnersNow = sanitizeGithubOwnersNow;
|
|
38
38
|
exports.splitNeededParts = splitNeededParts;
|
|
39
39
|
exports.ingestedAtOf = ingestedAtOf;
|
|
40
|
+
exports.ingestedRowOf = ingestedRowOf;
|
|
41
|
+
exports.runLogUrlOf = runLogUrlOf;
|
|
42
|
+
exports.lastSyncRunUrlOf = lastSyncRunUrlOf;
|
|
43
|
+
exports.runSourceWordOf = runSourceWordOf;
|
|
40
44
|
exports.fleetLastSyncOf = fleetLastSyncOf;
|
|
41
45
|
exports.stateRefKey = stateRefKey;
|
|
42
46
|
exports.registeredRefKeys = registeredRefKeys;
|
|
@@ -977,7 +981,23 @@ const STATE_STATUSES = {
|
|
|
977
981
|
// 「作成済み」の行が overlay に届く前に落ちて、画面は永久に「作成中」のまま
|
|
978
982
|
calendar: ["requested", "ok", "failed"],
|
|
979
983
|
};
|
|
980
|
-
const STATE_ROW_FIELDS = ["cap", "ref", "workspace", "question", "status", "at", "by", "needed", "detail", "lastOkAt", "lastFailAt"];
|
|
984
|
+
const STATE_ROW_FIELDS = ["cap", "ref", "workspace", "question", "status", "at", "by", "needed", "detail", "lastOkAt", "lastFailAt", "runUrl"];
|
|
985
|
+
/**
|
|
986
|
+
* 行の `runUrl`(その行を書いた GitHub Actions の run・#560)に許す形。**原本は
|
|
987
|
+
* `infra/lambda/shared/connection-state-keys.mjs` の `RUN_URL_RE`**で、これはその写し
|
|
988
|
+
* (画面は `href` にそのまま置くので、intake が篩ったあとでも画面側でもう一度縛る)。
|
|
989
|
+
* 埋め込み JS には `var RUN_URL_RE` として注入する(export すると `exports.` 参照が客先へ
|
|
990
|
+
* 渡って画面が死ぬ——`state-vocab-parity.test.mjs` 冒頭の実害)。
|
|
991
|
+
*/
|
|
992
|
+
const RUN_URL_RE = /^https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/actions\/runs\/[0-9]+$/;
|
|
993
|
+
/** `runUrl` を持てる書き手(Actions の run の中で動く engine の書き手)。ほかの書き手の値は出さない */
|
|
994
|
+
const RUN_URL_WRITERS = ["ingest", "gold", "nightly"];
|
|
995
|
+
/**
|
|
996
|
+
* `runUrl` が無い行の出どころの語(#560)。run が無い書き手だけ。**`ingest` / `gold` は
|
|
997
|
+
* 載せない**——`runUrl` が無いのは古い engine か固定 IP の CodeBuild で、行からは区別できない
|
|
998
|
+
* (「Webhook」と断定すると嘘になる)
|
|
999
|
+
*/
|
|
1000
|
+
const RUN_SOURCE_WORDS = { central: "中央の処理", button: "その場で確認", auto: "保存時に確認" };
|
|
981
1001
|
/** stateNow はライブ専用キーで build.ts の網にかからない。画面側でも許可リストを通す */
|
|
982
1002
|
function sanitizeStateNow(v) {
|
|
983
1003
|
if (!Array.isArray(v))
|
|
@@ -999,6 +1019,9 @@ function sanitizeStateNow(v) {
|
|
|
999
1019
|
continue; // 知らない語は「不明」に化けさせず落とす
|
|
1000
1020
|
if (!item.cap || !item.ref || !item.at)
|
|
1001
1021
|
continue;
|
|
1022
|
+
// `runUrl` は run ページの形だけ(#560)。形が違えば**欄だけ落として行は残す**
|
|
1023
|
+
if (item.runUrl && !RUN_URL_RE.test(item.runUrl))
|
|
1024
|
+
delete item.runUrl;
|
|
1002
1025
|
out.push(item);
|
|
1003
1026
|
}
|
|
1004
1027
|
return out.length ? out : null;
|
|
@@ -1079,6 +1102,8 @@ function overlayStateOnFleet(view, rows) {
|
|
|
1079
1102
|
gateBy: hit.by,
|
|
1080
1103
|
needed: hit.needed || "",
|
|
1081
1104
|
detail: hit.detail || "",
|
|
1105
|
+
// その行を書いた run(#560)。無ければ空
|
|
1106
|
+
gateRunUrl: hit.runUrl || "",
|
|
1082
1107
|
});
|
|
1083
1108
|
});
|
|
1084
1109
|
return changed ? Object.assign({}, v, { externalSources: externals }) : v;
|
|
@@ -1922,6 +1947,75 @@ function ingestedAtOf(rows, capId, refs) {
|
|
|
1922
1947
|
}
|
|
1923
1948
|
return best;
|
|
1924
1949
|
}
|
|
1950
|
+
/**
|
|
1951
|
+
* `ingestedAtOf` と**同じ選び方**で、時刻ではなく**その行**を返す(#560)。「最終同期」の横に
|
|
1952
|
+
* 「実行ログ」を出すために要る。選び方をここに書き写さず、同じ規則で行を選ぶ
|
|
1953
|
+
* (分かれると「最終同期の時刻」と「そのリンク先の run」が別の行のものになる)。
|
|
1954
|
+
*
|
|
1955
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
1956
|
+
* @returns 選んだ行。1件も無ければ null
|
|
1957
|
+
*/
|
|
1958
|
+
function ingestedRowOf(rows, capId, refs) {
|
|
1959
|
+
if (!Array.isArray(rows) || !capId)
|
|
1960
|
+
return null;
|
|
1961
|
+
let best = "";
|
|
1962
|
+
let bestRow = null;
|
|
1963
|
+
for (const r of rows) {
|
|
1964
|
+
if (!r || r.cap !== capId || r.question !== "ingested")
|
|
1965
|
+
continue;
|
|
1966
|
+
if (refs && !refs[stateRefKey(capId, r.ref, r.workspace)])
|
|
1967
|
+
continue;
|
|
1968
|
+
const at = r.lastOkAt || (r.status === "ok" ? r.at : "");
|
|
1969
|
+
if (typeof at === "string" && at > best) {
|
|
1970
|
+
best = at;
|
|
1971
|
+
bestRow = r;
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
return bestRow;
|
|
1975
|
+
}
|
|
1976
|
+
/**
|
|
1977
|
+
* 行の横に出す「実行ログ」のリンク先(#560)。**無ければ空文字。**
|
|
1978
|
+
*
|
|
1979
|
+
* 出すのは Actions の run の中で動く書き手(`RUN_URL_WRITERS`)の行だけ。ボタン・中央の
|
|
1980
|
+
* 書き手は intake が `runUrl` を消して書くが、画面側でも二重の網にする——残っていると
|
|
1981
|
+
* 「いま測った結果」の横に別の run のログが出る。形は `RUN_URL_RE`(`href` にそのまま置く)。
|
|
1982
|
+
*
|
|
1983
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
1984
|
+
*/
|
|
1985
|
+
function runLogUrlOf(row) {
|
|
1986
|
+
if (!row || typeof row.runUrl !== "string" || !RUN_URL_RE.test(row.runUrl))
|
|
1987
|
+
return "";
|
|
1988
|
+
if (RUN_URL_WRITERS.indexOf(String(row.by || "")) < 0)
|
|
1989
|
+
return "";
|
|
1990
|
+
return row.runUrl;
|
|
1991
|
+
}
|
|
1992
|
+
/**
|
|
1993
|
+
* 「最終同期: …」の横に出すリンク先(#560)。**その時刻を書いた run のときだけ。**
|
|
1994
|
+
*
|
|
1995
|
+
* 「最終同期」は `lastOkAt`(最後に取り込めた時刻)で、行の `runUrl` は**いまの status を
|
|
1996
|
+
* 書いた run**のもの。いま `failed` の行の `lastOkAt` が最大なら、その `runUrl` は失敗した run
|
|
1997
|
+
* を指すので出さない(間違った run へ送るより、無いほうがよい)。`ok` の行でも `lastOkAt` と
|
|
1998
|
+
* `statusAt` が違う(履歴だけ先に進んだ)回は出さない。
|
|
1999
|
+
*
|
|
2000
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
2001
|
+
*/
|
|
2002
|
+
function lastSyncRunUrlOf(row) {
|
|
2003
|
+
if (!row || row.status !== "ok")
|
|
2004
|
+
return "";
|
|
2005
|
+
if (row.lastOkAt && row.lastOkAt !== row.at)
|
|
2006
|
+
return "";
|
|
2007
|
+
return runLogUrlOf(row);
|
|
2008
|
+
}
|
|
2009
|
+
/**
|
|
2010
|
+
* `runUrl` の無い行に添える出どころの語(#560)。リンクが出る行・語の無い書き手は空文字。
|
|
2011
|
+
*
|
|
2012
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
2013
|
+
*/
|
|
2014
|
+
function runSourceWordOf(row) {
|
|
2015
|
+
if (!row || runLogUrlOf(row))
|
|
2016
|
+
return "";
|
|
2017
|
+
return RUN_SOURCE_WORDS[String(row.by || "")] || "";
|
|
2018
|
+
}
|
|
1925
2019
|
/**
|
|
1926
2020
|
* まとめ表(fleet-status.json)の「最終同期」を、画面に出してよい形で取る(#523 決定1)。
|
|
1927
2021
|
*
|
|
@@ -3926,6 +4020,12 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
3926
4020
|
.ds-all-connected { color: var(--muted); }
|
|
3927
4021
|
.ds-gate { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; font-weight: 600; flex: 0 0 auto; }
|
|
3928
4022
|
.ds-gate-at { font-size: 11px; color: var(--muted); flex: 0 0 auto; }
|
|
4023
|
+
/* 実行ログへの導線(#560)。時刻の横の添え物なので .ds-gate-at と同じ弱さ。押せることだけ
|
|
4024
|
+
点線の下線で示す(目立たせない——案件リポジトリに入っていない人には開けない) */
|
|
4025
|
+
.ds-run-link { font-size: 11px; color: var(--muted); flex: 0 0 auto; text-decoration: underline dotted; text-underline-offset: 2px; }
|
|
4026
|
+
.ds-run-link:hover { color: var(--text); }
|
|
4027
|
+
/* run の無い書き手の行の出どころ(「中央の処理」「その場で確認」)。同じ弱さの文字 */
|
|
4028
|
+
.ds-run-src { font-size: 11px; color: var(--muted); flex: 0 0 auto; }
|
|
3929
4029
|
/* 接続先1件ごとの「取り込み」(段C・2026-08-24)。**「最終同期」(.ds-sync・run単位)とは
|
|
3930
4030
|
別の行に並ぶ**ので、同じ強さにしない——run の時刻より弱い添え物として読ませる。
|
|
3931
4031
|
失敗だけは .ds-gate-warn と同じ色にする(同じ画面で警告の色が2種類あると、
|
|
@@ -3963,7 +4063,10 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
3963
4063
|
.ds-probe-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
3964
4064
|
/* いつ測った結果かを必ず添える。夜間のスナップショットと混ざると、どちらの話か読めない */
|
|
3965
4065
|
.ds-probe-at { font-size: 11.5px; color: var(--muted); }
|
|
3966
|
-
|
|
4066
|
+
/* flex: 1 1 100% は #548 で足した——「接続を確認」の即答は、この段を .ds-probe の中では
|
|
4067
|
+
なく**行(.ds-card)に直接**置く。付けないと ID と「外す」の横に押し込まれて折り返す
|
|
4068
|
+
(.ds-gate-help と同じ理由)。.ds-probe の中(display: block)では効かない */
|
|
4069
|
+
.ds-probe-help { flex: 1 1 100%; margin: 6px 0 0; font-size: 12px; line-height: 1.7; color: #6b7280;
|
|
3967
4070
|
min-width: 0; white-space: normal; overflow-wrap: anywhere; }
|
|
3968
4071
|
/* 「アクセス不可」の原因の候補(0.12.2)。**箇条書きにする**——候補が3つあるので、
|
|
3969
4072
|
一続きの文章にすると読む人が「自分がどれなのか」を自分で切り出すことになる
|
|
@@ -4487,6 +4590,12 @@ ${pending_ops_1.pendingCountDelta.toString()}
|
|
|
4487
4590
|
${pending_ops_1.pendingIssuesRef.toString()}
|
|
4488
4591
|
var STATE_STATUSES = ${JSON.stringify(STATE_STATUSES)};
|
|
4489
4592
|
var STATE_ROW_FIELDS = ${JSON.stringify(STATE_ROW_FIELDS)};
|
|
4593
|
+
// 行の runUrl の形と、出どころの語(#560)。**正規表現は JSON にできない**ので
|
|
4594
|
+
// source から組み立てる。この定数行を落とすと sanitizeStateNow が未定義を参照して
|
|
4595
|
+
// ライブ取得が丸ごと死ぬ
|
|
4596
|
+
var RUN_URL_RE = new RegExp(${JSON.stringify(RUN_URL_RE.source)});
|
|
4597
|
+
var RUN_URL_WRITERS = ${JSON.stringify(RUN_URL_WRITERS)};
|
|
4598
|
+
var RUN_SOURCE_WORDS = ${JSON.stringify(RUN_SOURCE_WORDS)};
|
|
4490
4599
|
${sanitizeStateNow.toString()}
|
|
4491
4600
|
${overlayStateOnFleet.toString()}
|
|
4492
4601
|
// Home の「使用ツール」(#275)。**判定と表示語の実体はビルド時の定義**——
|
|
@@ -4519,6 +4628,10 @@ ${stateRefKey.toString()}
|
|
|
4519
4628
|
${registeredRefKeys.toString()}
|
|
4520
4629
|
${fleetLastSyncOf.toString()}
|
|
4521
4630
|
${ingestedAtOf.toString()}
|
|
4631
|
+
${ingestedRowOf.toString()}
|
|
4632
|
+
${runLogUrlOf.toString()}
|
|
4633
|
+
${lastSyncRunUrlOf.toString()}
|
|
4634
|
+
${runSourceWordOf.toString()}
|
|
4522
4635
|
var TILE_CAPS = ${JSON.stringify(TILE_CAPS)};
|
|
4523
4636
|
var BAD_STATE_STATUSES = ${JSON.stringify(BAD_STATE_STATUSES)};
|
|
4524
4637
|
// 登録直後の一時表示(#523 決定6)。**この定数行を落とすと、流し込んだ deriveCapTile が
|
|
@@ -6617,18 +6730,48 @@ ${calendarAddUrl.toString()}
|
|
|
6617
6730
|
});
|
|
6618
6731
|
return p;
|
|
6619
6732
|
}
|
|
6733
|
+
/**
|
|
6734
|
+
* ボタンの detail が「機械語の痕跡」でしかない能力(#548・設計v2 🔴2)。
|
|
6735
|
+
*
|
|
6736
|
+
* この3つは中央が艦隊の鍵で叩く経路(gate)で、押した回の detail には判定の語そのもの
|
|
6737
|
+
* ("unreachable")や生のエラー("ratelimited")が入る。**それ以外の能力
|
|
6738
|
+
* (design / materials / issues)のボタンは、engine の取り込みと同じ判定器の
|
|
6739
|
+
* 同じ1文を書く**ので、出さないと「読めません」の理由が押した人に届かない。
|
|
6740
|
+
*/
|
|
6741
|
+
var GATE_BUTTON_CAPS = ["chat", "dev", "google-chat"];
|
|
6742
|
+
/**
|
|
6743
|
+
* 外部ソースの種別 → 接続状態ストアの能力 id。**上の除外を引くためだけに使う。**
|
|
6744
|
+
* 知らない種別は空文字(=除外に当たらない=理由を出す側に倒す)。
|
|
6745
|
+
*/
|
|
6746
|
+
function gateCapOfType(type) {
|
|
6747
|
+
var t = String(type || "");
|
|
6748
|
+
if (t === "slack") return "chat";
|
|
6749
|
+
if (t === "google-chat") return "google-chat";
|
|
6750
|
+
if (t.indexOf("github") === 0) return "dev";
|
|
6751
|
+
return "";
|
|
6752
|
+
}
|
|
6620
6753
|
/**
|
|
6621
6754
|
* 休止状態の行に出す「最後に測った理由」(表にエントリが無い状態のフォールバック)。
|
|
6622
6755
|
* needed(次の一手・URL 込み)を優先し、無ければ detail。
|
|
6623
6756
|
*
|
|
6624
|
-
* 🔴
|
|
6625
|
-
*
|
|
6626
|
-
*
|
|
6627
|
-
* needed の側。夜間(gold)の detail
|
|
6757
|
+
* 🔴 **gate 経路の書き手が button の detail は出さない。** Slack / GitHub / Google Chat の
|
|
6758
|
+
* ボタンは detail に判定の語そのもの("unreachable")や生のエラー("ratelimited")を
|
|
6759
|
+
* 書く——lastFailDetail を空で潰さないための痕跡で、表示用の値ではない(intake の
|
|
6760
|
+
* op=probe のコメント)。人向けの文を持つのは needed の側。夜間(gold)の detail は
|
|
6761
|
+
* 人向けの文なので出す。
|
|
6762
|
+
*
|
|
6763
|
+
* 🔴 **除外は能力で絞る(#548)。** Figma / Drive / Backlog のボタンは中央がその場で
|
|
6764
|
+
* 案件の鍵で叩いて、engine の取り込みと同じ判定器の同じ1文を detail に書く。
|
|
6765
|
+
* 「button なら出さない」と一律にすると、**押した人にだけ理由が届かない**
|
|
6766
|
+
* (夜間まで待てば同じ文が出る、という逆立ちした画面になる)。
|
|
6767
|
+
*
|
|
6768
|
+
* @param s needed / detail / gateBy に加えて **cap(接続状態ストアの能力 id)** を渡す。
|
|
6769
|
+
* cap を渡さない呼び方は「除外に当たらない」=理由を出す側に倒れる
|
|
6628
6770
|
*/
|
|
6629
6771
|
function stateReasonOf(s) {
|
|
6630
6772
|
if (s.needed) return String(s.needed);
|
|
6631
|
-
|
|
6773
|
+
var hidden = s.gateBy === "button" && GATE_BUTTON_CAPS.indexOf(String(s.cap || "")) >= 0;
|
|
6774
|
+
if (s.detail && !hidden) return String(s.detail);
|
|
6632
6775
|
return "";
|
|
6633
6776
|
}
|
|
6634
6777
|
/**
|
|
@@ -8965,9 +9108,18 @@ ${calendarAddUrl.toString()}
|
|
|
8965
9108
|
function capBlockSyncEl(s, inactive) {
|
|
8966
9109
|
if (inactive || !s || !s.kind) return null;
|
|
8967
9110
|
var capId = capIdOf(s.kind);
|
|
8968
|
-
var
|
|
9111
|
+
var refs = capId ? refKeysOf(derCapOf(s.kind, "")) : null;
|
|
9112
|
+
var at = capId ? ingestedAtOf(LIVE_STATE, capId, refs) : "";
|
|
8969
9113
|
var t = dsFmtTime(at || fleetSyncFallback(s) || "");
|
|
8970
|
-
|
|
9114
|
+
if (!t) return null;
|
|
9115
|
+
var sync = el("span", { class: "ds-sync", text: "最終同期: " + t });
|
|
9116
|
+
// その時刻を書いた run へ(#560)。**ストア由来の時刻のときだけ**——まとめ表の後詰めに
|
|
9117
|
+
// run は無い。行は「ingestedAtOf」 と同じ選び方(「ingestedRowOf」)で取る。
|
|
9118
|
+
// run の無い書き手(中央 Apps Script の会議・資料の取り込み)は出どころの語
|
|
9119
|
+
var row = at ? ingestedRowOf(LIVE_STATE, capId, refs) : null;
|
|
9120
|
+
var url = lastSyncRunUrlOf(row);
|
|
9121
|
+
var trail = url ? [runLogLink(url)] : row ? runTrailNodes(row, "") : [];
|
|
9122
|
+
return trail.length ? frag([sync].concat(trail)) : sync;
|
|
8971
9123
|
}
|
|
8972
9124
|
|
|
8973
9125
|
if (internals.length) {
|
|
@@ -10332,6 +10484,8 @@ ${calendarAddUrl.toString()}
|
|
|
10332
10484
|
// 古い「X分前に確認」を残さない(下に出るいまの結果と、時刻が2つ並ぶ)
|
|
10333
10485
|
var oldAt = card.querySelector(".ds-gate-at");
|
|
10334
10486
|
if (oldAt) oldAt.remove();
|
|
10487
|
+
// 古い run の導線も残さない(#560)。「いま測った結果」の横に夜間の run のログが並ぶ形になる
|
|
10488
|
+
removeRunTrail(card);
|
|
10335
10489
|
// 🔴 **古いスコープ名の札も必ず消してから出し直す。** 行には夜間の判定に添えた
|
|
10336
10490
|
// 札が出ていることがあり(段B)、置き換えた「接続OK」の横に古いスコープ名が
|
|
10337
10491
|
// 残ると、同じ行が2つのことを言う——この節が何度も直してきた形そのもの。
|
|
@@ -10784,6 +10938,59 @@ ${calendarAddUrl.toString()}
|
|
|
10784
10938
|
return null;
|
|
10785
10939
|
}
|
|
10786
10940
|
|
|
10941
|
+
/* -------------------------------------------------------------------------
|
|
10942
|
+
* 実行ログへの導線(#560)
|
|
10943
|
+
* -------------------------------------------------------------------------
|
|
10944
|
+
* 行の 「runUrl」(その行を書いた Actions の run)があれば、時刻の横に小さな「実行ログ ↗」を
|
|
10945
|
+
* 出す。run の無い書き手の行は、出どころを語で示す(「中央の処理」「その場で確認」)。
|
|
10946
|
+
* どちらを出すかの判断は純関数(runLogUrlOf / runSourceWordOf)が持ち、ここは描くだけ。
|
|
10947
|
+
* ----------------------------------------------------------------------- */
|
|
10948
|
+
|
|
10949
|
+
/** リンクの title。案件リポジトリに入っていない人には開けないので、押す前に分かるようにする */
|
|
10950
|
+
var RUN_LINK_TITLE = "GitHub Actions の実行ログを開きます(案件リポジトリへのアクセスが要ります)";
|
|
10951
|
+
/** 一覧(開始直後・run の番号がまだ無い)の title。飛び先が違うので文言も分ける */
|
|
10952
|
+
var RUN_LIST_TITLE = "GitHub Actions の実行の一覧を開きます(案件リポジトリへのアクセスが要ります)";
|
|
10953
|
+
var RUN_LIST_TEXT = "実行の一覧 ↗";
|
|
10954
|
+
|
|
10955
|
+
/** 「実行ログ ↗」(新しいタブ・title つき)。一覧のときは文言と title を一覧のものにする */
|
|
10956
|
+
function runLogLink(url, text) {
|
|
10957
|
+
var list = text === RUN_LIST_TEXT;
|
|
10958
|
+
return el("a", { class: "ds-run-link", href: url, target: "_blank", rel: "noopener", title: list ? RUN_LIST_TITLE : RUN_LINK_TITLE, text: text || "実行ログ ↗" });
|
|
10959
|
+
}
|
|
10960
|
+
|
|
10961
|
+
/**
|
|
10962
|
+
* 行の時刻の横に添えるもの(リンクか出どころの語)。**無ければ空配列。**
|
|
10963
|
+
* 「.ds-gate-at」「.ds-ingest」 の**兄弟**として置く(子にすると、文言の検査と
|
|
10964
|
+
* 「いま測った結果」への差し替えが崩れる)。
|
|
10965
|
+
*
|
|
10966
|
+
* @param kind どの時刻に添えたか(「gate」=「◯分前に確認」)。「いま測った結果」への差し替えは
|
|
10967
|
+
* **この印のものだけ**消す——「取り込み: 〜に成功」の横のリンク(別の行の run)は残す
|
|
10968
|
+
*/
|
|
10969
|
+
function runTrailNodes(row, url, kind) {
|
|
10970
|
+
var u = url === undefined ? runLogUrlOf(row) : url;
|
|
10971
|
+
var word = u ? "" : runSourceWordOf(row);
|
|
10972
|
+
var node = u ? runLogLink(u) : word ? el("span", { class: "ds-run-src", text: word }) : null;
|
|
10973
|
+
if (!node) return [];
|
|
10974
|
+
if (kind) node.setAttribute("data-trail", kind);
|
|
10975
|
+
return [node];
|
|
10976
|
+
}
|
|
10977
|
+
|
|
10978
|
+
/** 複数のノードを 1 つの子として返す(「el」 の children に並べるため) */
|
|
10979
|
+
function frag(nodes) {
|
|
10980
|
+
var f = document.createDocumentFragment();
|
|
10981
|
+
(nodes || []).forEach(function (n) { if (n) f.appendChild(n); });
|
|
10982
|
+
return f;
|
|
10983
|
+
}
|
|
10984
|
+
|
|
10985
|
+
/**
|
|
10986
|
+
* 「いま測った結果」に差し替えるとき、**「◯分前に確認」に添えた**古い run の導線を外す
|
|
10987
|
+
* (同じ行が 2 つのことを言わない)。「取り込み: 〜に成功」の横のリンクは別の行の run なので残す
|
|
10988
|
+
*/
|
|
10989
|
+
function removeRunTrail(scope) {
|
|
10990
|
+
var old = scope.querySelectorAll('.ds-run-link[data-trail="gate"], .ds-run-src[data-trail="gate"]');
|
|
10991
|
+
for (var i = 0; i < old.length; i++) old[i].remove();
|
|
10992
|
+
}
|
|
10993
|
+
|
|
10787
10994
|
/**
|
|
10788
10995
|
* 接続先1件の「取り込み」の表示。**測っていなければ何も出さない(null)。**
|
|
10789
10996
|
*
|
|
@@ -10806,10 +11013,12 @@ ${calendarAddUrl.toString()}
|
|
|
10806
11013
|
// 語は鍵カードの名前と揃える(keyMissingText の項)
|
|
10807
11014
|
else if (r.status === "skipped") text = "取り込み: 未実行(" + keyMissingText(cap) + ")";
|
|
10808
11015
|
if (!text) return null;
|
|
10809
|
-
|
|
11016
|
+
var span = el("span", {
|
|
10810
11017
|
class: "ds-ingest" + (r.status === "failed" ? " ds-ingest-failed" : ""),
|
|
10811
11018
|
text: text,
|
|
10812
11019
|
});
|
|
11020
|
+
// その行を書いた run へ(#560)。成功でも失敗でも、この時刻を書いた run のログ
|
|
11021
|
+
return frag([span].concat(runTrailNodes(r)));
|
|
10813
11022
|
}
|
|
10814
11023
|
|
|
10815
11024
|
/**
|
|
@@ -10851,6 +11060,8 @@ ${calendarAddUrl.toString()}
|
|
|
10851
11060
|
row.appendChild(el("span", { class: "ds-gate " + gate.cls, text: gate.text }));
|
|
10852
11061
|
var when = rtAgo(r.at);
|
|
10853
11062
|
if (when) row.appendChild(el("span", { class: "ds-gate-at", text: when + "に確認" }));
|
|
11063
|
+
// その行を書いた run へ(#560)。run の無い書き手は出どころの語
|
|
11064
|
+
runTrailNodes(r, undefined, "gate").forEach(function (n) { row.appendChild(n); });
|
|
10854
11065
|
return row;
|
|
10855
11066
|
}
|
|
10856
11067
|
|
|
@@ -10879,22 +11090,26 @@ ${calendarAddUrl.toString()}
|
|
|
10879
11090
|
return row;
|
|
10880
11091
|
}
|
|
10881
11092
|
if (r.status === "ok" || r.status === "no_token" || r.status === "missing_scope" || r.status === "not_in_channel") return row;
|
|
10882
|
-
|
|
11093
|
+
// **cap を渡す(#548)。** この3能力(design / materials / issues)のボタンは
|
|
11094
|
+
// 判定器の1文を detail に書くので、gate 経路の除外に当てない(stateReasonOf の項)
|
|
11095
|
+
var reason = stateReasonOf({ needed: r.needed, detail: r.detail, gateBy: r.by, cap: capId });
|
|
10883
11096
|
// needed は Slack の行と同じ部品を通す(URL がリンクになる・スコープ名がラベル化される)
|
|
10884
11097
|
if (reason) row.appendChild(r.needed ? neededNode(reason, "ds-gate-help") : el("p", { class: "ds-gate-help", text: reason }));
|
|
10885
11098
|
return row;
|
|
10886
11099
|
}
|
|
10887
11100
|
|
|
10888
11101
|
/* -------------------------------------------------------------------------
|
|
10889
|
-
*
|
|
11102
|
+
* 「接続を確認」と「今すぐ同期」(#523 S3・#548・Backlog / Drive / Figma)
|
|
10890
11103
|
* -------------------------------------------------------------------------
|
|
10891
|
-
*
|
|
10892
|
-
*
|
|
10893
|
-
*
|
|
11104
|
+
* #548 までは、この3つは中央が鍵を読まない(#105 決定5)ので、押すとその案件の同期が
|
|
11105
|
+
* 1回起きるだけだった。オーナーがその境界を覆し、いまは「接続を確認」は Slack / GitHub と
|
|
11106
|
+
* 同じく**中央がその場で叩いて答えを返す**(即答・「showProbeVerdict」)。同期を1回
|
|
11107
|
+
* 起こす従来の動きは「今すぐ同期」(送る値に 「sync: true」)に移った。
|
|
10894
11108
|
*
|
|
10895
|
-
*
|
|
11109
|
+
* 待ちの仕組み(下)は「今すぐ同期」と、Backlog が IP 制限で叩けず夜間と同じ経路へ
|
|
11110
|
+
* 倒れた回のために残る:
|
|
10896
11111
|
* 1. 押す前にその行の 「at」 を控える(🔴2・壁時計を使わない)
|
|
10897
|
-
* 2.
|
|
11112
|
+
* 2. 「同期を開始しました」を出して、取り直し(op=state)を回す
|
|
10898
11113
|
* 3. 控えた 「at」 より新しい行が届いたら、待ちを解いて札を描き直す
|
|
10899
11114
|
* ——札そのものは 「appendReachableChip」 が描くので、ここは待ちの表示だけ
|
|
10900
11115
|
* ----------------------------------------------------------------------- */
|
|
@@ -10972,60 +11187,203 @@ ${calendarAddUrl.toString()}
|
|
|
10972
11187
|
}
|
|
10973
11188
|
|
|
10974
11189
|
/**
|
|
10975
|
-
*
|
|
11190
|
+
* 断られた回の後始末。**待ちに入れない**(出ない結果を15分待たせない)。
|
|
11191
|
+
* 文言はサーバのものをそのまま出す(回数制限・鍵未登録・未登録の接続先・
|
|
11192
|
+
* 登録簿が読めない・ロール未登録・起動失敗が、全部ここへ来る)。
|
|
11193
|
+
*/
|
|
11194
|
+
function probeDeclined(note, key, j) {
|
|
11195
|
+
note.textContent = (j && j.message) || "確認できませんでした。";
|
|
11196
|
+
delete PROBE_WAITS[key];
|
|
11197
|
+
}
|
|
11198
|
+
|
|
11199
|
+
/**
|
|
11200
|
+
* 従来の待ちに入る(同期が1回起きて、答えは接続状態ストアの行として後から届く)。
|
|
11201
|
+
* 通るのは2つ——「今すぐ同期」と、Backlog が IP 制限でこの場では叩けず
|
|
11202
|
+
* **夜間と同じ経路へ倒れた回**(#548)。
|
|
11203
|
+
*
|
|
11204
|
+
* 🔴 **控えた 「at」 で待つ(🔴2・壁時計を使わない)。** 押した時刻で見ると、
|
|
11205
|
+
* 端末の時計がずれている人には永久に届かない(または届く前に届いたことになる)。
|
|
11206
|
+
*/
|
|
11207
|
+
function probeEnterWait(note, key, capId, ref, before, j) {
|
|
11208
|
+
PROBE_WAITS[key] = {
|
|
11209
|
+
cap: capId, ref: ref,
|
|
11210
|
+
at: (before && before.at) || "",
|
|
11211
|
+
startedAt: Date.now(),
|
|
11212
|
+
message: (j && j.message) || "",
|
|
11213
|
+
// 起こした run(特定できた回)と一覧(#560)。描き直しでもリンクが消えないよう控える
|
|
11214
|
+
runUrl: (j && RUN_URL_RE.test(String(j.runUrl || ""))) ? String(j.runUrl) : "",
|
|
11215
|
+
runsUrl: (j && /^https:\\/\\/github\\.com\\/[^\\s"'<>]+$/.test(String(j.runsUrl || ""))) ? String(j.runsUrl) : "",
|
|
11216
|
+
};
|
|
11217
|
+
probeWaitNote(note, PROBE_WAITS[key]);
|
|
11218
|
+
// 待っているあいだは取り直しを回す(届いた行で一覧が描き直される)
|
|
11219
|
+
refreshStateTimer();
|
|
11220
|
+
}
|
|
11221
|
+
|
|
11222
|
+
/**
|
|
11223
|
+
* 待ちの 1 文と、その横の導線(#560)。**その run を特定できていればそれ、無ければ一覧。**
|
|
11224
|
+
* 開始直後は run の番号が無いことが多いので一覧へ。行が更新されて待ちが解けたら、
|
|
11225
|
+
* 行側の「実行ログ ↗」(その run)に置き換わる。run の無い経路(固定 IP・中央)は何も出ない
|
|
11226
|
+
*/
|
|
11227
|
+
function probeWaitNote(note, wait) {
|
|
11228
|
+
note.textContent = (wait && wait.message) || "";
|
|
11229
|
+
if (!wait) return;
|
|
11230
|
+
var link = wait.runUrl ? runLogLink(wait.runUrl) : wait.runsUrl ? runLogLink(wait.runsUrl, RUN_LIST_TEXT) : null;
|
|
11231
|
+
if (link) {
|
|
11232
|
+
note.appendChild(document.createTextNode(" "));
|
|
11233
|
+
note.appendChild(link);
|
|
11234
|
+
}
|
|
11235
|
+
}
|
|
11236
|
+
|
|
11237
|
+
/**
|
|
11238
|
+
* 即答(#548 の direct)を行に映す。**「probeSection」 と同じ見た目にする**——
|
|
11239
|
+
* 夜間のスナップショットの判定といま測った判定を**同じ行に並べない**ため
|
|
11240
|
+
* (並べると「⚠️ と 接続OK が同時に出ている」になり、この節で何度も直してきた
|
|
11241
|
+
* 食い違いを画面の側から作ることになる)。置き換えたことが分かるよう、
|
|
11242
|
+
* いつ測ったかを必ず添える。
|
|
11243
|
+
*
|
|
11244
|
+
* 🔴 **札が無い行もある**(一度も測っていない接続先= 「appendReachableChip」 が
|
|
11245
|
+
* 何も足していない行)。その場合は札を作って**ボタンの前**に差し込む——後ろに置くと
|
|
11246
|
+
* 行の読み順(札 → ボタン)が崩れる。
|
|
11247
|
+
*
|
|
11248
|
+
* @param anchor 差し込む位置の目印(1つ目のボタン)
|
|
11249
|
+
*/
|
|
11250
|
+
function showProbeVerdict(row, capId, anchorIn, j) {
|
|
11251
|
+
var gate = dsGateForCap(capId, j.gate);
|
|
11252
|
+
// 差し込む位置は**行の最初のボタン**の前(「外す」が出る行では「外す」の前)。
|
|
11253
|
+
// 「接続を確認」の前に置くと、外せる行だけ「外す → 札 → ボタン」の並びになる(🟡10)
|
|
11254
|
+
var anchor = anchorIn;
|
|
11255
|
+
var btns = row.querySelectorAll(".ds-toggle-btn");
|
|
11256
|
+
for (var bi = 0; bi < btns.length; bi++) {
|
|
11257
|
+
// **行の直下にあるボタンだけ**が目印になれる(入れ子の中のボタンの前には差し込めない)
|
|
11258
|
+
if (btns[bi].parentNode === row) { anchor = btns[bi]; break; }
|
|
11259
|
+
}
|
|
11260
|
+
var chip = row.querySelector(".ds-gate");
|
|
11261
|
+
if (!chip) {
|
|
11262
|
+
chip = el("span", { class: "ds-gate" });
|
|
11263
|
+
row.insertBefore(chip, anchor);
|
|
11264
|
+
}
|
|
11265
|
+
chip.className = "ds-gate " + gate.cls;
|
|
11266
|
+
chip.textContent = gate.text;
|
|
11267
|
+
var at = row.querySelector(".ds-gate-at");
|
|
11268
|
+
if (!at) {
|
|
11269
|
+
at = el("span", { class: "ds-gate-at" });
|
|
11270
|
+
row.insertBefore(at, anchor);
|
|
11271
|
+
}
|
|
11272
|
+
at.textContent = "いま測った結果(" + (dsFmtTime(j.checkedAt) || "たった今") + ")";
|
|
11273
|
+
// 古い run の導線も外す(#560)。残すと「いま測った結果」の横に夜間の run のログが並ぶ
|
|
11274
|
+
removeRunTrail(row);
|
|
11275
|
+
// **夜間の判定に添えてあった案内は隠す。** 置き換えた判定と食い違う案内が下に残ると、
|
|
11276
|
+
// 同じ行が2つのことを言う(probeSection の stale 処理と同じ)
|
|
11277
|
+
var stale = row.querySelectorAll(".ds-gate-help");
|
|
11278
|
+
for (var si = 0; si < stale.length; si++) stale[si].hidden = true;
|
|
11279
|
+
// **押し直しで段が増えないよう、前回の結果は消してから出す**(probeSection の札と同じ)
|
|
11280
|
+
var old = row.querySelectorAll(".ds-probe-help");
|
|
11281
|
+
for (var oi = 0; oi < old.length; oi++) old[oi].remove();
|
|
11282
|
+
// 次の一手は語の表(DS_GATE_CAP)が持っていればそれ。無ければ判定器の1文(detail)
|
|
11283
|
+
// ——どちらも**1段だけ**(帯は症状・行は一手・繰り返さない)
|
|
11284
|
+
var nodes = gateHelpNodes(gate, "ds-probe-help");
|
|
11285
|
+
if (!nodes.length && j.detail) nodes = [el("p", { class: "ds-probe-help", text: String(j.detail) })];
|
|
11286
|
+
nodes.forEach(function (n) { row.appendChild(n); });
|
|
11287
|
+
}
|
|
11288
|
+
|
|
11289
|
+
/**
|
|
11290
|
+
* 接続先1件の「接続を確認」「今すぐ同期」(2ボタン+その場の返事1文)を行に足す。
|
|
11291
|
+
*
|
|
11292
|
+
* **なぜ2つに割れたか(#548)。** 中央が案件の鍵で1回だけ叩けるようになった
|
|
11293
|
+
* (オーナーが #105 決定5 を覆した)ので、「接続を確認」は**その場で答えが返る**
|
|
11294
|
+
* ——押した人を数分〜十数分待たせない。一方「取り込みをやり直したい」は別の用事なので、
|
|
11295
|
+
* 同期を1回起こす従来の動きは「今すぐ同期」として残す(送る値は 「sync: true」)。
|
|
10976
11296
|
*
|
|
10977
11297
|
* **ボタンは行の中**(Slack の行と同じ・2026-08-20 の「1行が2段になる」を繰り返さない)。
|
|
10978
|
-
*
|
|
11298
|
+
* 🔴 **その場の返事(「.ds-probe-wait」)は2つのボタンで1つ・行の最後。** 2つ持つと
|
|
11299
|
+
* 行が2段になり、片方に古い返事が残る。「ds-gate-help」 は付けない——あれは
|
|
11300
|
+
* 「最後に測った理由」の1段で、行の補足が1段であることを見張る検査(#523 S1)が
|
|
11301
|
+
* 数えている。押した人へのその場の返事は別の話なので、専用の class を持たせる。
|
|
10979
11302
|
*/
|
|
10980
11303
|
function appendDispatchProbe(row, capId, ref) {
|
|
10981
11304
|
var type = dispatchProbeTypeOf(capId);
|
|
10982
11305
|
// **書き込み経路が無ければ出さない**(押しても何も起きないボタンを置かない)
|
|
10983
11306
|
if (!type || !SITE.intake || !ref) return row;
|
|
10984
|
-
var
|
|
10985
|
-
|
|
10986
|
-
// 行の補足が1段であることを見張る検査(#523 S1)が数えている。待ちの1文は
|
|
10987
|
-
// 別の話(押した人へのその場の返事)なので、専用の class を持たせる
|
|
11307
|
+
var checkBtn = el("button", { class: "ds-toggle-btn", type: "button", text: "接続を確認" });
|
|
11308
|
+
var syncBtn = el("button", { class: "ds-toggle-btn", type: "button", text: "今すぐ同期" });
|
|
10988
11309
|
var note = el("p", { class: "ds-probe-wait" });
|
|
10989
11310
|
var phase = probeWaitPhaseOf(capId, ref);
|
|
10990
11311
|
var wait = probeWaitOf(capId, ref);
|
|
10991
|
-
if (phase === "waiting") note
|
|
10992
|
-
else if (phase === "timeout")
|
|
11312
|
+
if (phase === "waiting") probeWaitNote(note, wait);
|
|
11313
|
+
else if (phase === "timeout") {
|
|
11314
|
+
// 15 分待って届かないなら見に行く番。**行き先を添える**(#560)——一覧でも run でも
|
|
11315
|
+
note.textContent = PROBE_WAIT_TIMEOUT_TEXT;
|
|
11316
|
+
var to = wait && (wait.runUrl || wait.runsUrl);
|
|
11317
|
+
if (to) { note.appendChild(document.createTextNode(" ")); note.appendChild(runLogLink(to, wait.runUrl ? "実行ログ ↗" : RUN_LIST_TEXT)); }
|
|
11318
|
+
}
|
|
10993
11319
|
else note.hidden = true;
|
|
10994
11320
|
|
|
10995
|
-
|
|
10996
|
-
var endBusy = beginBusy(
|
|
11321
|
+
checkBtn.addEventListener("click", async function () {
|
|
11322
|
+
var endBusy = beginBusy(checkBtn, "確認中…");
|
|
10997
11323
|
note.hidden = false;
|
|
10998
11324
|
note.textContent = "確認中…";
|
|
10999
11325
|
// 🔴 **押す前に、いまの行の 「at」 を控える(🔴2)。** 行が無ければ空文字
|
|
11000
|
-
//(どんな 「at」
|
|
11326
|
+
//(どんな 「at」 が来ても「新しい」と読める)。使うのは IP 制限で倒れた回だけだが、
|
|
11327
|
+
// 応答が返ってからでは「押す前の行」を控えられない
|
|
11001
11328
|
var before = probeLatestRow(capId, ref);
|
|
11002
11329
|
var key = probeWaitKey(capId, ref);
|
|
11003
11330
|
try {
|
|
11004
11331
|
var res = await callIntake("probe", { type: type, ref: ref });
|
|
11005
11332
|
var j = await res.json().catch(function () { return {}; });
|
|
11006
11333
|
if (!res.ok || j.queued === false) {
|
|
11007
|
-
|
|
11008
|
-
note.textContent = j.message || "確認できませんでした。";
|
|
11009
|
-
delete PROBE_WAITS[key];
|
|
11334
|
+
probeDeclined(note, key, j);
|
|
11010
11335
|
endBusy();
|
|
11011
11336
|
return;
|
|
11012
11337
|
}
|
|
11013
|
-
|
|
11014
|
-
|
|
11015
|
-
|
|
11016
|
-
|
|
11017
|
-
|
|
11018
|
-
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
|
|
11338
|
+
if (!j.gate) {
|
|
11339
|
+
// 語が返らない回=この場では叩けなかった回。Backlog の IP 制限
|
|
11340
|
+
//(「reason」 が 「ip-restricted」)で夜間と同じ経路へ倒したときと、
|
|
11341
|
+
// 即答をまだ知らない古い Lambda が相手のとき。どちらも従来どおり待つ
|
|
11342
|
+
probeEnterWait(note, key, capId, ref, before, j);
|
|
11343
|
+
endBusy();
|
|
11344
|
+
return;
|
|
11345
|
+
}
|
|
11346
|
+
// 即答。🔴 **待ちには入れない(🟡7)**——結果はもう行に出ているので、
|
|
11347
|
+
// 待ちに入れると「届いた行」を探して15分待つ空回りになる
|
|
11348
|
+
delete PROBE_WAITS[key];
|
|
11349
|
+
note.hidden = true;
|
|
11350
|
+
note.textContent = "";
|
|
11351
|
+
showProbeVerdict(row, capId, checkBtn, j);
|
|
11352
|
+
// ストアにも 「button」 の行が書かれている。**取りに行くのは1回だけ**——
|
|
11353
|
+
// 届いた行で一覧が描き直され、この行の札が正本の値に揃う
|
|
11354
|
+
loadLiveFleet();
|
|
11022
11355
|
} catch (e) {
|
|
11023
11356
|
note.textContent = "通信に失敗しました。";
|
|
11024
11357
|
delete PROBE_WAITS[key];
|
|
11025
11358
|
}
|
|
11026
11359
|
endBusy();
|
|
11027
11360
|
});
|
|
11028
|
-
|
|
11361
|
+
|
|
11362
|
+
syncBtn.addEventListener("click", async function () {
|
|
11363
|
+
var endBusy = beginBusy(syncBtn, "同期中…");
|
|
11364
|
+
note.hidden = false;
|
|
11365
|
+
note.textContent = "同期中…";
|
|
11366
|
+
// 押す前の 「at」 を控える(上と同じ理由・壁時計を使わない)
|
|
11367
|
+
var before = probeLatestRow(capId, ref);
|
|
11368
|
+
var key = probeWaitKey(capId, ref);
|
|
11369
|
+
try {
|
|
11370
|
+
var res = await callIntake("probe", { type: type, ref: ref, sync: true });
|
|
11371
|
+
var j = await res.json().catch(function () { return {}; });
|
|
11372
|
+
if (!res.ok || j.queued === false) {
|
|
11373
|
+
probeDeclined(note, key, j);
|
|
11374
|
+
endBusy();
|
|
11375
|
+
return;
|
|
11376
|
+
}
|
|
11377
|
+
probeEnterWait(note, key, capId, ref, before, j);
|
|
11378
|
+
} catch (e) {
|
|
11379
|
+
note.textContent = "通信に失敗しました。";
|
|
11380
|
+
delete PROBE_WAITS[key];
|
|
11381
|
+
}
|
|
11382
|
+
endBusy();
|
|
11383
|
+
});
|
|
11384
|
+
|
|
11385
|
+
row.appendChild(checkBtn);
|
|
11386
|
+
row.appendChild(syncBtn);
|
|
11029
11387
|
row.appendChild(note);
|
|
11030
11388
|
return row;
|
|
11031
11389
|
}
|
|
@@ -11034,7 +11392,7 @@ ${calendarAddUrl.toString()}
|
|
|
11034
11392
|
* 一覧に出ている接続先の「届くか」をひとつの文字列にする(描き直しの要否の判定用)。
|
|
11035
11393
|
*
|
|
11036
11394
|
* **待ちの相も混ぜる(#523 S3)。** 混ぜないと、15分の上限に達しても一覧が
|
|
11037
|
-
*
|
|
11395
|
+
* 作り直されず、「同期を開始しました」が出たまま止まる(待てば出ると言い続ける形)。
|
|
11038
11396
|
*/
|
|
11039
11397
|
function reachSigOf(capId, refs) {
|
|
11040
11398
|
var now = Date.now();
|
|
@@ -12272,7 +12630,7 @@ ${calendarAddUrl.toString()}
|
|
|
12272
12630
|
// 起動できなかった案件(権限・スタブ未配布)ではリンクを出さない——押しても何も無い
|
|
12273
12631
|
if (j.runsUrl) {
|
|
12274
12632
|
msg.appendChild(document.createTextNode(" "));
|
|
12275
|
-
msg.appendChild(el("a", { href: j.runsUrl, target: "_blank", rel: "noopener", text: "実行状況を見る →" }));
|
|
12633
|
+
msg.appendChild(el("a", { href: j.runUrl || j.runsUrl, target: "_blank", rel: "noopener", title: RUN_LINK_TITLE, text: "実行状況を見る →" })); // その run を特定できていればそれ(#560)、無ければ一覧
|
|
12276
12634
|
}
|
|
12277
12635
|
// **「反映の状況 →」のリンクは無くなった(#221・2026-08-25)。** 指していたのは
|
|
12278
12636
|
// 「画面を追いつかせるための fleet-status の実行」で、その起動ごと撤去した
|
|
@@ -12822,6 +13180,8 @@ ${calendarAddUrl.toString()}
|
|
|
12822
13180
|
var gateAtEl = s.gateAt
|
|
12823
13181
|
? el("span", { class: "ds-gate-at", text: rtAgo(s.gateAt) + "に確認" })
|
|
12824
13182
|
: null;
|
|
13183
|
+
// その行を書いた run へ(#560)。overlay が写した 「gateRunUrl」 / 「gateBy」 から決める
|
|
13184
|
+
var gateTrail = s.gateAt ? runTrailNodes({ runUrl: s.gateRunUrl || "", by: s.gateBy || "" }, undefined, "gate") : [];
|
|
12825
13185
|
var card = el("div", { class: "ds-card" }, [
|
|
12826
13186
|
el("div", { class: "ds-card-main" }, [
|
|
12827
13187
|
el("span", { class: "ds-icon", text: meta.icon }),
|
|
@@ -12844,6 +13204,7 @@ ${calendarAddUrl.toString()}
|
|
|
12844
13204
|
card.appendChild(el("code", { class: "ds-probe-scope", text: String(s.needed) }));
|
|
12845
13205
|
}
|
|
12846
13206
|
if (gateAtEl) card.appendChild(gateAtEl);
|
|
13207
|
+
gateTrail.forEach(function (n) { card.appendChild(n); });
|
|
12847
13208
|
// チャンネルの登録解除。書き込み経路(intake Lambda)がある案件でだけ出す。
|
|
12848
13209
|
// **Slack だけ。** github は登録ファイルが別(dev-sources.json)で、下のトグルと
|
|
12849
13210
|
// 「登録から削除」が担う。
|
|
@@ -12921,7 +13282,9 @@ ${calendarAddUrl.toString()}
|
|
|
12921
13282
|
var restingParts = restingHelpPartsOf(s.type, s.gate);
|
|
12922
13283
|
if (restingParts) card.appendChild(restingHelpNode(restingParts, "ds-gate-help ds-gate-resting"));
|
|
12923
13284
|
else {
|
|
12924
|
-
|
|
13285
|
+
// **能力に畳んでから渡す(#548)。** ここへ来るのは Slack / GitHub / Google Chat の
|
|
13286
|
+
// 行だけなので、ボタンが書いた detail(判定語)は従来どおり出さない
|
|
13287
|
+
var reason = stateReasonOf({ needed: s.needed, detail: s.detail, gateBy: s.gateBy, cap: gateCapOfType(s.type) });
|
|
12925
13288
|
if (reason) card.appendChild(neededNode(reason, "ds-gate-help ds-gate-reason"));
|
|
12926
13289
|
}
|
|
12927
13290
|
}
|
|
@@ -12935,9 +13298,9 @@ ${calendarAddUrl.toString()}
|
|
|
12935
13298
|
// 判定と文面は infra/lambda/shared/github-gate.mjs 側(画面に分岐を持たせない)。
|
|
12936
13299
|
// **Google Chat は #347(同じ理由)。** スペースにアプリを追加した人が、その場で
|
|
12937
13300
|
// 直ったことを確かめられる。判定は infra/lambda/shared/google-chat-gate.mjs 側。
|
|
12938
|
-
// **Backlog / Figma / Drive は「接続を確認」の型が違う**(#523 S3・レジストリの
|
|
12939
|
-
// 「probe:
|
|
12940
|
-
//
|
|
13301
|
+
// **Backlog / Figma / Drive は「接続を確認」の型が違う**(#523 S3・#548・レジストリの
|
|
13302
|
+
// 「probe: direct」)。中央が案件の鍵で叩いて即答し、「今すぐ同期」も並ぶので、
|
|
13303
|
+
// ここではなくそれぞれの一覧の行が 「appendDispatchProbe」 で出す。
|
|
12941
13304
|
//
|
|
12942
13305
|
// **origin === "explicit" でも出す。** 確認は読むだけで、どの登録ファイル由来かに
|
|
12943
13306
|
// 関係なく効く(書き込みになる「表示名を更新する」だけが由来で出し分かれる)
|
|
@@ -13870,7 +14233,7 @@ ${calendarAddUrl.toString()}
|
|
|
13870
14233
|
// 起動できたときだけ、実行状況への導線を出す(鍵を入れた直後に効いたか確かめられる)
|
|
13871
14234
|
if (j.runsUrl) {
|
|
13872
14235
|
msg.appendChild(document.createTextNode(" "));
|
|
13873
|
-
msg.appendChild(el("a", { href: j.runsUrl, target: "_blank", rel: "noopener", text: "実行状況を見る →" }));
|
|
14236
|
+
msg.appendChild(el("a", { href: j.runUrl || j.runsUrl, target: "_blank", rel: "noopener", title: RUN_LINK_TITLE, text: "実行状況を見る →" })); // その run を特定できていればそれ(#560)、無ければ一覧
|
|
13874
14237
|
}
|
|
13875
14238
|
// 入れた値は画面に残さない(肩越しに見えるのを防ぐ)
|
|
13876
14239
|
input.value = "";
|
package/package.json
CHANGED