@takagaki/cortex-decisions-viewer 0.12.55 → 0.12.57
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/pending-ops.js +32 -7
- package/dist/render.js +311 -24
- package/package.json +1 -1
package/dist/pending-ops.js
CHANGED
|
@@ -202,9 +202,17 @@ function backlogTargetOf(input) {
|
|
|
202
202
|
function pendingIsSlackTeamId(v) {
|
|
203
203
|
return /^[TE][A-Z0-9]{6,20}$/.test(String(v == null ? "" : v));
|
|
204
204
|
}
|
|
205
|
-
/**
|
|
205
|
+
/**
|
|
206
|
+
* Backlog の接続先の鍵(render.ts の issuesRefOf と同形: ドメイン小文字 / キー大文字)。
|
|
207
|
+
*
|
|
208
|
+
* 🔴 **規則の正本は `infra/lambda/shared/connection-state-keys.mjs` の `issuesRefOf`**(#556)。
|
|
209
|
+
* ここも render.ts も**写し**で、ずれると仮置きの札が実測の行に重ならない
|
|
210
|
+
* (押した直後の札が消えないまま、別の行に本物が出る)。
|
|
211
|
+
* ずれを捕まえる網は `viewer/test/state-ref-parity.test.mjs`。
|
|
212
|
+
*/
|
|
206
213
|
function pendingIssuesRef(domain, projectKey) {
|
|
207
|
-
return String(domain == null ? "" : domain).toLowerCase() + "/" +
|
|
214
|
+
return String(domain == null ? "" : domain).trim().toLowerCase() + "/" +
|
|
215
|
+
String(projectKey == null ? "" : projectKey).trim().toUpperCase();
|
|
208
216
|
}
|
|
209
217
|
// ---- エントリを作る(op → kind / action / targetId の対応表はここ 1 つ) ------------
|
|
210
218
|
/**
|
|
@@ -277,8 +285,13 @@ function pendingOpOf(payload, ctx) {
|
|
|
277
285
|
const name = pendingLabel(payload.name);
|
|
278
286
|
return name ? make("slack", "update", payload.ref, { name: name }) : null;
|
|
279
287
|
}
|
|
280
|
-
case "set-notify":
|
|
281
|
-
|
|
288
|
+
case "set-notify": {
|
|
289
|
+
if (typeof payload.value !== "boolean")
|
|
290
|
+
return null;
|
|
291
|
+
// op は 1 つ。ref の形(spaces/…)で Google Chat と決める(サーバの notifyRefKind と同じ・#572)
|
|
292
|
+
const kind = pendingIsSpaceRef(payload.ref) ? "google-chat" : "slack";
|
|
293
|
+
return make(kind, "update", payload.ref, { notify: payload.value });
|
|
294
|
+
}
|
|
282
295
|
case "add-google-chat-space": {
|
|
283
296
|
const ref = pendingGoogleChatSpaceRef(payload.url);
|
|
284
297
|
// 名前は画面に欄が無い(サーバが引く)。live が来るまでは ref で出す
|
|
@@ -660,6 +673,9 @@ function pendingExternalRow(e) {
|
|
|
660
673
|
row.type = "google-chat";
|
|
661
674
|
row.name = p.name || e.targetId;
|
|
662
675
|
row.ref = e.targetId;
|
|
676
|
+
// add に畳まれた update(通知先 ON)を落とさない(#572・Slack と同じ)
|
|
677
|
+
if (p.notify === true)
|
|
678
|
+
row.notify = true;
|
|
663
679
|
}
|
|
664
680
|
else {
|
|
665
681
|
row.type = p.type || "github-issues";
|
|
@@ -734,14 +750,23 @@ function applyPendingOps(view, list) {
|
|
|
734
750
|
extChanged = true;
|
|
735
751
|
}
|
|
736
752
|
else if (e.action === "add") {
|
|
737
|
-
if (idx >= 0)
|
|
753
|
+
if (idx >= 0) {
|
|
754
|
+
// 本物の行が先に来ている。**add に畳まれた update(通知先の向き)だけは当てる**
|
|
755
|
+
// (#572)——畳んだまま捨てると、追加 → 5 分以内に本物の行 → 通知先 ON の順で
|
|
756
|
+
// 押した人の札が、据え置きの live で戻る
|
|
757
|
+
if (typeof p.notify === "boolean" && (externals[idx].notify === true) !== p.notify) {
|
|
758
|
+
externals[idx] = Object.assign({}, externals[idx], { notify: p.notify });
|
|
759
|
+
extChanged = true;
|
|
760
|
+
}
|
|
738
761
|
continue;
|
|
762
|
+
}
|
|
739
763
|
externals.push(pendingExternalRow(e));
|
|
740
764
|
extChanged = true;
|
|
741
765
|
}
|
|
742
|
-
else if (e.kind === "slack" && idx >= 0) {
|
|
766
|
+
else if ((e.kind === "slack" || e.kind === "google-chat") && idx >= 0) {
|
|
767
|
+
// update: Slack は name / notify、Google Chat は notify だけ(名前はサーバが引く・#572)
|
|
743
768
|
const patch = {};
|
|
744
|
-
if (typeof p.name === "string" && p.name)
|
|
769
|
+
if (e.kind === "slack" && typeof p.name === "string" && p.name)
|
|
745
770
|
patch.name = p.name;
|
|
746
771
|
if (typeof p.notify === "boolean")
|
|
747
772
|
patch.notify = p.notify;
|
package/dist/render.js
CHANGED
|
@@ -18,6 +18,7 @@ exports.sanitizeStateNow = sanitizeStateNow;
|
|
|
18
18
|
exports.overlayStateOnFleet = overlayStateOnFleet;
|
|
19
19
|
exports.chatRowsToAdd = chatRowsToAdd;
|
|
20
20
|
exports.gchatRowsToAdd = gchatRowsToAdd;
|
|
21
|
+
exports.overlayGchatNotify = overlayGchatNotify;
|
|
21
22
|
exports.devRowsToAdd = devRowsToAdd;
|
|
22
23
|
exports.markExcludedPendingRows = markExcludedPendingRows;
|
|
23
24
|
exports.designRowsToAdd = designRowsToAdd;
|
|
@@ -37,6 +38,10 @@ exports.sanitizeCapabilitiesNow = sanitizeCapabilitiesNow;
|
|
|
37
38
|
exports.sanitizeGithubOwnersNow = sanitizeGithubOwnersNow;
|
|
38
39
|
exports.splitNeededParts = splitNeededParts;
|
|
39
40
|
exports.ingestedAtOf = ingestedAtOf;
|
|
41
|
+
exports.ingestedRowOf = ingestedRowOf;
|
|
42
|
+
exports.runLogUrlOf = runLogUrlOf;
|
|
43
|
+
exports.lastSyncRunUrlOf = lastSyncRunUrlOf;
|
|
44
|
+
exports.runSourceWordOf = runSourceWordOf;
|
|
40
45
|
exports.fleetLastSyncOf = fleetLastSyncOf;
|
|
41
46
|
exports.stateRefKey = stateRefKey;
|
|
42
47
|
exports.registeredRefKeys = registeredRefKeys;
|
|
@@ -850,7 +855,8 @@ const REGISTERED_CAP_NAMES = {
|
|
|
850
855
|
*/
|
|
851
856
|
const REGISTERED_FIELDS = {
|
|
852
857
|
chat: ["ref", "name", "workspace", "orgUnknown", "origin", "goldState", "notify"],
|
|
853
|
-
|
|
858
|
+
// notify(#572): スペースも通知先にできる。真偽値の扱いは chat の notify と同じ篩
|
|
859
|
+
"google-chat": ["ref", "name", "notify"],
|
|
854
860
|
dev: ["ref", "type"],
|
|
855
861
|
// 🔴 **意図的に外した開発リポジトリ(#391)。** サーバは前から別キーで返していたが、
|
|
856
862
|
// ここに無いので篩が丸ごと落としていた。**これが読めないと「読み取り停止中」の行を
|
|
@@ -977,7 +983,23 @@ const STATE_STATUSES = {
|
|
|
977
983
|
// 「作成済み」の行が overlay に届く前に落ちて、画面は永久に「作成中」のまま
|
|
978
984
|
calendar: ["requested", "ok", "failed"],
|
|
979
985
|
};
|
|
980
|
-
const STATE_ROW_FIELDS = ["cap", "ref", "workspace", "question", "status", "at", "by", "needed", "detail", "lastOkAt", "lastFailAt"];
|
|
986
|
+
const STATE_ROW_FIELDS = ["cap", "ref", "workspace", "question", "status", "at", "by", "needed", "detail", "lastOkAt", "lastFailAt", "runUrl"];
|
|
987
|
+
/**
|
|
988
|
+
* 行の `runUrl`(その行を書いた GitHub Actions の run・#560)に許す形。**原本は
|
|
989
|
+
* `infra/lambda/shared/connection-state-keys.mjs` の `RUN_URL_RE`**で、これはその写し
|
|
990
|
+
* (画面は `href` にそのまま置くので、intake が篩ったあとでも画面側でもう一度縛る)。
|
|
991
|
+
* 埋め込み JS には `var RUN_URL_RE` として注入する(export すると `exports.` 参照が客先へ
|
|
992
|
+
* 渡って画面が死ぬ——`state-vocab-parity.test.mjs` 冒頭の実害)。
|
|
993
|
+
*/
|
|
994
|
+
const RUN_URL_RE = /^https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/actions\/runs\/[0-9]+$/;
|
|
995
|
+
/** `runUrl` を持てる書き手(Actions の run の中で動く engine の書き手)。ほかの書き手の値は出さない */
|
|
996
|
+
const RUN_URL_WRITERS = ["ingest", "gold", "nightly"];
|
|
997
|
+
/**
|
|
998
|
+
* `runUrl` が無い行の出どころの語(#560)。run が無い書き手だけ。**`ingest` / `gold` は
|
|
999
|
+
* 載せない**——`runUrl` が無いのは古い engine か固定 IP の CodeBuild で、行からは区別できない
|
|
1000
|
+
* (「Webhook」と断定すると嘘になる)
|
|
1001
|
+
*/
|
|
1002
|
+
const RUN_SOURCE_WORDS = { central: "中央の処理", button: "その場で確認", auto: "保存時に確認" };
|
|
981
1003
|
/** stateNow はライブ専用キーで build.ts の網にかからない。画面側でも許可リストを通す */
|
|
982
1004
|
function sanitizeStateNow(v) {
|
|
983
1005
|
if (!Array.isArray(v))
|
|
@@ -999,6 +1021,9 @@ function sanitizeStateNow(v) {
|
|
|
999
1021
|
continue; // 知らない語は「不明」に化けさせず落とす
|
|
1000
1022
|
if (!item.cap || !item.ref || !item.at)
|
|
1001
1023
|
continue;
|
|
1024
|
+
// `runUrl` は run ページの形だけ(#560)。形が違えば**欄だけ落として行は残す**
|
|
1025
|
+
if (item.runUrl && !RUN_URL_RE.test(item.runUrl))
|
|
1026
|
+
delete item.runUrl;
|
|
1002
1027
|
out.push(item);
|
|
1003
1028
|
}
|
|
1004
1029
|
return out.length ? out : null;
|
|
@@ -1079,6 +1104,8 @@ function overlayStateOnFleet(view, rows) {
|
|
|
1079
1104
|
gateBy: hit.by,
|
|
1080
1105
|
needed: hit.needed || "",
|
|
1081
1106
|
detail: hit.detail || "",
|
|
1107
|
+
// その行を書いた run(#560)。無ければ空
|
|
1108
|
+
gateRunUrl: hit.runUrl || "",
|
|
1082
1109
|
});
|
|
1083
1110
|
});
|
|
1084
1111
|
return changed ? Object.assign({}, v, { externalSources: externals }) : v;
|
|
@@ -1152,10 +1179,58 @@ function gchatRowsToAdd(externals, rows) {
|
|
|
1152
1179
|
continue;
|
|
1153
1180
|
if (have[String(r.ref)])
|
|
1154
1181
|
continue;
|
|
1155
|
-
|
|
1182
|
+
const row = { type: "google-chat", name: r.name || r.ref, ref: r.ref };
|
|
1183
|
+
// 通知先の印(#572)。真偽値の印は true のときだけ載せる(chatRowsToAdd と同じ)
|
|
1184
|
+
if (r.notify === true)
|
|
1185
|
+
row.notify = true;
|
|
1186
|
+
out.push(row);
|
|
1156
1187
|
}
|
|
1157
1188
|
return out;
|
|
1158
1189
|
}
|
|
1190
|
+
/**
|
|
1191
|
+
* まとめ表が既に持っている Google Chat の行に、live(registeredNow)の「通知先」の印を重ねる(#572)。
|
|
1192
|
+
*
|
|
1193
|
+
* 🔴 **engine のまとめ表(fleet-status)は Google Chat の行に `notify` を付けない**
|
|
1194
|
+
* (`resolve-external-sources.mjs` は Slack にだけ付ける)。重ねないと、押した直後の仮置きが
|
|
1195
|
+
* 切れたあと(最長 24 時間後)に、通知先のスペースが「通知先にする」に戻って見える
|
|
1196
|
+
* ——画面では通知先でないのに投稿される、という取り違えになる。
|
|
1197
|
+
*
|
|
1198
|
+
* **Slack の行には触らない**(まとめ表が正しく持っている・挙動を変えない)。live に
|
|
1199
|
+
* `google-chat` のキーが無ければ(読めていない)何も変えない。live に同じ ref の行があれば
|
|
1200
|
+
* その `notify` を正とし(true なら付け、そうでなければ外す)、live に無い行はそのまま
|
|
1201
|
+
* (消す判断は `subtractRemovedRegistered` の責務)。
|
|
1202
|
+
*
|
|
1203
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
1204
|
+
*/
|
|
1205
|
+
function overlayGchatNotify(externals, rows) {
|
|
1206
|
+
const list = externals || [];
|
|
1207
|
+
if (!Array.isArray(rows))
|
|
1208
|
+
return list;
|
|
1209
|
+
const live = {};
|
|
1210
|
+
for (const r of rows) {
|
|
1211
|
+
if (!r || !r.ref)
|
|
1212
|
+
continue;
|
|
1213
|
+
live[String(r.ref)] = r.notify === true;
|
|
1214
|
+
}
|
|
1215
|
+
let changed = false;
|
|
1216
|
+
const out = list.map(function (s) {
|
|
1217
|
+
if (!s || s.type !== "google-chat" || !s.ref)
|
|
1218
|
+
return s;
|
|
1219
|
+
if (!Object.prototype.hasOwnProperty.call(live, String(s.ref)))
|
|
1220
|
+
return s;
|
|
1221
|
+
const want = live[String(s.ref)];
|
|
1222
|
+
if ((s.notify === true) === want)
|
|
1223
|
+
return s;
|
|
1224
|
+
changed = true;
|
|
1225
|
+
const row = Object.assign({}, s);
|
|
1226
|
+
if (want)
|
|
1227
|
+
row.notify = true;
|
|
1228
|
+
else
|
|
1229
|
+
delete row.notify;
|
|
1230
|
+
return row;
|
|
1231
|
+
});
|
|
1232
|
+
return changed ? out : list;
|
|
1233
|
+
}
|
|
1159
1234
|
/**
|
|
1160
1235
|
* 開発の行で、まとめ表がまだ知らないもの。**鍵は `owner/repo` の生文字列。**
|
|
1161
1236
|
*
|
|
@@ -1270,10 +1345,17 @@ function materialRowsToAdd(ids, rows) {
|
|
|
1270
1345
|
* ⚠ 画面の `targetsGenerationOf`(サーバへ送る世代)は同じ規則を持つが、この関数を
|
|
1271
1346
|
* 呼べない——配信物から関数1つを切り出して直接呼ぶテストがあり、外の名前を参照した
|
|
1272
1347
|
* 瞬間にそのテストが動かなくなる。あちらを直すときはここも直す。
|
|
1348
|
+
*
|
|
1349
|
+
* 🔴 **規則の正本は `infra/lambda/shared/connection-state-keys.mjs` の `issuesRefOf`**(#556)。
|
|
1350
|
+
* ここはその**写し**で、`viewer/` は独立した npm パッケージ(`rootDir: src`)なので
|
|
1351
|
+
* 原本を import できない。**ずれを捕まえる網は契約表**——
|
|
1352
|
+
* `infra/test/fixtures/connection-state-contract.json` の `issuesRefOf` の節を、
|
|
1353
|
+
* 原本(infra 側のテスト)と写し(viewer/test/state-ref-parity.test.mjs)の**両方**に流す。
|
|
1354
|
+
* 片方だけ直したら、直していない側が赤くなる。
|
|
1273
1355
|
*/
|
|
1274
1356
|
function issuesRefOf(domain, projectKey) {
|
|
1275
|
-
return String(domain == null ? "" : domain).toLowerCase() + "/" +
|
|
1276
|
-
String(projectKey == null ? "" : projectKey).toUpperCase();
|
|
1357
|
+
return String(domain == null ? "" : domain).trim().toLowerCase() + "/" +
|
|
1358
|
+
String(projectKey == null ? "" : projectKey).trim().toUpperCase();
|
|
1277
1359
|
}
|
|
1278
1360
|
/**
|
|
1279
1361
|
* 課題管理の行で、まとめ表がまだ知らないもの。
|
|
@@ -1553,9 +1635,11 @@ function mergeRegisteredFleet(view, reg) {
|
|
|
1553
1635
|
};
|
|
1554
1636
|
if (!reg)
|
|
1555
1637
|
return out;
|
|
1638
|
+
// Google Chat の行の「通知先」は live が正(#572・まとめ表は持っていない)。足す前に重ねる
|
|
1639
|
+
out.externalSources = overlayGchatNotify(v.externalSources, reg["google-chat"]);
|
|
1556
1640
|
const add = registeredRowsToAdd(v, reg);
|
|
1557
1641
|
if (add.externalSources.length)
|
|
1558
|
-
out.externalSources = (
|
|
1642
|
+
out.externalSources = (out.externalSources || []).concat(add.externalSources);
|
|
1559
1643
|
if (add.design.length || add.materials.length) {
|
|
1560
1644
|
const internals = (v.internalSources || []).slice();
|
|
1561
1645
|
const put = (kind, patch) => {
|
|
@@ -1922,6 +2006,75 @@ function ingestedAtOf(rows, capId, refs) {
|
|
|
1922
2006
|
}
|
|
1923
2007
|
return best;
|
|
1924
2008
|
}
|
|
2009
|
+
/**
|
|
2010
|
+
* `ingestedAtOf` と**同じ選び方**で、時刻ではなく**その行**を返す(#560)。「最終同期」の横に
|
|
2011
|
+
* 「実行ログ」を出すために要る。選び方をここに書き写さず、同じ規則で行を選ぶ
|
|
2012
|
+
* (分かれると「最終同期の時刻」と「そのリンク先の run」が別の行のものになる)。
|
|
2013
|
+
*
|
|
2014
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
2015
|
+
* @returns 選んだ行。1件も無ければ null
|
|
2016
|
+
*/
|
|
2017
|
+
function ingestedRowOf(rows, capId, refs) {
|
|
2018
|
+
if (!Array.isArray(rows) || !capId)
|
|
2019
|
+
return null;
|
|
2020
|
+
let best = "";
|
|
2021
|
+
let bestRow = null;
|
|
2022
|
+
for (const r of rows) {
|
|
2023
|
+
if (!r || r.cap !== capId || r.question !== "ingested")
|
|
2024
|
+
continue;
|
|
2025
|
+
if (refs && !refs[stateRefKey(capId, r.ref, r.workspace)])
|
|
2026
|
+
continue;
|
|
2027
|
+
const at = r.lastOkAt || (r.status === "ok" ? r.at : "");
|
|
2028
|
+
if (typeof at === "string" && at > best) {
|
|
2029
|
+
best = at;
|
|
2030
|
+
bestRow = r;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
return bestRow;
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* 行の横に出す「実行ログ」のリンク先(#560)。**無ければ空文字。**
|
|
2037
|
+
*
|
|
2038
|
+
* 出すのは Actions の run の中で動く書き手(`RUN_URL_WRITERS`)の行だけ。ボタン・中央の
|
|
2039
|
+
* 書き手は intake が `runUrl` を消して書くが、画面側でも二重の網にする——残っていると
|
|
2040
|
+
* 「いま測った結果」の横に別の run のログが出る。形は `RUN_URL_RE`(`href` にそのまま置く)。
|
|
2041
|
+
*
|
|
2042
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
2043
|
+
*/
|
|
2044
|
+
function runLogUrlOf(row) {
|
|
2045
|
+
if (!row || typeof row.runUrl !== "string" || !RUN_URL_RE.test(row.runUrl))
|
|
2046
|
+
return "";
|
|
2047
|
+
if (RUN_URL_WRITERS.indexOf(String(row.by || "")) < 0)
|
|
2048
|
+
return "";
|
|
2049
|
+
return row.runUrl;
|
|
2050
|
+
}
|
|
2051
|
+
/**
|
|
2052
|
+
* 「最終同期: …」の横に出すリンク先(#560)。**その時刻を書いた run のときだけ。**
|
|
2053
|
+
*
|
|
2054
|
+
* 「最終同期」は `lastOkAt`(最後に取り込めた時刻)で、行の `runUrl` は**いまの status を
|
|
2055
|
+
* 書いた run**のもの。いま `failed` の行の `lastOkAt` が最大なら、その `runUrl` は失敗した run
|
|
2056
|
+
* を指すので出さない(間違った run へ送るより、無いほうがよい)。`ok` の行でも `lastOkAt` と
|
|
2057
|
+
* `statusAt` が違う(履歴だけ先に進んだ)回は出さない。
|
|
2058
|
+
*
|
|
2059
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
2060
|
+
*/
|
|
2061
|
+
function lastSyncRunUrlOf(row) {
|
|
2062
|
+
if (!row || row.status !== "ok")
|
|
2063
|
+
return "";
|
|
2064
|
+
if (row.lastOkAt && row.lastOkAt !== row.at)
|
|
2065
|
+
return "";
|
|
2066
|
+
return runLogUrlOf(row);
|
|
2067
|
+
}
|
|
2068
|
+
/**
|
|
2069
|
+
* `runUrl` の無い行に添える出どころの語(#560)。リンクが出る行・語の無い書き手は空文字。
|
|
2070
|
+
*
|
|
2071
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
2072
|
+
*/
|
|
2073
|
+
function runSourceWordOf(row) {
|
|
2074
|
+
if (!row || runLogUrlOf(row))
|
|
2075
|
+
return "";
|
|
2076
|
+
return RUN_SOURCE_WORDS[String(row.by || "")] || "";
|
|
2077
|
+
}
|
|
1925
2078
|
/**
|
|
1926
2079
|
* まとめ表(fleet-status.json)の「最終同期」を、画面に出してよい形で取る(#523 決定1)。
|
|
1927
2080
|
*
|
|
@@ -1961,12 +2114,16 @@ function fleetLastSyncOf(internal) {
|
|
|
1961
2114
|
* `issuesRefOf` はこれより**前**に流し込んである)。
|
|
1962
2115
|
*/
|
|
1963
2116
|
function stateRefKey(capId, ref, workspace) {
|
|
1964
|
-
|
|
2117
|
+
// 🔴 **`normalizeStateRef`(connection-state-keys.mjs)の写し**(#556)。ワークスペースを
|
|
2118
|
+
// 足すところだけが画面固有で、ref の畳み方そのものは向こうが正本
|
|
2119
|
+
// (契約表 `normalizeStateRef` の節を両側に流して突き合わせる)
|
|
2120
|
+
var s = String(ref == null ? "" : ref).trim();
|
|
1965
2121
|
if (!s)
|
|
1966
2122
|
return "";
|
|
1967
2123
|
if (capId === "issues") {
|
|
1968
2124
|
var at = s.indexOf("/");
|
|
1969
|
-
|
|
2125
|
+
// ドメインもキーも欠けた値から `issues` の鍵は組めない(原本と同じ判断)
|
|
2126
|
+
if (at <= 0 || at === s.length - 1)
|
|
1970
2127
|
return "";
|
|
1971
2128
|
return issuesRefOf(s.slice(0, at), s.slice(at + 1));
|
|
1972
2129
|
}
|
|
@@ -2000,24 +2157,27 @@ function registeredRefKeys(regKey, rows) {
|
|
|
2000
2157
|
out[issuesRefOf(r.domain, r.projectKey)] = true;
|
|
2001
2158
|
continue;
|
|
2002
2159
|
}
|
|
2160
|
+
// 🔴 **相方(`stateRefKey`)と同じだけ畳む(#556)。** あちらが前後の空白を落とすので、
|
|
2161
|
+
// ここが落とさないと**登録してあるのに「登録簿に無い」と判定される**行ができる
|
|
2162
|
+
// (いまは登録簿の値がサーバ側で trim 済みなので起きないが、片側だけ畳む形を残さない)
|
|
2003
2163
|
if (regKey === "design") {
|
|
2004
2164
|
if (r.key)
|
|
2005
|
-
out[String(r.key)] = true;
|
|
2165
|
+
out[String(r.key).trim()] = true;
|
|
2006
2166
|
continue;
|
|
2007
2167
|
}
|
|
2008
2168
|
if (regKey === "materials") {
|
|
2009
2169
|
if (r.id)
|
|
2010
|
-
out[String(r.id)] = true;
|
|
2170
|
+
out[String(r.id).trim()] = true;
|
|
2011
2171
|
continue;
|
|
2012
2172
|
}
|
|
2013
2173
|
if (!r.ref)
|
|
2014
2174
|
continue;
|
|
2015
2175
|
if (regKey === "chat") {
|
|
2016
|
-
out[String(r.workspace == null ? "" : r.workspace) + "\t" + String(r.ref)] = true;
|
|
2017
|
-
out["\t" + String(r.ref)] = true;
|
|
2176
|
+
out[String(r.workspace == null ? "" : r.workspace) + "\t" + String(r.ref).trim()] = true;
|
|
2177
|
+
out["\t" + String(r.ref).trim()] = true;
|
|
2018
2178
|
continue;
|
|
2019
2179
|
}
|
|
2020
|
-
out[String(r.ref)] = true;
|
|
2180
|
+
out[String(r.ref).trim()] = true;
|
|
2021
2181
|
}
|
|
2022
2182
|
return out;
|
|
2023
2183
|
}
|
|
@@ -3926,6 +4086,12 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
3926
4086
|
.ds-all-connected { color: var(--muted); }
|
|
3927
4087
|
.ds-gate { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; font-weight: 600; flex: 0 0 auto; }
|
|
3928
4088
|
.ds-gate-at { font-size: 11px; color: var(--muted); flex: 0 0 auto; }
|
|
4089
|
+
/* 実行ログへの導線(#560)。時刻の横の添え物なので .ds-gate-at と同じ弱さ。押せることだけ
|
|
4090
|
+
点線の下線で示す(目立たせない——案件リポジトリに入っていない人には開けない) */
|
|
4091
|
+
.ds-run-link { font-size: 11px; color: var(--muted); flex: 0 0 auto; text-decoration: underline dotted; text-underline-offset: 2px; }
|
|
4092
|
+
.ds-run-link:hover { color: var(--text); }
|
|
4093
|
+
/* run の無い書き手の行の出どころ(「中央の処理」「その場で確認」)。同じ弱さの文字 */
|
|
4094
|
+
.ds-run-src { font-size: 11px; color: var(--muted); flex: 0 0 auto; }
|
|
3929
4095
|
/* 接続先1件ごとの「取り込み」(段C・2026-08-24)。**「最終同期」(.ds-sync・run単位)とは
|
|
3930
4096
|
別の行に並ぶ**ので、同じ強さにしない——run の時刻より弱い添え物として読ませる。
|
|
3931
4097
|
失敗だけは .ds-gate-warn と同じ色にする(同じ画面で警告の色が2種類あると、
|
|
@@ -4445,6 +4611,7 @@ var PROBE_WAIT_TIMEOUT_TEXT = ${JSON.stringify(exports.PROBE_WAIT_TIMEOUT_TEXT)}
|
|
|
4445
4611
|
${sanitizeRegisteredNow.toString()}
|
|
4446
4612
|
${chatRowsToAdd.toString()}
|
|
4447
4613
|
${gchatRowsToAdd.toString()}
|
|
4614
|
+
${overlayGchatNotify.toString()}
|
|
4448
4615
|
${devRowsToAdd.toString()}
|
|
4449
4616
|
${markExcludedPendingRows.toString()}
|
|
4450
4617
|
${designRowsToAdd.toString()}
|
|
@@ -4490,6 +4657,12 @@ ${pending_ops_1.pendingCountDelta.toString()}
|
|
|
4490
4657
|
${pending_ops_1.pendingIssuesRef.toString()}
|
|
4491
4658
|
var STATE_STATUSES = ${JSON.stringify(STATE_STATUSES)};
|
|
4492
4659
|
var STATE_ROW_FIELDS = ${JSON.stringify(STATE_ROW_FIELDS)};
|
|
4660
|
+
// 行の runUrl の形と、出どころの語(#560)。**正規表現は JSON にできない**ので
|
|
4661
|
+
// source から組み立てる。この定数行を落とすと sanitizeStateNow が未定義を参照して
|
|
4662
|
+
// ライブ取得が丸ごと死ぬ
|
|
4663
|
+
var RUN_URL_RE = new RegExp(${JSON.stringify(RUN_URL_RE.source)});
|
|
4664
|
+
var RUN_URL_WRITERS = ${JSON.stringify(RUN_URL_WRITERS)};
|
|
4665
|
+
var RUN_SOURCE_WORDS = ${JSON.stringify(RUN_SOURCE_WORDS)};
|
|
4493
4666
|
${sanitizeStateNow.toString()}
|
|
4494
4667
|
${overlayStateOnFleet.toString()}
|
|
4495
4668
|
// Home の「使用ツール」(#275)。**判定と表示語の実体はビルド時の定義**——
|
|
@@ -4522,6 +4695,10 @@ ${stateRefKey.toString()}
|
|
|
4522
4695
|
${registeredRefKeys.toString()}
|
|
4523
4696
|
${fleetLastSyncOf.toString()}
|
|
4524
4697
|
${ingestedAtOf.toString()}
|
|
4698
|
+
${ingestedRowOf.toString()}
|
|
4699
|
+
${runLogUrlOf.toString()}
|
|
4700
|
+
${lastSyncRunUrlOf.toString()}
|
|
4701
|
+
${runSourceWordOf.toString()}
|
|
4525
4702
|
var TILE_CAPS = ${JSON.stringify(TILE_CAPS)};
|
|
4526
4703
|
var BAD_STATE_STATUSES = ${JSON.stringify(BAD_STATE_STATUSES)};
|
|
4527
4704
|
// 登録直後の一時表示(#523 決定6)。**この定数行を落とすと、流し込んだ deriveCapTile が
|
|
@@ -8998,9 +9175,18 @@ ${calendarAddUrl.toString()}
|
|
|
8998
9175
|
function capBlockSyncEl(s, inactive) {
|
|
8999
9176
|
if (inactive || !s || !s.kind) return null;
|
|
9000
9177
|
var capId = capIdOf(s.kind);
|
|
9001
|
-
var
|
|
9178
|
+
var refs = capId ? refKeysOf(derCapOf(s.kind, "")) : null;
|
|
9179
|
+
var at = capId ? ingestedAtOf(LIVE_STATE, capId, refs) : "";
|
|
9002
9180
|
var t = dsFmtTime(at || fleetSyncFallback(s) || "");
|
|
9003
|
-
|
|
9181
|
+
if (!t) return null;
|
|
9182
|
+
var sync = el("span", { class: "ds-sync", text: "最終同期: " + t });
|
|
9183
|
+
// その時刻を書いた run へ(#560)。**ストア由来の時刻のときだけ**——まとめ表の後詰めに
|
|
9184
|
+
// run は無い。行は「ingestedAtOf」 と同じ選び方(「ingestedRowOf」)で取る。
|
|
9185
|
+
// run の無い書き手(中央 Apps Script の会議・資料の取り込み)は出どころの語
|
|
9186
|
+
var row = at ? ingestedRowOf(LIVE_STATE, capId, refs) : null;
|
|
9187
|
+
var url = lastSyncRunUrlOf(row);
|
|
9188
|
+
var trail = url ? [runLogLink(url)] : row ? runTrailNodes(row, "") : [];
|
|
9189
|
+
return trail.length ? frag([sync].concat(trail)) : sync;
|
|
9004
9190
|
}
|
|
9005
9191
|
|
|
9006
9192
|
if (internals.length) {
|
|
@@ -10365,6 +10551,8 @@ ${calendarAddUrl.toString()}
|
|
|
10365
10551
|
// 古い「X分前に確認」を残さない(下に出るいまの結果と、時刻が2つ並ぶ)
|
|
10366
10552
|
var oldAt = card.querySelector(".ds-gate-at");
|
|
10367
10553
|
if (oldAt) oldAt.remove();
|
|
10554
|
+
// 古い run の導線も残さない(#560)。「いま測った結果」の横に夜間の run のログが並ぶ形になる
|
|
10555
|
+
removeRunTrail(card);
|
|
10368
10556
|
// 🔴 **古いスコープ名の札も必ず消してから出し直す。** 行には夜間の判定に添えた
|
|
10369
10557
|
// 札が出ていることがあり(段B)、置き換えた「接続OK」の横に古いスコープ名が
|
|
10370
10558
|
// 残ると、同じ行が2つのことを言う——この節が何度も直してきた形そのもの。
|
|
@@ -10503,6 +10691,9 @@ ${calendarAddUrl.toString()}
|
|
|
10503
10691
|
"次回の Gold 昇格(毎晩22時ごろ)から、このスペースは読み取られなくなります。",
|
|
10504
10692
|
"",
|
|
10505
10693
|
"※ 既に Gold 層に入った内容は消えません(Decision・用語集はそのまま残ります)。",
|
|
10694
|
+
// 解除は通知先の宣言(notify.json)を触らない(#572)。通知先のまま解除すると
|
|
10695
|
+
// 行が消えて画面から止められなくなる——先に止める手順をここで言う
|
|
10696
|
+
"※ 通知先にしている場合は、先に「通知を止める」を押してください(解除しても通知先は変わりません)。",
|
|
10506
10697
|
"",
|
|
10507
10698
|
"解除しますか?",
|
|
10508
10699
|
];
|
|
@@ -10561,6 +10752,12 @@ ${calendarAddUrl.toString()}
|
|
|
10561
10752
|
*
|
|
10562
10753
|
* **クロージャを持たない純関数に保つこと**(テストが配信物から切り出して直接呼ぶ)。
|
|
10563
10754
|
* だから issuesRefOf を呼べない(規則の正本はあちら側。直すときは両方直す)。
|
|
10755
|
+
*
|
|
10756
|
+
* ⚠ **ここは前後の空白を落とさない。行の鍵(issuesRefOf)とは別物**(#556)。
|
|
10757
|
+
* 揃えたくなるが、**揃えなくても食い違わない**——サーバは受け取った世代を
|
|
10758
|
+
* normalizeGeneration に通してから比べ、そちらが空白を落とすため。逆に、ここで
|
|
10759
|
+
* 落とす形に変えるなら**サーバの両方**(targetsGeneration と normalizeGeneration)を
|
|
10760
|
+
* 同時に見ること。善意で片側だけ揃えると、正しい操作が毎回 409 になる。
|
|
10564
10761
|
*/
|
|
10565
10762
|
function targetsGenerationOf(list) {
|
|
10566
10763
|
return (list || [])
|
|
@@ -10810,13 +11007,66 @@ ${calendarAddUrl.toString()}
|
|
|
10810
11007
|
// cap と question の両方で絞る。片方だけだと、同じ ref を持つ別の問い
|
|
10811
11008
|
//(将来 issues に別の question が増えたとき)の行を取り込みとして読む
|
|
10812
11009
|
if (!r || r.cap !== "issues" || r.question !== "ingested") continue;
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
if (
|
|
11010
|
+
// 行側も畳み方の正本(stateRefKey = normalizeStateRef の写し)を通す(#556)。
|
|
11011
|
+
// ここで indexOf を自前で切っていた間は、**切り方が5本目**になっていた
|
|
11012
|
+
if (stateRefKey("issues", r.ref) === want) return r;
|
|
10816
11013
|
}
|
|
10817
11014
|
return null;
|
|
10818
11015
|
}
|
|
10819
11016
|
|
|
11017
|
+
/* -------------------------------------------------------------------------
|
|
11018
|
+
* 実行ログへの導線(#560)
|
|
11019
|
+
* -------------------------------------------------------------------------
|
|
11020
|
+
* 行の 「runUrl」(その行を書いた Actions の run)があれば、時刻の横に小さな「実行ログ ↗」を
|
|
11021
|
+
* 出す。run の無い書き手の行は、出どころを語で示す(「中央の処理」「その場で確認」)。
|
|
11022
|
+
* どちらを出すかの判断は純関数(runLogUrlOf / runSourceWordOf)が持ち、ここは描くだけ。
|
|
11023
|
+
* ----------------------------------------------------------------------- */
|
|
11024
|
+
|
|
11025
|
+
/** リンクの title。案件リポジトリに入っていない人には開けないので、押す前に分かるようにする */
|
|
11026
|
+
var RUN_LINK_TITLE = "GitHub Actions の実行ログを開きます(案件リポジトリへのアクセスが要ります)";
|
|
11027
|
+
/** 一覧(開始直後・run の番号がまだ無い)の title。飛び先が違うので文言も分ける */
|
|
11028
|
+
var RUN_LIST_TITLE = "GitHub Actions の実行の一覧を開きます(案件リポジトリへのアクセスが要ります)";
|
|
11029
|
+
var RUN_LIST_TEXT = "実行の一覧 ↗";
|
|
11030
|
+
|
|
11031
|
+
/** 「実行ログ ↗」(新しいタブ・title つき)。一覧のときは文言と title を一覧のものにする */
|
|
11032
|
+
function runLogLink(url, text) {
|
|
11033
|
+
var list = text === RUN_LIST_TEXT;
|
|
11034
|
+
return el("a", { class: "ds-run-link", href: url, target: "_blank", rel: "noopener", title: list ? RUN_LIST_TITLE : RUN_LINK_TITLE, text: text || "実行ログ ↗" });
|
|
11035
|
+
}
|
|
11036
|
+
|
|
11037
|
+
/**
|
|
11038
|
+
* 行の時刻の横に添えるもの(リンクか出どころの語)。**無ければ空配列。**
|
|
11039
|
+
* 「.ds-gate-at」「.ds-ingest」 の**兄弟**として置く(子にすると、文言の検査と
|
|
11040
|
+
* 「いま測った結果」への差し替えが崩れる)。
|
|
11041
|
+
*
|
|
11042
|
+
* @param kind どの時刻に添えたか(「gate」=「◯分前に確認」)。「いま測った結果」への差し替えは
|
|
11043
|
+
* **この印のものだけ**消す——「取り込み: 〜に成功」の横のリンク(別の行の run)は残す
|
|
11044
|
+
*/
|
|
11045
|
+
function runTrailNodes(row, url, kind) {
|
|
11046
|
+
var u = url === undefined ? runLogUrlOf(row) : url;
|
|
11047
|
+
var word = u ? "" : runSourceWordOf(row);
|
|
11048
|
+
var node = u ? runLogLink(u) : word ? el("span", { class: "ds-run-src", text: word }) : null;
|
|
11049
|
+
if (!node) return [];
|
|
11050
|
+
if (kind) node.setAttribute("data-trail", kind);
|
|
11051
|
+
return [node];
|
|
11052
|
+
}
|
|
11053
|
+
|
|
11054
|
+
/** 複数のノードを 1 つの子として返す(「el」 の children に並べるため) */
|
|
11055
|
+
function frag(nodes) {
|
|
11056
|
+
var f = document.createDocumentFragment();
|
|
11057
|
+
(nodes || []).forEach(function (n) { if (n) f.appendChild(n); });
|
|
11058
|
+
return f;
|
|
11059
|
+
}
|
|
11060
|
+
|
|
11061
|
+
/**
|
|
11062
|
+
* 「いま測った結果」に差し替えるとき、**「◯分前に確認」に添えた**古い run の導線を外す
|
|
11063
|
+
* (同じ行が 2 つのことを言わない)。「取り込み: 〜に成功」の横のリンクは別の行の run なので残す
|
|
11064
|
+
*/
|
|
11065
|
+
function removeRunTrail(scope) {
|
|
11066
|
+
var old = scope.querySelectorAll('.ds-run-link[data-trail="gate"], .ds-run-src[data-trail="gate"]');
|
|
11067
|
+
for (var i = 0; i < old.length; i++) old[i].remove();
|
|
11068
|
+
}
|
|
11069
|
+
|
|
10820
11070
|
/**
|
|
10821
11071
|
* 接続先1件の「取り込み」の表示。**測っていなければ何も出さない(null)。**
|
|
10822
11072
|
*
|
|
@@ -10839,10 +11089,12 @@ ${calendarAddUrl.toString()}
|
|
|
10839
11089
|
// 語は鍵カードの名前と揃える(keyMissingText の項)
|
|
10840
11090
|
else if (r.status === "skipped") text = "取り込み: 未実行(" + keyMissingText(cap) + ")";
|
|
10841
11091
|
if (!text) return null;
|
|
10842
|
-
|
|
11092
|
+
var span = el("span", {
|
|
10843
11093
|
class: "ds-ingest" + (r.status === "failed" ? " ds-ingest-failed" : ""),
|
|
10844
11094
|
text: text,
|
|
10845
11095
|
});
|
|
11096
|
+
// その行を書いた run へ(#560)。成功でも失敗でも、この時刻を書いた run のログ
|
|
11097
|
+
return frag([span].concat(runTrailNodes(r)));
|
|
10846
11098
|
}
|
|
10847
11099
|
|
|
10848
11100
|
/**
|
|
@@ -10884,6 +11136,8 @@ ${calendarAddUrl.toString()}
|
|
|
10884
11136
|
row.appendChild(el("span", { class: "ds-gate " + gate.cls, text: gate.text }));
|
|
10885
11137
|
var when = rtAgo(r.at);
|
|
10886
11138
|
if (when) row.appendChild(el("span", { class: "ds-gate-at", text: when + "に確認" }));
|
|
11139
|
+
// その行を書いた run へ(#560)。run の無い書き手は出どころの語
|
|
11140
|
+
runTrailNodes(r, undefined, "gate").forEach(function (n) { row.appendChild(n); });
|
|
10887
11141
|
return row;
|
|
10888
11142
|
}
|
|
10889
11143
|
|
|
@@ -11032,12 +11286,30 @@ ${calendarAddUrl.toString()}
|
|
|
11032
11286
|
at: (before && before.at) || "",
|
|
11033
11287
|
startedAt: Date.now(),
|
|
11034
11288
|
message: (j && j.message) || "",
|
|
11289
|
+
// 起こした run(特定できた回)と一覧(#560)。描き直しでもリンクが消えないよう控える
|
|
11290
|
+
runUrl: (j && RUN_URL_RE.test(String(j.runUrl || ""))) ? String(j.runUrl) : "",
|
|
11291
|
+
runsUrl: (j && /^https:\\/\\/github\\.com\\/[^\\s"'<>]+$/.test(String(j.runsUrl || ""))) ? String(j.runsUrl) : "",
|
|
11035
11292
|
};
|
|
11036
|
-
note
|
|
11293
|
+
probeWaitNote(note, PROBE_WAITS[key]);
|
|
11037
11294
|
// 待っているあいだは取り直しを回す(届いた行で一覧が描き直される)
|
|
11038
11295
|
refreshStateTimer();
|
|
11039
11296
|
}
|
|
11040
11297
|
|
|
11298
|
+
/**
|
|
11299
|
+
* 待ちの 1 文と、その横の導線(#560)。**その run を特定できていればそれ、無ければ一覧。**
|
|
11300
|
+
* 開始直後は run の番号が無いことが多いので一覧へ。行が更新されて待ちが解けたら、
|
|
11301
|
+
* 行側の「実行ログ ↗」(その run)に置き換わる。run の無い経路(固定 IP・中央)は何も出ない
|
|
11302
|
+
*/
|
|
11303
|
+
function probeWaitNote(note, wait) {
|
|
11304
|
+
note.textContent = (wait && wait.message) || "";
|
|
11305
|
+
if (!wait) return;
|
|
11306
|
+
var link = wait.runUrl ? runLogLink(wait.runUrl) : wait.runsUrl ? runLogLink(wait.runsUrl, RUN_LIST_TEXT) : null;
|
|
11307
|
+
if (link) {
|
|
11308
|
+
note.appendChild(document.createTextNode(" "));
|
|
11309
|
+
note.appendChild(link);
|
|
11310
|
+
}
|
|
11311
|
+
}
|
|
11312
|
+
|
|
11041
11313
|
/**
|
|
11042
11314
|
* 即答(#548 の direct)を行に映す。**「probeSection」 と同じ見た目にする**——
|
|
11043
11315
|
* 夜間のスナップショットの判定といま測った判定を**同じ行に並べない**ため
|
|
@@ -11074,6 +11346,8 @@ ${calendarAddUrl.toString()}
|
|
|
11074
11346
|
row.insertBefore(at, anchor);
|
|
11075
11347
|
}
|
|
11076
11348
|
at.textContent = "いま測った結果(" + (dsFmtTime(j.checkedAt) || "たった今") + ")";
|
|
11349
|
+
// 古い run の導線も外す(#560)。残すと「いま測った結果」の横に夜間の run のログが並ぶ
|
|
11350
|
+
removeRunTrail(row);
|
|
11077
11351
|
// **夜間の判定に添えてあった案内は隠す。** 置き換えた判定と食い違う案内が下に残ると、
|
|
11078
11352
|
// 同じ行が2つのことを言う(probeSection の stale 処理と同じ)
|
|
11079
11353
|
var stale = row.querySelectorAll(".ds-gate-help");
|
|
@@ -11111,8 +11385,13 @@ ${calendarAddUrl.toString()}
|
|
|
11111
11385
|
var note = el("p", { class: "ds-probe-wait" });
|
|
11112
11386
|
var phase = probeWaitPhaseOf(capId, ref);
|
|
11113
11387
|
var wait = probeWaitOf(capId, ref);
|
|
11114
|
-
if (phase === "waiting") note
|
|
11115
|
-
else if (phase === "timeout")
|
|
11388
|
+
if (phase === "waiting") probeWaitNote(note, wait);
|
|
11389
|
+
else if (phase === "timeout") {
|
|
11390
|
+
// 15 分待って届かないなら見に行く番。**行き先を添える**(#560)——一覧でも run でも
|
|
11391
|
+
note.textContent = PROBE_WAIT_TIMEOUT_TEXT;
|
|
11392
|
+
var to = wait && (wait.runUrl || wait.runsUrl);
|
|
11393
|
+
if (to) { note.appendChild(document.createTextNode(" ")); note.appendChild(runLogLink(to, wait.runUrl ? "実行ログ ↗" : RUN_LIST_TEXT)); }
|
|
11394
|
+
}
|
|
11116
11395
|
else note.hidden = true;
|
|
11117
11396
|
|
|
11118
11397
|
checkBtn.addEventListener("click", async function () {
|
|
@@ -12427,7 +12706,7 @@ ${calendarAddUrl.toString()}
|
|
|
12427
12706
|
// 起動できなかった案件(権限・スタブ未配布)ではリンクを出さない——押しても何も無い
|
|
12428
12707
|
if (j.runsUrl) {
|
|
12429
12708
|
msg.appendChild(document.createTextNode(" "));
|
|
12430
|
-
msg.appendChild(el("a", { href: j.runsUrl, target: "_blank", rel: "noopener", text: "実行状況を見る →" }));
|
|
12709
|
+
msg.appendChild(el("a", { href: j.runUrl || j.runsUrl, target: "_blank", rel: "noopener", title: RUN_LINK_TITLE, text: "実行状況を見る →" })); // その run を特定できていればそれ(#560)、無ければ一覧
|
|
12431
12710
|
}
|
|
12432
12711
|
// **「反映の状況 →」のリンクは無くなった(#221・2026-08-25)。** 指していたのは
|
|
12433
12712
|
// 「画面を追いつかせるための fleet-status の実行」で、その起動ごと撤去した
|
|
@@ -12977,6 +13256,8 @@ ${calendarAddUrl.toString()}
|
|
|
12977
13256
|
var gateAtEl = s.gateAt
|
|
12978
13257
|
? el("span", { class: "ds-gate-at", text: rtAgo(s.gateAt) + "に確認" })
|
|
12979
13258
|
: null;
|
|
13259
|
+
// その行を書いた run へ(#560)。overlay が写した 「gateRunUrl」 / 「gateBy」 から決める
|
|
13260
|
+
var gateTrail = s.gateAt ? runTrailNodes({ runUrl: s.gateRunUrl || "", by: s.gateBy || "" }, undefined, "gate") : [];
|
|
12980
13261
|
var card = el("div", { class: "ds-card" }, [
|
|
12981
13262
|
el("div", { class: "ds-card-main" }, [
|
|
12982
13263
|
el("span", { class: "ds-icon", text: meta.icon }),
|
|
@@ -12999,6 +13280,7 @@ ${calendarAddUrl.toString()}
|
|
|
12999
13280
|
card.appendChild(el("code", { class: "ds-probe-scope", text: String(s.needed) }));
|
|
13000
13281
|
}
|
|
13001
13282
|
if (gateAtEl) card.appendChild(gateAtEl);
|
|
13283
|
+
gateTrail.forEach(function (n) { card.appendChild(n); });
|
|
13002
13284
|
// チャンネルの登録解除。書き込み経路(intake Lambda)がある案件でだけ出す。
|
|
13003
13285
|
// **Slack だけ。** github は登録ファイルが別(dev-sources.json)で、下のトグルと
|
|
13004
13286
|
// 「登録から削除」が担う。
|
|
@@ -13021,6 +13303,11 @@ ${calendarAddUrl.toString()}
|
|
|
13021
13303
|
// だけなので、Slack のような origin の出し分けは不要
|
|
13022
13304
|
if (SITE.intake && s.type === "google-chat" && s.ref) {
|
|
13023
13305
|
card.appendChild(removeSpaceButton(s, card));
|
|
13306
|
+
// 通知先の入り切り(#572)。Slack と同じ notifyToggle・同じ文言・同じ op(サーバは
|
|
13307
|
+
// ref の形(spaces/…)で Google Chat と判定する)。スペースの行に workspace は無いので
|
|
13308
|
+
// 「読み取り専用の接続」の分岐には入らず、常にボタンが出る。仮置きの行(本物の行が
|
|
13309
|
+
// 来るまで)には Slack と同じく出さない
|
|
13310
|
+
if (s.pending !== true) card.appendChild(notifyToggle(s, badges));
|
|
13024
13311
|
}
|
|
13025
13312
|
// GitHubリポの登録から削除。**ON/OFF のトグルは撤去した(2026-08-21)**
|
|
13026
13313
|
//(stateToggle のコメント参照)。
|
|
@@ -14027,7 +14314,7 @@ ${calendarAddUrl.toString()}
|
|
|
14027
14314
|
// 起動できたときだけ、実行状況への導線を出す(鍵を入れた直後に効いたか確かめられる)
|
|
14028
14315
|
if (j.runsUrl) {
|
|
14029
14316
|
msg.appendChild(document.createTextNode(" "));
|
|
14030
|
-
msg.appendChild(el("a", { href: j.runsUrl, target: "_blank", rel: "noopener", text: "実行状況を見る →" }));
|
|
14317
|
+
msg.appendChild(el("a", { href: j.runUrl || j.runsUrl, target: "_blank", rel: "noopener", title: RUN_LINK_TITLE, text: "実行状況を見る →" })); // その run を特定できていればそれ(#560)、無ければ一覧
|
|
14031
14318
|
}
|
|
14032
14319
|
// 入れた値は画面に残さない(肩越しに見えるのを防ぐ)
|
|
14033
14320
|
input.value = "";
|
package/package.json
CHANGED