@takagaki/cortex-decisions-viewer 0.5.0 → 0.7.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/build.js +55 -1
- package/dist/cli.js +1 -1
- package/dist/render.js +1032 -312
- package/package.json +3 -2
package/dist/render.js
CHANGED
|
@@ -1107,6 +1107,17 @@ a:hover { text-decoration: underline; }
|
|
|
1107
1107
|
display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px;
|
|
1108
1108
|
}
|
|
1109
1109
|
.ds-card-main { display: flex; align-items: center; gap: 10px; flex: 1 1 auto; min-width: 0; }
|
|
1110
|
+
/* 能力モーダルの中身は**箱に入れない**(2026-08-21・オーナー実機指摘)。
|
|
1111
|
+
かつては .ds-card.ds-capbody という枠で包み、その中に「📋 課題管理 Backlog」と
|
|
1112
|
+
能力名まで書いていた。押しているのは Backlog のタイルで、**モーダルの見出しも
|
|
1113
|
+
ツール名(Backlog)**なので、枠と能力名は「課題管理・Backlog」という入れ子の
|
|
1114
|
+
重複でしかなかった。いまは見出しの直下へ中身をそのまま並べ、ここは
|
|
1115
|
+
**縦に積む役だけ**を持つ(枠線・背景・影は持たない)。
|
|
1116
|
+
⚠ **枠が無くなったので、未使用(enabled: false)の灰色の破線は出ない。**
|
|
1117
|
+
代わりに未使用を示すのは (1) 下の .ds-inactive の子孫ルール(中の文字が灰色になる)と
|
|
1118
|
+
(2)「未使用(この案件では設定されていません)」の一行(.ds-inactive-note)。
|
|
1119
|
+
モーダルは1つの能力しか映さないので、他の行と並べて灰色で見分ける必要が無い。 */
|
|
1120
|
+
.ds-capblock { display: flex; flex-direction: column; gap: 10px; }
|
|
1110
1121
|
.ds-icon { font-size: 18px; line-height: 1; flex: 0 0 auto; }
|
|
1111
1122
|
.ds-type { font-size: 12px; font-weight: 600; color: var(--muted); flex: 0 0 auto; }
|
|
1112
1123
|
.ds-name { font-size: 14.5px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -1271,7 +1282,7 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1271
1282
|
min-width: 0 … flex の子が min-content より縮めるようにする(無いと折り返しても溢れる) */
|
|
1272
1283
|
.ds-tile-name, .ds-tile-desc, .ds-tile-sub, .ds-tile-note,
|
|
1273
1284
|
.ds-check-label, .ds-check-action, .ds-check-detail,
|
|
1274
|
-
.ds-pipe-label, .ds-pipe-todo,
|
|
1285
|
+
.ds-pipe-label, .ds-pipe-todo,
|
|
1275
1286
|
.ds-empty, .sec-how, .modal-desc, .ds-toggle-msg,
|
|
1276
1287
|
.ds-drive-note, .ds-inactive-note, .ds-legacy-chip, .ds-keys-code, .ds-gate-help {
|
|
1277
1288
|
min-width: 0; white-space: normal; overflow-wrap: anywhere;
|
|
@@ -1282,14 +1293,20 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1282
1293
|
.ds-toggle-btn:disabled { opacity: .6; cursor: default; }
|
|
1283
1294
|
.ds-toggle-btn.ds-danger { color: #b42318; border-color: #f3c6c1; }
|
|
1284
1295
|
.ds-toggle-btn.ds-danger:hover:not(:disabled) { border-color: #b42318; color: #b42318; background: #fff5f4; }
|
|
1285
|
-
.ds-subitems
|
|
1286
|
-
|
|
1296
|
+
/* .ds-subitems / .ds-subitem は撤去した(2026-08-21)。共有資料のフォルダと Figma の
|
|
1297
|
+
ファイルの行は、Slack / GitHub と同じ .ds-list > .ds-card になったので、
|
|
1298
|
+
行間(gap)も .ds-list に揃う。**.ds-removed の規則は .ds-subitem に依存していない**
|
|
1299
|
+
ので、そのまま両方の行に効く。 */
|
|
1287
1300
|
/* 削除できたことを行に残す。一覧そのものは翌朝まで更新されないので、消えたように見せない */
|
|
1288
1301
|
.ds-removed .ds-name { text-decoration: line-through; color: var(--muted); }
|
|
1289
1302
|
.ds-toggle-msg { font-size: 12px; color: var(--muted); }
|
|
1290
1303
|
.ds-toggle-msg.is-ok { color: #1a7f37; }
|
|
1291
1304
|
.ds-toggle-msg.is-error { color: #b42318; }
|
|
1292
1305
|
.badge.ds-notify { background: #eff6ff; color: #1e40af; border: 1px solid #bfdbfe; }
|
|
1306
|
+
/* 読み取りを止めてあるリポジトリ(2026-08-21)。**それまではトグルの向きが示していた**ので、
|
|
1307
|
+
トグルを撤去したいま、読み取られていないことを示すのはこのバッジだけ。
|
|
1308
|
+
**判断のバッジなので、由来や組織のバッジより強く出す** */
|
|
1309
|
+
.badge.ds-excluded { background: #f3f4f6; color: #4b5563; border: 1px solid #d1d5db; }
|
|
1293
1310
|
/* 登録の由来(#118)。**薄く出す**——読み取りの可否や Gold 対象かより弱い情報で、
|
|
1294
1311
|
ここが目立つと「除外」「未宣言」の判断のバッジと同じ強さに見えてしまう */
|
|
1295
1312
|
.badge.ds-origin { background: transparent; color: var(--muted); border: 1px dashed var(--border); }
|
|
@@ -1337,13 +1354,10 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1337
1354
|
とは別物で、同じ色にすると「押して繋ぎましょう」と読まれる */
|
|
1338
1355
|
.ds-gate-off { color: #9ca3af; }
|
|
1339
1356
|
.ds-pipes { display: flex; flex-direction: column; gap: 8px; }
|
|
1340
|
-
/*
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
.ds-owner-name { font-weight: 700; font-size: 13px; }
|
|
1345
|
-
.ds-owner-state { font-size: 12.5px; }
|
|
1346
|
-
.ds-owner-install { font-size: 12.5px; margin-left: auto; white-space: nowrap; }
|
|
1357
|
+
/* GitHub App のインストールへのリンク。**独立した「組織ごとの接続状況」の節は
|
|
1358
|
+
2026-08-20 に廃止した**(行のラベル+必要な行だけ囲う形へ)が、
|
|
1359
|
+
このクラスだけは案内と手順の両方で使い続けている */
|
|
1360
|
+
.ds-owner-install { font-size: 12.5px; white-space: nowrap; }
|
|
1347
1361
|
/* 実行状況の行に直し方を添える。同じ run の未達を別の節にも出すと画面に2回並ぶ */
|
|
1348
1362
|
.ds-pipe-wrap { display: flex; flex-direction: column; gap: 3px; }
|
|
1349
1363
|
.ds-pipe-todo { font-size: 12.5px; color: var(--muted); line-height: 1.7; padding-left: 4px; }
|
|
@@ -1360,6 +1374,31 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1360
1374
|
.sec-state { font-size: 12.5px; font-weight: 600; margin: 0 0 8px; color: var(--muted); }
|
|
1361
1375
|
.sec-state.is-managed { color: #1a7f37; }
|
|
1362
1376
|
.sec-state.is-none { color: var(--muted); font-weight: 400; }
|
|
1377
|
+
/* 登録されているか分からない(engine がスペース別の状況をまだ出していない)。
|
|
1378
|
+
**未登録と同じ見た目にしない**——断定していないことが色でも分かるようにする */
|
|
1379
|
+
.sec-state.is-unknown { color: var(--muted); font-weight: 400; font-style: italic; }
|
|
1380
|
+
/* 鍵の欄の置き場(2026-08-21)。レコードの行の中と、一覧の直後の2か所で使う。
|
|
1381
|
+
**.ds-card は flex-wrap: wrap の横並び**なので、100% の basis を与えて
|
|
1382
|
+
行の中で自分の段へ落とす(行そのものの並びは変えない——縦組みのクラスを
|
|
1383
|
+
流用すると Slack / GitHub の行まで縦に割れる)。 */
|
|
1384
|
+
.ds-keyrow { flex: 1 1 100%; min-width: 0; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
|
|
1385
|
+
/* 一覧の直後に置くとき(Figma)は、行の中ではないので区切り線を持たない */
|
|
1386
|
+
.ds-keyrow-list { margin-top: 10px; padding-top: 0; border-top: none; }
|
|
1387
|
+
/* 行の中に入った鍵カードは、カードの枠を持たない(行の一部に見せる) */
|
|
1388
|
+
.ops-card.ds-keycard { border: none; box-shadow: none; padding: 0; background: transparent; gap: 6px; }
|
|
1389
|
+
.ops-card.ds-keycard > .ops-card-head { gap: 8px; }
|
|
1390
|
+
.ops-card.ds-keycard .ops-card-icon { font-size: 16px; }
|
|
1391
|
+
.ops-card.ds-keycard .ops-card-title { font-size: 13px; }
|
|
1392
|
+
/* 押すまで入力欄を出さない(2026-08-21・オーナー指摘)。summary はボタンに見せる */
|
|
1393
|
+
.sec-input-fold { border: none; margin: 0; }
|
|
1394
|
+
.sec-input-fold > summary {
|
|
1395
|
+
cursor: pointer; display: inline-block; list-style: none;
|
|
1396
|
+
padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border);
|
|
1397
|
+
background: #fff; color: var(--text); font-size: 12.5px; font-weight: 600;
|
|
1398
|
+
}
|
|
1399
|
+
.sec-input-fold > summary::-webkit-details-marker { display: none; }
|
|
1400
|
+
.sec-input-fold > summary:hover { border-color: var(--accent); color: var(--accent); }
|
|
1401
|
+
.sec-input-fold[open] > summary { margin-bottom: 8px; }
|
|
1363
1402
|
.ds-addform { border: 1px dashed var(--border); border-radius: 8px; padding: 12px 14px; margin-top: 10px; background: #fff; }
|
|
1364
1403
|
.ds-addform-title { font-size: 13px; font-weight: 700; color: var(--text); margin-bottom: 6px; }
|
|
1365
1404
|
.ds-addform .sec-input { margin-bottom: 6px; }
|
|
@@ -1368,17 +1407,10 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1368
1407
|
/* 「この接続は何のためのものでないか」(2026-08-18)。**説明文より強く出す**——
|
|
1369
1408
|
ここを読み飛ばした人が、社内チャンネルのためにボタンを押し、必ず失敗する */
|
|
1370
1409
|
.ds-scope-note { color: var(--text); }
|
|
1371
|
-
/*
|
|
1372
|
-
.ds-
|
|
1373
|
-
.ds-
|
|
1374
|
-
.ds-
|
|
1375
|
-
.ds-current-value.is-unset { color: var(--muted); font-weight: 400; }
|
|
1376
|
-
/* 接続先の一覧(#127)。**1件のときは従来どおりラベルの右に1行**——単数の案件で
|
|
1377
|
-
見た目が変わると、複数対応と関係のない全案件に「何か変わった」と読ませる */
|
|
1378
|
-
.ds-target-list { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
|
1379
|
-
.ds-target-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
|
|
1380
|
-
/* 行の中のボタンは行に揃える(.ds-toggle の縦マージンは節と節の間隔なので効かせない) */
|
|
1381
|
-
.ds-target-row .ds-toggle-btn { flex: 0 0 auto; }
|
|
1410
|
+
/* .ds-current / .ds-current-label / .ds-current-value / .ds-target-list /
|
|
1411
|
+
.ds-target-row は撤去した(2026-08-21)。Backlog の接続先の行は、Slack / GitHub /
|
|
1412
|
+
Figma / Drive と同じ .ds-list > .ds-card になったので、行間も見た目も .ds-list と
|
|
1413
|
+
.ds-card に揃う(それまでは同じモーダルの中でここだけ独自レイアウトだった)。 */
|
|
1382
1414
|
/* 入力欄のすぐ下。貼る直前に読める位置に置く */
|
|
1383
1415
|
.sec-note { color: var(--muted); font-size: 12px; line-height: 1.7; margin: 6px 0 0; }
|
|
1384
1416
|
.sec-how p { margin: 0; }
|
|
@@ -1394,6 +1426,12 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1394
1426
|
padding: 18px; box-shadow: var(--shadow); display: flex; flex-direction: column; gap: 10px;
|
|
1395
1427
|
}
|
|
1396
1428
|
/* リアルタイム同期の設定手順(#113)。番号付きなのは「上から順に1回やる」作業だから */
|
|
1429
|
+
/* **上に余白を置く(2026-08-21・オーナー実機指摘「リアルタイム同期のセクションが
|
|
1430
|
+
くっついてて気持ち悪かった。上のスペースがないから違和感ある」)。**
|
|
1431
|
+
直前に来るのは接続先の追加フォーム(.ds-addform)で、そちらは margin-top: 10px を
|
|
1432
|
+
持っている。こちらが 0 だと2つの箱が接して1枚に見える。**同じ 10px で釣り合わせる。**
|
|
1433
|
+
⚠ CSS は jsdom から見えないので、この余白はテストでは守れない(実機で見ること)。 */
|
|
1434
|
+
.rt-card { margin-top: 10px; }
|
|
1397
1435
|
.rt-steps { margin: 0; padding-left: 1.4em; color: var(--text); font-size: 13px; line-height: 1.9; }
|
|
1398
1436
|
.rt-steps li { margin: 2px 0; }
|
|
1399
1437
|
/* URLは長いので、入力欄を伸ばしてボタンを右に置く(折り返しても崩れないように wrap) */
|
|
@@ -1412,6 +1450,17 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1412
1450
|
/* まだ受信していない接続先(複数接続のとき混在する)。稼働中の行と見分けが付く濃さに落とす */
|
|
1413
1451
|
.rt-live-line.is-waiting { color: var(--muted); font-weight: 500; }
|
|
1414
1452
|
/* 手順は畳んで残す(張り替え・再確認用)。開いたときだけ間隔を空ける */
|
|
1453
|
+
/* 鍵カードの発行手順。**畳んであるだけで、中身は消していない**(2026-08-21)。
|
|
1454
|
+
**マージンは持たせない**——.ops-card は column flex の gap: 10px なので、
|
|
1455
|
+
自前のマージンを足すとここだけ間隔が広くなる(短く見せたいカードで逆効果)。
|
|
1456
|
+
閉じているときに最後の段落の下マージンが残らないよう、中の余白も畳む */
|
|
1457
|
+
.sec-fold { border: none; margin: 0; }
|
|
1458
|
+
.sec-fold > summary { cursor: pointer; color: var(--muted); font-size: 12px; }
|
|
1459
|
+
.sec-fold[open] > summary { margin-bottom: 8px; }
|
|
1460
|
+
.sec-fold > .sec-how:last-child { margin-bottom: 0; }
|
|
1461
|
+
/* 鍵の入力欄も同じ理由でマージンを持たせない(.ds-addform の中は従来どおり6px)。
|
|
1462
|
+
子結合子で書くのは、リアルタイム同期カードの .rt-url(.rt-url-row の中)に当てないため */
|
|
1463
|
+
.ops-card > .sec-input { margin-bottom: 0; }
|
|
1415
1464
|
.rt-steps-fold > summary { cursor: pointer; color: var(--muted); font-size: 12px; }
|
|
1416
1465
|
.rt-steps-fold[open] > summary { margin-bottom: 10px; }
|
|
1417
1466
|
.rt-steps-fold[open] > *:not(summary) { margin-top: 10px; }
|
|
@@ -1617,8 +1666,12 @@ ${capabilityState.toString()}
|
|
|
1617
1666
|
var countEl = { textContent: "" }; // 件数表示は廃止(ヘッダーから削除済み)
|
|
1618
1667
|
var footerEl = document.getElementById("footer-meta");
|
|
1619
1668
|
|
|
1669
|
+
// **画面の版も出す(2026-08-20)。** 新しい画面は案件ごとに順次切り替わるので、
|
|
1670
|
+
// **案件によって版が違う**。出していないと「直したはずなのに直っていない」の正体が
|
|
1671
|
+
// 「その案件だけ古い版」であることを切り分けられない
|
|
1620
1672
|
footerEl.textContent = "生成: " + SITE.generatedAt +
|
|
1621
|
-
(SITE.repoBaseUrl ? " / " + SITE.repoBaseUrl.split("://").pop() + " (" + SITE.branch + ")" : "")
|
|
1673
|
+
(SITE.repoBaseUrl ? " / " + SITE.repoBaseUrl.split("://").pop() + " (" + SITE.branch + ")" : "") +
|
|
1674
|
+
(SITE.viewerVersion ? " / 画面 v" + SITE.viewerVersion : "");
|
|
1622
1675
|
|
|
1623
1676
|
/**
|
|
1624
1677
|
* 「貼り付けて使う文字列」を、選べる形+コピーボタンで出す。
|
|
@@ -1628,6 +1681,19 @@ ${capabilityState.toString()}
|
|
|
1628
1681
|
* clipboard API が使えない環境(http・古いブラウザ・権限拒否)では、**選択までしてやって**
|
|
1629
1682
|
* 次の一手を伝える(何も起きないのが一番悪い)。
|
|
1630
1683
|
*/
|
|
1684
|
+
/**
|
|
1685
|
+
* 共有資料の取り込みに使う Google アカウント(2026-08-20)。
|
|
1686
|
+
*
|
|
1687
|
+
* **画面に出す。** それまでは「取り込み用アカウント」としか書いておらず、
|
|
1688
|
+
* **誰を招待すればいいのかが画面から分からなかった**——担当者に聞かないと
|
|
1689
|
+
* 手順が完了できなかった。
|
|
1690
|
+
*
|
|
1691
|
+
* **艦隊で1つ。** 案件ごとに違うものではないので定数で足りる
|
|
1692
|
+
* (案件ごとになったら fleet-status から運ぶ器に変える)。
|
|
1693
|
+
* 議事録の取り込みでも同じアカウントを使っている。
|
|
1694
|
+
*/
|
|
1695
|
+
var DRIVE_INGEST_ACCOUNT = "cortex-notetaker@classmethod.jp";
|
|
1696
|
+
|
|
1631
1697
|
function copyRow(text) {
|
|
1632
1698
|
// **input と button を使わない。** 追加フォームの中に置くので、input を足すと
|
|
1633
1699
|
// 「先頭がURL欄・末尾が名前欄」、button を足すと「最初のボタンが送信」という
|
|
@@ -2073,6 +2139,10 @@ ${capabilityState.toString()}
|
|
|
2073
2139
|
// **状態の語で「招待」と言わない**——言うと、何度招待しても直らないものを繰り返させる
|
|
2074
2140
|
"missing_scope": { text: "権限が足りません", cls: "ds-gate-warn" },
|
|
2075
2141
|
"unreachable": { text: "アクセス不可", cls: "ds-gate-warn" },
|
|
2142
|
+
// **この素の語が出るのは、まだ対応していない種別のときだけ。**
|
|
2143
|
+
// slack / github は下の DS_GATE_NO_TOKEN で経路ごとに言い換える(dsGateOf を通す)。
|
|
2144
|
+
// 残してあるのは「知らない種別のソースを黙って消さない」ため——新しいアダプタが
|
|
2145
|
+
// 増えた日に、行が状態を持たずに並ぶより、素の語でも出ているほうがよい
|
|
2076
2146
|
"no_token": { text: "トークン未設定", cls: "ds-gate-muted" },
|
|
2077
2147
|
"unknown": { text: "不明", cls: "ds-gate-muted" },
|
|
2078
2148
|
};
|
|
@@ -2111,6 +2181,27 @@ ${capabilityState.toString()}
|
|
|
2111
2181
|
cls: "ds-gate-muted",
|
|
2112
2182
|
help: "このチャンネルがあるお客様の Slack ワークスペースが、まだ接続されていない(または接続が切れている)状態です。「Slack ワークスペースに接続する」から接続してください。",
|
|
2113
2183
|
},
|
|
2184
|
+
/* -------------------------------------------------------------------------
|
|
2185
|
+
* GitHub。**「トークン未設定」と言ってはいけない**(2026-08-21)
|
|
2186
|
+
* -------------------------------------------------------------------------
|
|
2187
|
+
* 読み取り用の個人アクセストークンは廃止し、GitHub App のインストールトークンに
|
|
2188
|
+
* 一本化した。**画面のどこにも、そのトークンを入れる欄はもう無い。**
|
|
2189
|
+
* それでも「トークン未設定」と出すと、上の DS_GATE_NO_TOKEN の項が書いている
|
|
2190
|
+
* 2026-08-18 の不具合と同じ形になる——しかも**探した先が存在しない**ぶん悪い。
|
|
2191
|
+
*
|
|
2192
|
+
* engine 側は、画面がこう言う前提で値を返している(scripts/fleet-status.mjs の
|
|
2193
|
+
* probeGithubGate): App のトークンを持たずに読もうとして 404/403 で落ちたなら、
|
|
2194
|
+
* 原因はスコープではなく**この組織に App が入っていない**。
|
|
2195
|
+
* **同じモーダルの中で、組織の案内が「App を入れてください」と言っているのに
|
|
2196
|
+
* 行と能力タイルが「トークン未設定」と言う**状態を作らないこと。
|
|
2197
|
+
*
|
|
2198
|
+
* **help は付けない。** 次の一手(インストール導線)は組織ごとの案内
|
|
2199
|
+
* (githubNotConnectedNodes)が1つだけ持つ。行ごとに繰り返すと一覧が案内で埋まる。
|
|
2200
|
+
* ----------------------------------------------------------------------- */
|
|
2201
|
+
github: {
|
|
2202
|
+
text: "App が未インストール",
|
|
2203
|
+
cls: "ds-gate-muted",
|
|
2204
|
+
},
|
|
2114
2205
|
};
|
|
2115
2206
|
/**
|
|
2116
2207
|
* Slack のチャンネルが社内ワークスペースのものか。**workspace の有無だけで決まる**
|
|
@@ -2138,10 +2229,26 @@ ${capabilityState.toString()}
|
|
|
2138
2229
|
if (!s || s.indexOf("(名前未取得") === 0) return s;
|
|
2139
2230
|
return "#" + s.replace(/^#+/, "");
|
|
2140
2231
|
}
|
|
2141
|
-
/**
|
|
2232
|
+
/**
|
|
2233
|
+
* 行に出す接続状態。**no_token だけは経路で文面が分かれる。**
|
|
2234
|
+
*
|
|
2235
|
+
* | 種別 | no_token の意味 | 語 |
|
|
2236
|
+
* |---|---|---|
|
|
2237
|
+
* | slack(社内) | 中央 Bot の鍵が無い。**画面から設定できない** | 管理者の設定が必要です |
|
|
2238
|
+
* | slack(顧客) | お客様のワークスペースが未接続。接続で直せる | トークン未設定 |
|
|
2239
|
+
* | github | 読む鍵が1本も無かった=**この組織に App が入っていない** | App が未インストール |
|
|
2240
|
+
*
|
|
2241
|
+
* **ここを通さずに語を書き写さないこと。** 行バッジ・能力タイルの要約・
|
|
2242
|
+
* 「接続を確認」の結果が同じ関数を通るので、片方だけ古くなることが構造的に起きない
|
|
2243
|
+
* (attentionSummary / probeVerdict の項に、実際に割れた経緯がある)。
|
|
2244
|
+
*/
|
|
2142
2245
|
function dsGateOf(s) {
|
|
2143
|
-
if (s.gate === "no_token"
|
|
2144
|
-
|
|
2246
|
+
if (s.gate === "no_token") {
|
|
2247
|
+
if (s.type === "slack") {
|
|
2248
|
+
return isInternalSlack(s) ? DS_GATE_NO_TOKEN.internal : DS_GATE_NO_TOKEN.customer;
|
|
2249
|
+
}
|
|
2250
|
+
// github-issues / github-discussions のどちらも同じ原因(組織単位の App)
|
|
2251
|
+
if (String(s.type || "").indexOf("github") === 0) return DS_GATE_NO_TOKEN.github;
|
|
2145
2252
|
}
|
|
2146
2253
|
return DS_GATE[s.gate] || DS_GATE["unknown"];
|
|
2147
2254
|
}
|
|
@@ -2153,6 +2260,14 @@ ${capabilityState.toString()}
|
|
|
2153
2260
|
* 場所が画面に無いので、探した人が顧客ワークスペースの接続へ吸い込まれる(DS_GATE_NO_TOKEN
|
|
2154
2261
|
* の項の事故がここから始まっている)。1件でも顧客側が混ざるときは従来の文面のまま——
|
|
2155
2262
|
* そちらは接続で直せるので、経路を名指しできない要約に倒す方が正しい。
|
|
2263
|
+
*
|
|
2264
|
+
* **GitHub も同じ理由で「トークン」と言わない(2026-08-21)。** 読み取り用の個人
|
|
2265
|
+
* アクセストークンは廃止済みで、**入力欄が画面のどこにも無い**。ここが古い語のまま
|
|
2266
|
+
* 残っていたので、同じモーダルの中で組織の案内は「App を入れてください」・
|
|
2267
|
+
* その直下の行と能力タイルは「トークン未設定」という食い違いが出ていた。
|
|
2268
|
+
*
|
|
2269
|
+
* **語は dsGateOf から引く(写経しない)。** 行バッジと同じ関数を通すので、
|
|
2270
|
+
* 片方だけ古くなることが構造的に起きない。
|
|
2156
2271
|
*/
|
|
2157
2272
|
function attentionSummary(items) {
|
|
2158
2273
|
var bad = items.filter(function (s) { return sourceNeedsAttention(s); });
|
|
@@ -2160,8 +2275,19 @@ ${capabilityState.toString()}
|
|
|
2160
2275
|
var head = "⚠️ " + bad.length + "件";
|
|
2161
2276
|
var noToken = bad.filter(function (s) { return s.gate === "no_token"; });
|
|
2162
2277
|
if (noToken.length !== bad.length) return head + "に問題";
|
|
2163
|
-
|
|
2164
|
-
|
|
2278
|
+
// 原因を名指しできるのは、行バッジの語が**1つに揃っている**ときだけ
|
|
2279
|
+
var texts = {};
|
|
2280
|
+
noToken.forEach(function (s) { texts[dsGateOf(s).text] = true; });
|
|
2281
|
+
var names = [];
|
|
2282
|
+
for (var t in texts) if (Object.prototype.hasOwnProperty.call(texts, t)) names.push(t);
|
|
2283
|
+
if (names.length === 1) return head + "が読めていません(" + names[0] + ")";
|
|
2284
|
+
// 語が割れた。**Slack の中だけで割れているなら従来どおり顧客側の語に倒す**——
|
|
2285
|
+
// そちらは接続で直せるので、「管理者の設定が必要です」と言い切ると直せる人を止める。
|
|
2286
|
+
// 種別をまたいで割れているとき(Slack と GitHub が同時に読めていない等)は、
|
|
2287
|
+
// 次にする人も操作も違うので1つの原因として書けない。件数だけにする
|
|
2288
|
+
var allSlack = noToken.every(function (s) { return s.type === "slack"; });
|
|
2289
|
+
if (allSlack) return head + "が読めていません(" + DS_GATE_NO_TOKEN.customer.text + ")";
|
|
2290
|
+
return head + "に問題";
|
|
2165
2291
|
}
|
|
2166
2292
|
/**
|
|
2167
2293
|
* Slack のチャンネルを、所属する組織ごとに分ける(2026-08-20)。
|
|
@@ -2169,7 +2295,7 @@ ${capabilityState.toString()}
|
|
|
2169
2295
|
* ## なぜ純関数にするか
|
|
2170
2296
|
*
|
|
2171
2297
|
* ここが**判断の全部**。描画に混ぜると「どう分けたか」を実測できなくなる。
|
|
2172
|
-
*
|
|
2298
|
+
* 並べる側は受け取ったものを出すだけで、意味を持たない
|
|
2173
2299
|
* (GitHub は組織・Backlog はスペースで同じ形が要るため)。
|
|
2174
2300
|
*
|
|
2175
2301
|
* ## 分け方
|
|
@@ -2371,6 +2497,193 @@ ${capabilityState.toString()}
|
|
|
2371
2497
|
}
|
|
2372
2498
|
}
|
|
2373
2499
|
|
|
2500
|
+
/**
|
|
2501
|
+
* GitHub のリポジトリを、組織ごとに分ける(2026-08-20・Slack からの横展開)。
|
|
2502
|
+
*
|
|
2503
|
+
* ## Slack との違い
|
|
2504
|
+
*
|
|
2505
|
+
* **帰属を API に聞く必要が無い。** 組織は ref(owner/repo)に入っている。
|
|
2506
|
+
* だから判定は文字列を切るだけで、実測も印も要らない。
|
|
2507
|
+
*
|
|
2508
|
+
* ## 接続状態は台帳(githubOwners)から引く
|
|
2509
|
+
*
|
|
2510
|
+
* トークンは**組織ごとにしか効かない**(Fine-grained PAT も App の
|
|
2511
|
+
* インストールトークンも1組織分)ので、状態の単位も組織。
|
|
2512
|
+
*
|
|
2513
|
+
* @returns [{ key, title, items, state }] state は "ok" | "warn" | "unsure" | null
|
|
2514
|
+
*/
|
|
2515
|
+
/** 台帳から、その組織の情報を引く(無ければ null=断定しない) */
|
|
2516
|
+
function githubOwnerMeta(owner) {
|
|
2517
|
+
var list = fleetVal("githubOwners") || [];
|
|
2518
|
+
for (var i = 0; i < list.length; i++) {
|
|
2519
|
+
if (list[i] && list[i].owner === owner) return list[i];
|
|
2520
|
+
}
|
|
2521
|
+
return null;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
function groupGithubByOwner(items, owners) {
|
|
2525
|
+
var known = {};
|
|
2526
|
+
(owners || []).forEach(function (o) { if (o && o.owner) known[o.owner] = o; });
|
|
2527
|
+
var order = [];
|
|
2528
|
+
var byKey = {};
|
|
2529
|
+
(items || []).forEach(function (s) {
|
|
2530
|
+
var owner = String(s.ref || "").split("/")[0] || "";
|
|
2531
|
+
var g = byKey[owner];
|
|
2532
|
+
if (!g) {
|
|
2533
|
+
var o = known[owner];
|
|
2534
|
+
// **台帳に無ければ断定しない。** 夜間バッチの成果物なので、
|
|
2535
|
+
// 立ち上げ直後の案件には無い(「0件」と「知らない」を同じ扱いにすると嘘になる)
|
|
2536
|
+
var state = null;
|
|
2537
|
+
// **「warn」 は else 側の総取り。** ここに載っていない値は全部「未接続」に落ちるので、
|
|
2538
|
+
// engine が 「source」 に新しい値を足したら**必ずここも足す**——載せ忘れると、
|
|
2539
|
+
// 読めている組織が顧客の画面で一斉に「まだ接続されていません」になる。
|
|
2540
|
+
//
|
|
2541
|
+
// 「workflow」 は「App は無いが、ワークフロー自身のトークンで全部読めた」=**接続OK**。
|
|
2542
|
+
// 「token」(廃止した個人アクセストークンで読めていた)も**当面 OK のまま受ける**——
|
|
2543
|
+
// 画面(Amplify で即配布)と engine(案件スタブが 「@v1」 を指しており、タグを
|
|
2544
|
+
// 進めるまで古い 「fleet-status.json」 のまま)は**別々に配られる**ので、
|
|
2545
|
+
// どちらを先に出しても片側だけ新しい期間ができる。その間に 「token」 を落とすと、
|
|
2546
|
+
// コミット済みの値を読んだ画面が偽の警告を出す。**外すのはフェーズ2**(engine の
|
|
2547
|
+
// v1 が全案件へ行き渡ったことを確かめてから)。
|
|
2548
|
+
if (o) {
|
|
2549
|
+
state = (o.source === "app" || o.source === "workflow" || o.source === "token") ? "ok"
|
|
2550
|
+
: o.source === "unknown" ? "unsure"
|
|
2551
|
+
: "warn";
|
|
2552
|
+
}
|
|
2553
|
+
g = { key: owner, title: owner || "(組織不明)", items: [], state: state, meta: o || null };
|
|
2554
|
+
byKey[owner] = g;
|
|
2555
|
+
order.push(g);
|
|
2556
|
+
}
|
|
2557
|
+
g.items.push(s);
|
|
2558
|
+
});
|
|
2559
|
+
// **繋がっている組織を先に、繋がっていない組織を後に。**
|
|
2560
|
+
// 直すものが無い人にも「未接続」が最初に見えるのは、優先順位が逆
|
|
2561
|
+
order.sort(function (a, b) {
|
|
2562
|
+
var rank = function (g) { return g.state === "warn" ? 2 : g.state === "unsure" ? 1 : 0; };
|
|
2563
|
+
return rank(a) - rank(b);
|
|
2564
|
+
});
|
|
2565
|
+
return order;
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
/**
|
|
2569
|
+
* GitHub のリポジトリを**平らに**並べる(2026-08-20)。
|
|
2570
|
+
*
|
|
2571
|
+
* Slack と同じ形。並び順は組織ごとだが**箱で囲まない**。
|
|
2572
|
+
* どの組織かは**行のラベル**が示し、**接続が要る組だけ**案内が行を抱える。
|
|
2573
|
+
*/
|
|
2574
|
+
function githubRows(items) {
|
|
2575
|
+
var owners = fleetVal("githubOwners");
|
|
2576
|
+
var out = [];
|
|
2577
|
+
groupGithubByOwner(items, owners).forEach(function (g) {
|
|
2578
|
+
// **行ごとに meta を引く。** issues と discussions でアイコンとラベルが違う
|
|
2579
|
+
var cards = g.items.map(function (x) {
|
|
2580
|
+
return extSourceCard(x, DS_TYPE[x.type] || { icon: "🔗", label: x.type || "その他" });
|
|
2581
|
+
});
|
|
2582
|
+
if (g.state === "warn") {
|
|
2583
|
+
out.push(orgNoteBox(githubNotConnectedNodes(g), cards));
|
|
2584
|
+
return;
|
|
2585
|
+
}
|
|
2586
|
+
if (g.state === "unsure") {
|
|
2587
|
+
// **確かめられなかった夜は、そう言う。** gh の不在・タイムアウト・
|
|
2588
|
+
// ネットワーク断で起きる。「接続OK」と出すと同じ画面の集計と食い違い、
|
|
2589
|
+
// 「未接続」と出すと繋がっている組織に偽の警告を出す——どちらも嘘。
|
|
2590
|
+
// **導線は出さない**(すでに入っているかもしれないので、押させる理由が無い)
|
|
2591
|
+
out.push(orgNoteBox(githubUnsureNodes(g), cards));
|
|
2592
|
+
return;
|
|
2593
|
+
}
|
|
2594
|
+
cards.forEach(function (n) { out.push(n); });
|
|
2595
|
+
});
|
|
2596
|
+
return out;
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2599
|
+
/** 確かめられなかった組織の案内。**導線は出さない** */
|
|
2600
|
+
function githubUnsureNodes(g) {
|
|
2601
|
+
var o = g.meta || {};
|
|
2602
|
+
return [
|
|
2603
|
+
el("div", { class: "ds-orgnote-title", text: "⚠️ " + g.title + " の接続を確認できませんでした" }),
|
|
2604
|
+
el("p", {
|
|
2605
|
+
class: "ds-group-note",
|
|
2606
|
+
// **件数を出す。** 4リポのうち3つは確かめられている夜に
|
|
2607
|
+
// 「4リポジトリを確かめられていません」と読めるのは実態と違う
|
|
2608
|
+
text: (o.repos || g.items.length) + "リポジトリ中 "
|
|
2609
|
+
+ (o.unchecked != null ? o.unchecked : (o.repos || g.items.length))
|
|
2610
|
+
+ "件の接続を確かめられていません。翌朝の表示をご確認ください。",
|
|
2611
|
+
}),
|
|
2612
|
+
];
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
/**
|
|
2616
|
+
* 繋がっていない組織の案内。
|
|
2617
|
+
*
|
|
2618
|
+
* **「読めない」の原因は1つではない。** 以前はどの組織にも
|
|
2619
|
+
* 「この組織に Cortex の GitHub App を入れると読めるようになります」と出していたが、
|
|
2620
|
+
* **App は入っているのにそのリポジトリが選ばれていない**組織にはこれが効かない。
|
|
2621
|
+
* インストールは済んでいるので、押しても画面は変わらず、何度押しても直らない。
|
|
2622
|
+
*
|
|
2623
|
+
* 「appInstalled」 が原因を分ける(engine がインストールトークンを取れたかどうか):
|
|
2624
|
+
*
|
|
2625
|
+
* | 値 | 意味 | 案内 |
|
|
2626
|
+
* |---|---|---|
|
|
2627
|
+
* | 「false」 | App のトークンが取れなかった=未インストール | インストールへ |
|
|
2628
|
+
* | 「true」 | 取れたのに読めない=そのリポジトリが未選択 | **インストール設定**へ |
|
|
2629
|
+
* | 「null」 | その夜は確かめられなかった | **どちらも出さない**(押しても直るとは限らない) |
|
|
2630
|
+
*
|
|
2631
|
+
* **自社か顧客かで文言を分けない。** 組織名(「classmethod-*」)で分岐すると、
|
|
2632
|
+
* 新しい自社組織が増えたときに黙って間違った案内を出す。どちらにも通じる文にする。
|
|
2633
|
+
*/
|
|
2634
|
+
function githubNotConnectedNodes(g) {
|
|
2635
|
+
var out = [];
|
|
2636
|
+
var o = g.meta || {};
|
|
2637
|
+
var repos = o.repos || g.items.length;
|
|
2638
|
+
var unread = o.unreadable != null ? o.unreadable : g.items.length;
|
|
2639
|
+
var installed = o.appInstalled;
|
|
2640
|
+
out.push(el("div", { class: "ds-orgnote-title", text: "⚠️ " + g.title + " はまだ接続されていません" }));
|
|
2641
|
+
// **読める件数を出す。** 総数だけ出すと、同じ画面の集計と食い違う(#101 で3度直した形)
|
|
2642
|
+
var head = repos + "リポジトリ中 " + unread + "件が読めていません。";
|
|
2643
|
+
if (installed === true) {
|
|
2644
|
+
// App は入っている。**インストールをもう一度促さないこと**——済んでいる操作を促すのは
|
|
2645
|
+
// 「設定する必要が無いものに設定を促す」偽の警告と同じで、しかも直らない
|
|
2646
|
+
//
|
|
2647
|
+
// **原因を1つに断定しない(2026-08-21)。** 「appInstalled」 が分けられるのは
|
|
2648
|
+
// 「①未インストール」と「②未選択/③消えた・改名」までで、**②と③は分かれない**。
|
|
2649
|
+
// 「対象に選ばれていません」と言い切ると、③の人は一覧に無いリポジトリを
|
|
2650
|
+
// 探し続けることになる(押しても直らない導線と同じ形)。逃げ道を1文で示す。
|
|
2651
|
+
//
|
|
2652
|
+
// **設定画面の宛先も断定しない。** リンク先は 「/settings/installations」=
|
|
2653
|
+
// **押した本人の**インストール一覧で(appSettingsLink の項に、組織の設定ページが
|
|
2654
|
+
// 管理者以外で 404 になる理由がある)、App を入れたのが別のメンバーや
|
|
2655
|
+
// 顧客側のオーナーなら**着いた先は空**。そこで詰まる人に次の宛先を渡す。
|
|
2656
|
+
out.push(el("p", {
|
|
2657
|
+
class: "ds-group-note",
|
|
2658
|
+
text: head + "GitHub App はこの組織に入っていますが、これらのリポジトリが読み取りの対象に選ばれていません。"
|
|
2659
|
+
+ "インストール設定を開いて、対象のリポジトリを追加してください。"
|
|
2660
|
+
+ "設定は App を入れた方の画面に出ます。見当たらない場合は、この組織で App を入れた方にご依頼ください。"
|
|
2661
|
+
+ "リポジトリ自体が一覧に見当たらない場合は、移動・改名・削除されている可能性があるので、登録から外してください。"
|
|
2662
|
+
+ "お客様の組織では、組織のオーナーに承認を依頼してください。",
|
|
2663
|
+
}));
|
|
2664
|
+
out.push(appSettingsLink("インストール設定を開く →"));
|
|
2665
|
+
return out;
|
|
2666
|
+
}
|
|
2667
|
+
if (installed === false) {
|
|
2668
|
+
out.push(el("p", {
|
|
2669
|
+
class: "ds-group-note",
|
|
2670
|
+
text: head + "この組織に Cortex の GitHub App を入れると読めるようになります(Issues の読み取りだけ)。"
|
|
2671
|
+
+ "お客様の組織では、組織のオーナーに承認を依頼してください。",
|
|
2672
|
+
}));
|
|
2673
|
+
out.push(appInstallLink("この組織にインストール →"));
|
|
2674
|
+
return out;
|
|
2675
|
+
}
|
|
2676
|
+
// 「null」(確かめられなかった)と、この値を知らない古い fleet-status.json。
|
|
2677
|
+
// **導線を出さない。** どちらが原因か分からないので、押させると外れたほうを
|
|
2678
|
+
// 押させることになる(済んでいるインストールをもう一度、あるいは効かない設定画面へ)
|
|
2679
|
+
out.push(el("p", {
|
|
2680
|
+
class: "ds-group-note",
|
|
2681
|
+
text: head + "原因(GitHub App が入っていない/入っているがこれらのリポジトリが選ばれていない)は、"
|
|
2682
|
+
+ "今回の実行では確かめられませんでした。翌朝の表示をご確認ください。",
|
|
2683
|
+
}));
|
|
2684
|
+
return out;
|
|
2685
|
+
}
|
|
2686
|
+
|
|
2374
2687
|
/**
|
|
2375
2688
|
* Slack のチャンネルを**平らに**並べる(2026-08-20)。
|
|
2376
2689
|
*
|
|
@@ -2488,14 +2801,6 @@ ${capabilityState.toString()}
|
|
|
2488
2801
|
}
|
|
2489
2802
|
|
|
2490
2803
|
|
|
2491
|
-
var DS_KIND_ICON = {
|
|
2492
|
-
"課題管理": "📋",
|
|
2493
|
-
"会議": "🗒️",
|
|
2494
|
-
"共有資料": "📎",
|
|
2495
|
-
"デザイン": "🎨",
|
|
2496
|
-
"開発": "🐙",
|
|
2497
|
-
"チャット": "💬",
|
|
2498
|
-
};
|
|
2499
2804
|
function dsFmtTime(iso) {
|
|
2500
2805
|
var d = new Date(iso);
|
|
2501
2806
|
if (isNaN(d.getTime())) return "";
|
|
@@ -2581,6 +2886,63 @@ ${capabilityState.toString()}
|
|
|
2581
2886
|
*/
|
|
2582
2887
|
var GITHUB_APP_INSTALL_URL = "https://github.com/apps/classmethod-cortex-app/installations/new";
|
|
2583
2888
|
|
|
2889
|
+
/**
|
|
2890
|
+
* GitHub App のインストールへ行くリンク(2026-08-20 に部品化)。
|
|
2891
|
+
*
|
|
2892
|
+
* **同じものを2箇所に書かない。** 組織ごとの案内と、追加フォームの手順が
|
|
2893
|
+
* 同じ導線を持つ(#138 で「1箇所にしか無い」ことが事故になったので、
|
|
2894
|
+
* **むしろ複数あるのが正しい**)。写経すると、URLの張り替えで片方だけ古くなる。
|
|
2895
|
+
*
|
|
2896
|
+
* **正本は手順の側。** 組織ごとの案内は行が無いと出ないので、
|
|
2897
|
+
* 行0件の案件では手順側しか残らない。
|
|
2898
|
+
*
|
|
2899
|
+
* **⚠️ ただし手順は追加フォームの中にあり、追加フォームは
|
|
2900
|
+
* SITE.intake が無いと丸ごと消える**(renderExternalAdders の冒頭)。
|
|
2901
|
+
* つまり **intake 無し+行0件** の案件では App の導線が1本も無くなる。
|
|
2902
|
+
* いまは config.ts の intakeUrl が艦隊で1つ・全案件に渡っているので
|
|
2903
|
+
* その組み合わせは起きない(2026-08-20 に確認)。
|
|
2904
|
+
* **案件ごとに intake を出し分けるようになったら、ここを見直すこと。**
|
|
2905
|
+
*/
|
|
2906
|
+
function appInstallLink(label) {
|
|
2907
|
+
return el("a", {
|
|
2908
|
+
class: "ds-owner-install",
|
|
2909
|
+
href: GITHUB_APP_INSTALL_URL,
|
|
2910
|
+
target: "_blank", rel: "noopener",
|
|
2911
|
+
text: label || "GitHub App を入れる →",
|
|
2912
|
+
});
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
/**
|
|
2916
|
+
* すでに入っている App の**インストール設定**(対象リポジトリの追加)へ行くリンク。
|
|
2917
|
+
*
|
|
2918
|
+
* **インストールとは別の宛先。** 「installations/new」 は「入れる」ための画面で、
|
|
2919
|
+
* すでに入っている組織の人が押しても対象リポジトリは増えない。
|
|
2920
|
+
* リポジトリの追加は、その人が入れた先(個人 or 組織)の設定画面で行う。
|
|
2921
|
+
*
|
|
2922
|
+
* **組織名を URL に埋め込まない。** 組織ごとの設定ページは
|
|
2923
|
+
* 「github.com/organizations/<組織>/settings/installations」 だが、**その組織の
|
|
2924
|
+
* 管理者でないと 404 になる**。読み取り対象の組織のオーナーが Cortex の利用者とは
|
|
2925
|
+
* 限らない(お客様の組織がまさにそれ)ので、404 に飛ばすより、
|
|
2926
|
+
* 本人のインストール一覧から辿らせるほうが確実に着く。
|
|
2927
|
+
* ——「GITHUB_APP_INSTALL_URL」 の「確かめられないものを顧客に押させない」と同じ判断。
|
|
2928
|
+
*
|
|
2929
|
+
* ⚠ **ただし「押した本人が入れた App」しか出ない。** App を入れたのが別のメンバーや
|
|
2930
|
+
* 顧客側のオーナーなら、着いた先は空になる。だから**案内の本文の側が**
|
|
2931
|
+
* 「App を入れた方の画面に出ます/見当たらない場合はその方にご依頼ください」と断っている
|
|
2932
|
+
* (githubNotConnectedNodes)。**リンクだけ残して本文の断りを消さないこと**——
|
|
2933
|
+
* 消すと「開けば必ずそこにある」前提の案内に戻り、着いた先が空の人が詰む。
|
|
2934
|
+
*/
|
|
2935
|
+
var GITHUB_APP_SETTINGS_URL = "https://github.com/settings/installations";
|
|
2936
|
+
|
|
2937
|
+
function appSettingsLink(label) {
|
|
2938
|
+
return el("a", {
|
|
2939
|
+
class: "ds-owner-install",
|
|
2940
|
+
href: GITHUB_APP_SETTINGS_URL,
|
|
2941
|
+
target: "_blank", rel: "noopener",
|
|
2942
|
+
text: label || "インストール設定を開く →",
|
|
2943
|
+
});
|
|
2944
|
+
}
|
|
2945
|
+
|
|
2584
2946
|
/**
|
|
2585
2947
|
* 接続状況のライブ値(op=state の応答)。取得前・取得失敗時は null。
|
|
2586
2948
|
*
|
|
@@ -2639,14 +3001,33 @@ ${capabilityState.toString()}
|
|
|
2639
3001
|
* 能力モーダル。**中身は既存の部品をそのまま入れる。**
|
|
2640
3002
|
* 一覧・追加フォーム・鍵・手動投入は作り直さない(先出しバッジやライブ差し替えを壊さないため)。
|
|
2641
3003
|
*/
|
|
3004
|
+
/**
|
|
3005
|
+
* 能力(課題管理・会議…)→ **押したタイルのツール名**(Backlog・Google Meet…)。
|
|
3006
|
+
*
|
|
3007
|
+
* 2026-08-21 のオーナー実機指摘「押してるのはそのツールなんだから、Backlog とか
|
|
3008
|
+
* Google ドライブとして出る必要がある」。出どころは ADAPTER_CATALOG(能力→アダプタ)で、
|
|
3009
|
+
* **今日は能力あたり1アダプタなので一意に決まる**(#107 / #127 で複数になったら、
|
|
3010
|
+
* ここが「どれを見出しにするか」を決める場所になる)。
|
|
3011
|
+
*
|
|
3012
|
+
* ⚠ **カタログに無いものは、そのまま返す。** ここには能力名だけでなく
|
|
3013
|
+
* 「文字起こしを手動で追加」のような**能力ではない見出し**も渡ってくるし、
|
|
3014
|
+
* 未知の能力(engine が先に増やした場合)も来る。空にすると
|
|
3015
|
+
* **名前の無いダイアログ**になり、何を開いたのか分からなくなる——落とすなら能力名まで。
|
|
3016
|
+
*/
|
|
3017
|
+
function capToolLabel(cap) {
|
|
3018
|
+
var list = ADAPTER_CATALOG[cap] || [];
|
|
3019
|
+
var tool = list.length ? list[0] : "";
|
|
3020
|
+
return (tool && CM_TOOL_LABEL_C[tool]) || cap;
|
|
3021
|
+
}
|
|
3022
|
+
|
|
2642
3023
|
function openCapabilityModal(cap, items, note) {
|
|
2643
|
-
var m = makeModal(cap, true);
|
|
3024
|
+
var m = makeModal(capToolLabel(cap), true);
|
|
2644
3025
|
// **何が読み取られるのかを必ず書く。** 一覧に並ぶものと読み取られるものの関係は、
|
|
2645
3026
|
// 書いていないと分からない(チャットは「載っていれば全部」、開発はリポジトリ単位でOFFできる)
|
|
2646
3027
|
if (cap === "チャット") {
|
|
2647
3028
|
m.modal.appendChild(el("p", { class: "modal-desc", text: "ここに並んでいるチャンネルは、例外なく全て毎晩の Gold 昇格が読み取り、Decision・用語集の材料になります。読み取りを止めるには「登録を解除」してください。" }));
|
|
2648
3029
|
} else if (cap === "開発") {
|
|
2649
|
-
m.modal.appendChild(el("p", { class: "modal-desc", text: "ここに並んでいるリポジトリの Issues を毎晩の Gold
|
|
3030
|
+
m.modal.appendChild(el("p", { class: "modal-desc", text: "ここに並んでいるリポジトリの Issues を毎晩の Gold 昇格が読み取り、Decision・用語集の材料になります。読み取りをやめるには「登録から削除」してください。" }));
|
|
2650
3031
|
}
|
|
2651
3032
|
// **なぜこの状態なのかを、押した先でも読めるようにする(#125②)。** タイルは常時出す
|
|
2652
3033
|
// ようになったので、未接続の能力を押したときに中身が空になる場面が増えた。
|
|
@@ -2667,7 +3048,32 @@ ${capabilityState.toString()}
|
|
|
2667
3048
|
showModal(m.overlay, m.modal);
|
|
2668
3049
|
}
|
|
2669
3050
|
|
|
3051
|
+
/**
|
|
3052
|
+
* 鍵の欄の置き場(2026-08-21・オーナー指摘「APIキーのセクションが下にあって、
|
|
3053
|
+
* 変わってないように見えます」)。
|
|
3054
|
+
*
|
|
3055
|
+
* 鍵の欄は**レコードの行の内側**(Backlog は接続先の行ごと・Figma は一覧の直後)に出す。
|
|
3056
|
+
* ところが**出す責任はここには移していない**——鍵カードを作っているのは
|
|
3057
|
+
* 「SECRET_FORMS」のループで、そこには
|
|
3058
|
+
* - intake を持たない案件でも鍵の欄を出す(internalControls は SITE.intake で早期return)
|
|
3059
|
+
* - OFF にした能力には入力欄を出さない
|
|
3060
|
+
* という2つのゲートが掛かっている。**内側で作り直すと、その両方が外れる**
|
|
3061
|
+
* (前者は「鍵の欄しか無い案件でデータソース節が丸ごと消える」形で実際に起きた)。
|
|
3062
|
+
*
|
|
3063
|
+
* そこで**置き場だけを内側から渡す**。ここに登録された受け皿へ、ループが作った
|
|
3064
|
+
* 鍵カードを差し込む。受け皿が無ければ従来どおり能力カードの直下へ積む。
|
|
3065
|
+
*
|
|
3066
|
+
* - backlog … スペース(ドメイン小文字)→ 受け皿。接続先が無い案件は空文字のキー
|
|
3067
|
+
* - backlogNamed … 保存時にスペースを名乗ってよいか(名簿由来の行だけ true)
|
|
3068
|
+
* - figma … 一覧の直後の受け皿(Figma の鍵は案件に1本なので1つだけ)
|
|
3069
|
+
*
|
|
3070
|
+
* **描き直すたびに作り直す。** ライブ差し替えで節ごと作り直されるので、
|
|
3071
|
+
* 前回の受け皿(切り離された古いノード)が残っていると、鍵の欄が画面から消える。
|
|
3072
|
+
*/
|
|
3073
|
+
var KEY_SLOTS = { backlog: {}, backlogNamed: false, figma: null };
|
|
3074
|
+
|
|
2670
3075
|
function buildDataSources() {
|
|
3076
|
+
KEY_SLOTS = { backlog: {}, backlogNamed: false, figma: null };
|
|
2671
3077
|
var internals = fleetVal("internalSources") || [];
|
|
2672
3078
|
var sources = fleetVal("externalSources") || [];
|
|
2673
3079
|
var pipes = fleetVal("pipelines") || [];
|
|
@@ -2751,8 +3157,18 @@ ${capabilityState.toString()}
|
|
|
2751
3157
|
// 用意してからここを戻す(syncNowRow と Lambda の op=sync は残してある)。
|
|
2752
3158
|
// sec.appendChild(syncNowRow());
|
|
2753
3159
|
internals.forEach(function (s) {
|
|
2754
|
-
//
|
|
2755
|
-
|
|
3160
|
+
// 補足行(会議の照合キー・Drive未設定の注記)を重ねられるよう縦組みにする。
|
|
3161
|
+
//
|
|
3162
|
+
// **情報源の名前は出さない(2026-08-21・オーナー指摘)。** モーダルの見出しが
|
|
3163
|
+
// ツール名(Backlog / Figma / Google Drive …)になったので、その直下にもう一度
|
|
3164
|
+
// 名前を出すと**同じことを2回言う**。実データの label は
|
|
3165
|
+
// 「Backlog 課題・ドキュメント(同期ミラー)」のような説明的な文で、見出しの
|
|
3166
|
+
// 言い換えにしかなっていない。
|
|
3167
|
+
//
|
|
3168
|
+
// **リンクを失わないことは確かめてある。** url を持つのは課題管理(プロジェクト)と
|
|
3169
|
+
// デザイン(Figmaファイル)だけで、どちらも**レコードの行が同じ先へリンクしている**。
|
|
3170
|
+
// 会議・共有資料は url を持たない。
|
|
3171
|
+
var col = el("div", { class: "ds-col" }, []);
|
|
2756
3172
|
// 照合キーの表示はここ1箇所に集約する(下の案内と二重に出さない)。
|
|
2757
3173
|
// **ON/OFFのトグルは出さない。** 取り込むかどうかは「Bot を会議に招待したか」で決まる
|
|
2758
3174
|
// (Router.gs:「フィルタは持たない…招待が同意のゲート」)。enabled はルーティングの
|
|
@@ -2826,21 +3242,32 @@ ${capabilityState.toString()}
|
|
|
2826
3242
|
// いまはタイルが飛び先。両方に付けると同じ id が2つある不正なHTMLになり、
|
|
2827
3243
|
// モーダルの中身がタイルより前に来る変更が入った瞬間、getElementById が
|
|
2828
3244
|
// 「開いていないモーダルの中」を指して黙って無反応になる
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
3245
|
+
//
|
|
3246
|
+
// **枠(.ds-card)とアイコン・能力名(.ds-icon / .ds-type)を落とす**
|
|
3247
|
+
// (2026-08-21・オーナー実機指摘)。Backlog のタイルを押して開いたモーダルの中に
|
|
3248
|
+
// 「📋 課題管理 Backlog」という箱がもう一段あり、見出しと同じことを二度言っていた。
|
|
3249
|
+
// モーダルの見出しがツール名になったので、ここは**見出しの直下に中身を並べる**だけ。
|
|
3250
|
+
//
|
|
3251
|
+
// 🔴 **落としたのは見出しと重複する2つだけ。** 会議の合図(.ds-keys)・別名チップ・
|
|
3252
|
+
// Drive / 未使用の注記・情報源へのリンクは col がそのまま抱えており、
|
|
3253
|
+
// 最終同期(.ds-sync)も条件ごと残している。
|
|
3254
|
+
//
|
|
3255
|
+
// **data-cap を付ける。** 能力名の文字列が画面から消えたので、
|
|
3256
|
+
// 「これはどの能力のブロックか」を掴む手掛かりがここしか無くなる(テストが引く)。
|
|
3257
|
+
var block = el("div", {
|
|
3258
|
+
class: "ds-capblock" + (inactive ? " ds-inactive" : ""),
|
|
3259
|
+
"data-cap": s.kind || "",
|
|
3260
|
+
}, [
|
|
3261
|
+
col,
|
|
2835
3262
|
!inactive && s.lastSync && dsFmtTime(s.lastSync)
|
|
2836
3263
|
? el("span", { class: "ds-sync", text: "最終同期: " + dsFmtTime(s.lastSync) })
|
|
2837
3264
|
: null,
|
|
2838
3265
|
]);
|
|
2839
|
-
//
|
|
3266
|
+
// 会議・共有資料・デザインの操作をブロック内に置く(その情報源の文脈で押せるように)
|
|
2840
3267
|
var ctl = internalControls(s, inactive);
|
|
2841
|
-
if (ctl)
|
|
3268
|
+
if (ctl) block.appendChild(ctl);
|
|
2842
3269
|
// 能力ごとの受け皿へ入れる(並べるのは下の CAP_ORDER のループ)
|
|
2843
|
-
pushCap(s.kind,
|
|
3270
|
+
pushCap(s.kind, block);
|
|
2844
3271
|
});
|
|
2845
3272
|
}
|
|
2846
3273
|
|
|
@@ -2871,8 +3298,13 @@ ${capabilityState.toString()}
|
|
|
2871
3298
|
var groups = [];
|
|
2872
3299
|
var byType = {};
|
|
2873
3300
|
sources.forEach(function (s) {
|
|
2874
|
-
|
|
2875
|
-
|
|
3301
|
+
// **GitHub は種別をまたいで1つにまとめる(2026-08-20)。**
|
|
3302
|
+
// issues と discussions を別グループにすると、**同じ組織の案内が2箱出る**
|
|
3303
|
+
// (組織ごとの畳み直しが箱をまたげない。実測で再現した)。
|
|
3304
|
+
// 組織は type ではなく ref に入っているので、まとめて渡すのが正しい
|
|
3305
|
+
var key = String(s.type).indexOf("github") === 0 ? "__github__" : s.type;
|
|
3306
|
+
var g = byType[key];
|
|
3307
|
+
if (!g) { g = { type: key, items: [] }; byType[key] = g; groups.push(g); }
|
|
2876
3308
|
g.items.push(s);
|
|
2877
3309
|
});
|
|
2878
3310
|
var UNIT = { "slack": "チャンネル", "github-issues": "リポジトリ", "github-discussions": "リポジトリ" };
|
|
@@ -2886,6 +3318,15 @@ ${capabilityState.toString()}
|
|
|
2886
3318
|
slackRows(g.items, meta).forEach(function (n) { pushCap("チャット", n); });
|
|
2887
3319
|
return;
|
|
2888
3320
|
}
|
|
3321
|
+
// **GitHub も組織ごとに分ける(2026-08-20・Slack からの横展開)。**
|
|
3322
|
+
// それまでは「リポジトリの一覧」と「組織ごとの接続状況」が**別々に並んで**おり、
|
|
3323
|
+
// どの行がどの組織のものか、行を見ても分からなかった。
|
|
3324
|
+
if (g.type === "__github__") {
|
|
3325
|
+
// **meta は行ごとに引く。** issues と discussions が混ざるので、
|
|
3326
|
+
// グループの type から1つに決められない
|
|
3327
|
+
githubRows(g.items).forEach(function (n) { pushCap("開発", n); });
|
|
3328
|
+
return;
|
|
3329
|
+
}
|
|
2889
3330
|
var cards = el("div", { class: "ds-list" });
|
|
2890
3331
|
g.items.forEach(function (s) { cards.appendChild(extSourceCard(s, meta)); });
|
|
2891
3332
|
if (g.items.length >= 4) {
|
|
@@ -2929,125 +3370,49 @@ ${capabilityState.toString()}
|
|
|
2929
3370
|
// 読み取れていない組として現れ、そこに接続ボタンが出る。
|
|
2930
3371
|
// 0件なら繋ぐ相手もまだ無いので、入口が要る場面にならない。
|
|
2931
3372
|
pushCap("チャット", adders.querySelector('[data-adder="slack"]'));
|
|
2932
|
-
//
|
|
2933
|
-
//
|
|
2934
|
-
//
|
|
2935
|
-
//
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
var row = el("div", { class: "ds-owner" }, [
|
|
2948
|
-
el("span", { class: "ds-owner-name", text: o.owner }),
|
|
2949
|
-
el("span", { class: "ds-owner-state ds-gate-" + (ok ? "ok" : "warn"),
|
|
2950
|
-
// **読める件数を出す。** 総数だけ出すと、同じ画面の
|
|
2951
|
-
// 「⚠️ 15件が読めていません」と食い違う(#101 で3度直した形)
|
|
2952
|
-
// **確かめられなかった件数を出す。** 未接続側は「18リポジトリ中 15件が
|
|
2953
|
-
// 読めていません」と出しているのに、こちらだけ総数だと同じ節の中で
|
|
2954
|
-
// 表現が揃わない。4リポ中1つだけ揺れた夜に「4リポジトリを確かめられて
|
|
2955
|
-
// いません」と読めるのも実態と違う
|
|
2956
|
-
text: unsure
|
|
2957
|
-
? "⚠️ 確認できませんでした " + o.repos + "リポジトリ中 " +
|
|
2958
|
-
(o.unchecked || o.repos) + "件の接続を確かめられていません"
|
|
2959
|
-
: ok
|
|
2960
|
-
? "● 接続OK " + o.repos + "リポジトリ" + (o.source === "app" ? "(GitHub App)" : "")
|
|
2961
|
-
: "⚠️ 未接続 " + o.repos + "リポジトリ中 " + o.unreadable + "件が読めていません" }),
|
|
2962
|
-
]);
|
|
2963
|
-
// **未接続のときだけ導線を出す。** 繋がっている組織に「インストール」を
|
|
2964
|
-
// 出すと、押す必要が無いものを押させることになる。
|
|
2965
|
-
// 確かめられなかっただけの組織にも出さない——すでに入っているかもしれないので
|
|
2966
|
-
if (!ok && !unsure) {
|
|
2967
|
-
row.appendChild(el("a", {
|
|
2968
|
-
class: "ds-owner-install",
|
|
2969
|
-
// どの組織かはこの行に出ているので、選ばせる形で足りる(URLの形は
|
|
2970
|
-
// GITHUB_APP_INSTALL_URL のコメントを参照)
|
|
2971
|
-
href: GITHUB_APP_INSTALL_URL,
|
|
2972
|
-
target: "_blank", rel: "noopener",
|
|
2973
|
-
text: "この組織にインストール →",
|
|
2974
|
-
}));
|
|
2975
|
-
}
|
|
2976
|
-
obox.appendChild(row);
|
|
2977
|
-
});
|
|
2978
|
-
pushCap("開発", obox);
|
|
2979
|
-
} else {
|
|
2980
|
-
// **組織が1件も無い案件にも、App の入口を置く(#138)。**
|
|
2981
|
-
// githubOwners は夜間バッチの成果物なので、立ち上げ直後の案件には無い。
|
|
2982
|
-
// インストールの導線を「未接続の組織の行」の中にしか置いていなかったため、
|
|
2983
|
-
// **まだ何も繋いでいない案件=一番 App を入れてほしい案件**の画面に、
|
|
2984
|
-
// App へ行く道が1本も無かった(実機で踏んだ)。
|
|
2985
|
-
var obox0 = el("div", { class: "ds-owners" });
|
|
2986
|
-
obox0.appendChild(el("div", { class: "ds-sub", text: "組織ごとの接続状況" }));
|
|
2987
|
-
obox0.appendChild(el("div", { class: "ds-owner" }, [
|
|
2988
|
-
el("span", { class: "ds-owner-state ds-gate-idle", text: "⦿ 未接続 読み取っている組織はまだありません" }),
|
|
2989
|
-
el("a", {
|
|
2990
|
-
class: "ds-owner-install",
|
|
2991
|
-
href: GITHUB_APP_INSTALL_URL,
|
|
2992
|
-
target: "_blank", rel: "noopener",
|
|
2993
|
-
text: "組織に GitHub App をインストール →",
|
|
2994
|
-
}),
|
|
2995
|
-
]));
|
|
2996
|
-
pushCap("開発", obox0);
|
|
2997
|
-
}
|
|
3373
|
+
// **組織ごとの接続状況は、行と一体にした(2026-08-20・Slack からの横展開)。**
|
|
3374
|
+
//
|
|
3375
|
+
// それまでは「リポジトリの一覧」と「組織ごとの接続状況」が**別々に並んで**おり、
|
|
3376
|
+
// 行を見てもどの組織のものか分からず、状況を見てもどの行の話か分からなかった。
|
|
3377
|
+
// いまは:
|
|
3378
|
+
// - どの組織かは**行のラベル**(extSourceCard)
|
|
3379
|
+
// - 繋がっていない組織は**案内が行を抱える**(githubRows)
|
|
3380
|
+
//
|
|
3381
|
+
// **⚠️ App の導線は、追加フォームの手順に常設してある(#138)。**
|
|
3382
|
+
// 組織ごとの案内は**行が無いと出ない**ので、
|
|
3383
|
+
// **行0件の案件=一番 App を入れてほしい案件**にはそちらしか無い。
|
|
3384
|
+
// 「案内側に導線があるから手順側は省く」とやると #138 が再発する。
|
|
3385
|
+
//
|
|
3386
|
+
// 立ち上げ直後(githubOwners が空)でも、追加フォームは必ず出る
|
|
3387
|
+
// (adders はグループの外に置いてある)。
|
|
2998
3388
|
|
|
2999
3389
|
pushCap("開発", adders.querySelector('[data-adder="github"]'));
|
|
3000
3390
|
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
* 取得に失敗した。**情報が無いので出す**(上の #118 の意図はここが担う)。
|
|
3019
|
-
* - 空の配列([])… 夜間バッチは走ったが、読み取り対象の開発リポジトリが0件。
|
|
3020
|
-
* 読むものが無いのだから鍵も要らない。**出さない**。
|
|
3021
|
-
* 以前はどちらも空配列に丸めていたので、0件の案件にも欄が出続けていた。
|
|
3022
|
-
* **この2つを混ぜると #118 を壊す**(立ち上げ直後の案件から唯一の入口が消える)。
|
|
3023
|
-
*/
|
|
3024
|
-
function githubTokenNeeded() {
|
|
3025
|
-
var list = fleetVal("githubOwners");
|
|
3026
|
-
if (!Array.isArray(list)) return true;
|
|
3027
|
-
if (!list.length) return false;
|
|
3028
|
-
return list.some(function (o) { return !o || (o.source !== "app" && o.source !== "token"); });
|
|
3391
|
+
// **0件の案件にも1行だけ残す(#138 のオーナー判断・置き場所だけ移した)。**
|
|
3392
|
+
// 元は GitHub の読み取りトークンの鍵カードを畳んだ跡地に出していたが、
|
|
3393
|
+
// その鍵ごと廃止したので、GitHub の節の側で持つ。
|
|
3394
|
+
//
|
|
3395
|
+
// **消さないこと。** 立ち上げ直後の案件は、この節に行が1本も無い
|
|
3396
|
+
//(=組織ごとの案内も出ない)。何も言わないと、上のフォームが何のためにあるのか、
|
|
3397
|
+
// 登録したあと何が起きるのかが画面から読み取れない。
|
|
3398
|
+
//
|
|
3399
|
+
// **「[]」(夜間バッチは走ったが対象0件)と 「undefined」(まだ走っていない)は別物。**
|
|
3400
|
+
// 後者に「まだありません」と書くと、実際には登録済みかもしれない案件に嘘を言う
|
|
3401
|
+
var ownersNow = fleetVal("githubOwners");
|
|
3402
|
+
if (Array.isArray(ownersNow) && ownersNow.length === 0) {
|
|
3403
|
+
pushCap("開発", el("p", {
|
|
3404
|
+
class: "sec-how ds-all-connected",
|
|
3405
|
+
text: "読み取り対象の開発リポジトリがまだありません。上のフォームで登録すると、"
|
|
3406
|
+
+ "読めているかどうかを翌朝からここに出します。",
|
|
3407
|
+
}));
|
|
3029
3408
|
}
|
|
3030
3409
|
|
|
3031
3410
|
// 連携の鍵は、その能力のところへ置く(画面下まで往復させない)
|
|
3032
|
-
|
|
3411
|
+
// **GitHub(「external-sources」)はここに無い。** 読み取りトークンは廃止し、
|
|
3412
|
+
// 読み取りは GitHub App に一本化した。**この表に戻すと入力欄が復活する**
|
|
3413
|
+
var SECRET_CAP = { figma: "デザイン", backlog: "課題管理" };
|
|
3033
3414
|
(SITE.secretKinds || []).forEach(function (k) {
|
|
3034
3415
|
if (!SECRET_FORMS[k]) return;
|
|
3035
|
-
// 全組織が繋がっているなら、入力欄ではなく**そう言う1行**に畳む(#118)。
|
|
3036
|
-
// 何も出さないと「トークンはどこで入れるのか」が分からなくなる
|
|
3037
|
-
if (k === "external-sources" && !githubTokenNeeded()) {
|
|
3038
|
-
// **0件の案件に「すべての組織に接続済み」と言わない(#138)。** 組織が1つも無いのに
|
|
3039
|
-
// 接続済みと書けば嘘になる。畳む理由が違うので、文も分ける——次の一歩
|
|
3040
|
-
//(リポジトリを登録する)が同じモーダルの上にあることまで書く
|
|
3041
|
-
var ownersNow = fleetVal("githubOwners");
|
|
3042
|
-
var noRepos = Array.isArray(ownersNow) && ownersNow.length === 0;
|
|
3043
|
-
pushCap(SECRET_CAP[k], el("p", {
|
|
3044
|
-
class: "sec-how ds-all-connected",
|
|
3045
|
-
text: noRepos
|
|
3046
|
-
? "読み取り対象の開発リポジトリがまだありません。このモーダルの上にあるリポジトリの追加フォームで登録すると、トークンが要るかどうかをここに出します。"
|
|
3047
|
-
: "すべての組織に接続済みです(GitHub App / 登録済みトークン)。読み取りトークンの登録は要りません。",
|
|
3048
|
-
}));
|
|
3049
|
-
return;
|
|
3050
|
-
}
|
|
3051
3416
|
// **意図的にOFFにした能力にだけ、入力欄を出さない(0.4.71)。** 使わないと決めたものに
|
|
3052
3417
|
// 鍵を求めるのは、設定する必要が無いものに設定を促す偽の警告と同じ。
|
|
3053
3418
|
// 何も出さないと「トークンはどこで入れるのか」が分からなくなるので、理由を1行だけ残す
|
|
@@ -3065,6 +3430,37 @@ ${capabilityState.toString()}
|
|
|
3065
3430
|
}));
|
|
3066
3431
|
return;
|
|
3067
3432
|
}
|
|
3433
|
+
// **Backlog は接続先のスペースごとにカードを出す(2026-08-20・#127)。**
|
|
3434
|
+
// キーはスペースごとに別なので、欄が1つだと**どちらの鍵を入れたのか
|
|
3435
|
+
// 誰にも分からない**まま片方の棚に入る(入れたのに動かない、が起きる)。
|
|
3436
|
+
//
|
|
3437
|
+
// **置き場は行の中(2026-08-21)。** backlogTargetsSection が接続先の行ごとに
|
|
3438
|
+
// 受け皿を用意しているので、そこへ差し込む。受け皿が無い案件
|
|
3439
|
+
//(intake を持たない・固定IP同期)では従来どおり能力カードの直下へ積む
|
|
3440
|
+
//——**ここで return してしまうと、鍵の欄しか無い案件で鍵が丸ごと消える。**
|
|
3441
|
+
if (k === "backlog") {
|
|
3442
|
+
var slots = KEY_SLOTS.backlog;
|
|
3443
|
+
var spaces = Object.keys(slots);
|
|
3444
|
+
if (spaces.length) {
|
|
3445
|
+
spaces.forEach(function (space) {
|
|
3446
|
+
slots[space].appendChild(secretCard(k, SECRET_FORMS[k], {
|
|
3447
|
+
// **名乗るのは名簿由来の行だけ。** 同期ミラーのURLから作った行で
|
|
3448
|
+
// スペースを名乗ると、名簿とミラーがずれている案件で**黙って別の棚に入る**
|
|
3449
|
+
space: KEY_SLOTS.backlogNamed ? space : "",
|
|
3450
|
+
stateSpace: space,
|
|
3451
|
+
spaceCount: spaces.length,
|
|
3452
|
+
inRow: true,
|
|
3453
|
+
}));
|
|
3454
|
+
});
|
|
3455
|
+
return;
|
|
3456
|
+
}
|
|
3457
|
+
backlogSecretCards().forEach(function (n) { pushCap(SECRET_CAP[k], n); });
|
|
3458
|
+
return;
|
|
3459
|
+
}
|
|
3460
|
+
if (k === "figma" && KEY_SLOTS.figma) {
|
|
3461
|
+
KEY_SLOTS.figma.appendChild(secretCard(k, SECRET_FORMS[k], { inRow: true }));
|
|
3462
|
+
return;
|
|
3463
|
+
}
|
|
3068
3464
|
pushCap(SECRET_CAP[k], secretCard(k, SECRET_FORMS[k]));
|
|
3069
3465
|
});
|
|
3070
3466
|
|
|
@@ -3089,7 +3485,9 @@ ${capabilityState.toString()}
|
|
|
3089
3485
|
"開発": { icon: "🐙", desc: "IssuesをGoldの材料に" },
|
|
3090
3486
|
};
|
|
3091
3487
|
var STATE_LABEL = { ok: "● 接続OK", idle: "⦿ 未接続", off: "未使用", warn: "⚠️" };
|
|
3092
|
-
|
|
3488
|
+
// **「開発」はここに無い。** GitHub の読み取りトークンは廃止したので、
|
|
3489
|
+
// 鍵の未設定を語る相手がいない(読めていないときは組織ごとの案内が拾う)
|
|
3490
|
+
var SECRET_OF_CAP = { "デザイン": "figma", "課題管理": "backlog" };
|
|
3093
3491
|
|
|
3094
3492
|
// ---- セットアップの残り(checks)----
|
|
3095
3493
|
//
|
|
@@ -3190,7 +3588,8 @@ ${capabilityState.toString()}
|
|
|
3190
3588
|
} else if (live.length) {
|
|
3191
3589
|
// 単位は分かるものだけ。知らない種別に勝手な単位を付けない。
|
|
3192
3590
|
// **「N件をGoldに使用」の内訳は出さない。** チャンネルは載っていれば全部が対象で、
|
|
3193
|
-
// github
|
|
3591
|
+
// github の除外は行のバッジ(「読み取り停止中」)が示す
|
|
3592
|
+
//(件数の内訳は Gold トグルがあった頃の名残)
|
|
3194
3593
|
var unit = cap === "チャット" ? "チャンネル" : cap === "開発" ? "リポジトリ" : "件";
|
|
3195
3594
|
parts.push(live.length + unit);
|
|
3196
3595
|
} else if (cap === "共有資料" && adapter === "google-drive" && internal && internal.driveFolderIds) {
|
|
@@ -3292,10 +3691,6 @@ ${capabilityState.toString()}
|
|
|
3292
3691
|
// 新規案件——**まさに何を入れれば繋がるのかを知りたい場面**——から、
|
|
3293
3692
|
// 鍵が未設定であることの手がかりまで消える
|
|
3294
3693
|
var sk = SECRET_OF_CAP[cap];
|
|
3295
|
-
// **GitHub は「トークンが無い」=「読めていない」ではない(#118)。** App で読めている
|
|
3296
|
-
// 案件に未設定の警告を出すと、直す必要が無いものを直させることになる。
|
|
3297
|
-
// 読めていない組織があるときは、この下の checks とタイルの状態(warn)が拾う
|
|
3298
|
-
var tokenIsFallback = sk === "external-sources" && !githubTokenNeeded();
|
|
3299
3694
|
// **#125②: 導出があるときは導出で判断する。** OFF(意図的に止めた)にだけ出さない
|
|
3300
3695
|
// ——入れる必要が無いものについて設定を促す偽の警告になる。
|
|
3301
3696
|
//
|
|
@@ -3304,7 +3699,7 @@ ${capabilityState.toString()}
|
|
|
3304
3699
|
// 0.4.70 は unset で入力欄を畳んでいたので注記も抑えていたが、案A で欄を出すようにしたため揃えた
|
|
3305
3700
|
// 導出が無いデータでは判断材料が無いので、注記を出す側(=入力欄と揃う側)に倒す
|
|
3306
3701
|
var tokenRelevant = derived != null ? derived !== "off" : true;
|
|
3307
|
-
if (
|
|
3702
|
+
if (tokenRelevant && sk && (SITE.secretKinds || []).indexOf(sk) >= 0 && !((fleetVal("secretSources") || {})[sk])) {
|
|
3308
3703
|
body.appendChild(el("div", { class: "ds-tile-note", text: "⚠ トークンが未設定です" }));
|
|
3309
3704
|
}
|
|
3310
3705
|
// セットアップの残りのうち、この能力のもの。**鍵の注記と同じ位置**に出して
|
|
@@ -3357,7 +3752,7 @@ ${capabilityState.toString()}
|
|
|
3357
3752
|
|
|
3358
3753
|
// 注記は全能力の後ろに1つ。**何が Gold の材料になるのかを1文で言う。**
|
|
3359
3754
|
if (anyCap) {
|
|
3360
|
-
sec.appendChild(el("p", { class: "ds-note", text: "登録されている Slack チャンネルと GitHub リポジトリは、毎晩の Gold 昇格が読み取り、Decision
|
|
3755
|
+
sec.appendChild(el("p", { class: "ds-note", text: "登録されている Slack チャンネルと GitHub リポジトリは、毎晩の Gold 昇格が読み取り、Decision・用語集の材料になります。チャンネルは登録を解除すると、リポジトリは登録から削除すると、以後は読み取られません。" }));
|
|
3361
3756
|
}
|
|
3362
3757
|
|
|
3363
3758
|
if (pipes.length) {
|
|
@@ -3437,7 +3832,7 @@ ${capabilityState.toString()}
|
|
|
3437
3832
|
* 注: ここは埋め込みJSのテンプレートリテラル内。**コメントでもバッククォートを使わない**
|
|
3438
3833
|
*(リテラルが閉じて構文エラーになる。実際にそれで壊した)。
|
|
3439
3834
|
*
|
|
3440
|
-
*
|
|
3835
|
+
* **これが画面から Slack の読み取りを止める唯一の手段。** チャンネル単位の Gold トグルは撤去した
|
|
3441
3836
|
* (載っているチャンネルは例外なく全て Gold 昇格の対象)。事故(社内限定の会話が顧客可視の
|
|
3442
3837
|
* Gold へ流れ始めた)に画面から手を打てないと、git で channels.json を直接編集するしかない。
|
|
3443
3838
|
*
|
|
@@ -3780,6 +4175,48 @@ ${capabilityState.toString()}
|
|
|
3780
4175
|
* **読み手が見に行くのと別の棚へ黙って入る**(入れたのに動かない、が一番起きてほしくない形)。
|
|
3781
4176
|
* 名乗らなければサーバが従来どおり名簿の値を使う。
|
|
3782
4177
|
*/
|
|
4178
|
+
/**
|
|
4179
|
+
* Backlog のAPIキーの欄を、接続先のスペースごとに出す(2026-08-20・#127)。
|
|
4180
|
+
*
|
|
4181
|
+
* **キーはスペースごとに別。** 欄が1つだと、複数スペースの案件で
|
|
4182
|
+
* 「どちらの鍵を入れたのか」が誰にも分からないまま片方の棚に入る。
|
|
4183
|
+
*
|
|
4184
|
+
* **ここは受け皿が無いときの退避先(2026-08-21)。** ふつうは接続先の行の中へ
|
|
4185
|
+
* 差し込む(KEY_SLOTS のコメント参照)。この関数が使われるのは、
|
|
4186
|
+
* 行を描く経路そのものが無い案件——intake を持たない案件——だけ。
|
|
4187
|
+
*
|
|
4188
|
+
* ## 登録状況はスペースごとに引く
|
|
4189
|
+
*
|
|
4190
|
+
* 夜間の実測(secretSources.backlog)は**種別ごと**の1つの値で、スペース別の充足を
|
|
4191
|
+
* 表せない。1枚目に帰属させると**片方だけ入れた状態で両方に「登録済み」と出る**
|
|
4192
|
+
* ——画面が嘘をつく。スペース別の答えは secretSpaces(engine 側)が持ち、
|
|
4193
|
+
* それが無い生成物では**断定しない**(「確認中」に倒す)。
|
|
4194
|
+
*
|
|
4195
|
+
* ## 接続先がまだ無いとき
|
|
4196
|
+
*
|
|
4197
|
+
* カードは1枚だけ出す(スペースは名乗らない)。サーバは名簿の値に倒す。
|
|
4198
|
+
*/
|
|
4199
|
+
function backlogSecretCards() {
|
|
4200
|
+
var spaces = backlogSpacesNow();
|
|
4201
|
+
if (spaces.length <= 1) return [secretCard("backlog", SECRET_FORMS["backlog"], { spaceCount: spaces.length })];
|
|
4202
|
+
return spaces.map(function (space) {
|
|
4203
|
+
return secretCard("backlog", SECRET_FORMS["backlog"], {
|
|
4204
|
+
space: space, stateSpace: space, spaceCount: spaces.length,
|
|
4205
|
+
});
|
|
4206
|
+
});
|
|
4207
|
+
}
|
|
4208
|
+
|
|
4209
|
+
/** 画面が見ている接続先のスペース一覧(重複なし) */
|
|
4210
|
+
function backlogSpacesNow() {
|
|
4211
|
+
var list = backlogTargetsNow(null);
|
|
4212
|
+
var domains = [];
|
|
4213
|
+
for (var i = 0; i < list.length; i++) {
|
|
4214
|
+
var d = String(list[i].domain || "").toLowerCase();
|
|
4215
|
+
if (d && domains.indexOf(d) === -1) domains.push(d);
|
|
4216
|
+
}
|
|
4217
|
+
return domains;
|
|
4218
|
+
}
|
|
4219
|
+
|
|
3783
4220
|
function backlogSecretSpace() {
|
|
3784
4221
|
var list = backlogTargetsNow(null);
|
|
3785
4222
|
var domains = [];
|
|
@@ -3805,17 +4242,25 @@ ${capabilityState.toString()}
|
|
|
3805
4242
|
var targets = backlogTargetsNow(s);
|
|
3806
4243
|
var editable = backlogTargetsEditable();
|
|
3807
4244
|
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
4245
|
+
// **Slack / GitHub / Figma / Drive と同じレコードの行にする(2026-08-21・オーナー指摘)。**
|
|
4246
|
+
// それまでは「現在の接続先」というラベル付きの独自レイアウト(.ds-current /
|
|
4247
|
+
// .ds-target-row)で、同じモーダルの中でもここだけ行間と見た目が違っていた。
|
|
4248
|
+
var listEl = el("div", { class: "ds-list" });
|
|
4249
|
+
// **0件の1行は一覧の外に置く**(Figma / Drive と同じ形)。中に .ds-card として
|
|
4250
|
+
// 置くと「行が1件ある」と読まれ、一覧を数えるテストにも行として数えられる
|
|
4251
|
+
var emptyEl = el("p", { class: "ds-empty", text: "同期する接続先はまだ登録されていません(未設定)。" });
|
|
3813
4252
|
// 追加・削除の結果はここに1つだけ出す(行を描き直しても消えない位置)
|
|
3814
4253
|
var msg = el("div", { class: "ds-toggle-msg" });
|
|
3815
4254
|
|
|
3816
4255
|
function removeRow(t) {
|
|
3817
|
-
|
|
3818
|
-
|
|
4256
|
+
// **ds-type はツール名**(能力名を入れると上の見出しと重複する)。
|
|
4257
|
+
// **名前はリンクにする**——Drive / Figma の行と同じく、正本を新しいタブで開ける
|
|
4258
|
+
var row = el("div", { class: "ds-card" }, [
|
|
4259
|
+
el("div", { class: "ds-card-main" }, [
|
|
4260
|
+
el("span", { class: "ds-icon", text: "📋" }),
|
|
4261
|
+
el("span", { class: "ds-type", text: "Backlog" }),
|
|
4262
|
+
dsNameEl(t.domain + " / " + t.projectKey, "https://" + t.domain + "/projects/" + t.projectKey),
|
|
4263
|
+
]),
|
|
3819
4264
|
]);
|
|
3820
4265
|
if (!editable) return row;
|
|
3821
4266
|
var btn = el("button", { class: "ds-toggle-btn ds-danger", type: "button", text: "この接続先を外す" });
|
|
@@ -3840,14 +4285,54 @@ ${capabilityState.toString()}
|
|
|
3840
4285
|
return row;
|
|
3841
4286
|
}
|
|
3842
4287
|
|
|
4288
|
+
/**
|
|
4289
|
+
* 描く順番。**同じスペースの行を隣り合わせにする(2026-08-21)。**
|
|
4290
|
+
*
|
|
4291
|
+
* 鍵の欄はそのスペースの**最後の行の下**に1つだけ出すので、
|
|
4292
|
+
* 「cm1/A, jleague/B, cm1/C」のように入り混じっていると
|
|
4293
|
+
* **どの行の鍵なのかが読めない**(cm1 の鍵が jleague の行を挟んだ先に出る)。
|
|
4294
|
+
* スペースの初出の順は保つので、一覧の見え方は今までと変わらない。
|
|
4295
|
+
*/
|
|
4296
|
+
function grouped(list) {
|
|
4297
|
+
var order = [];
|
|
4298
|
+
var byDomain = {};
|
|
4299
|
+
for (var i = 0; i < list.length; i++) {
|
|
4300
|
+
var d = String(list[i].domain || "").toLowerCase();
|
|
4301
|
+
if (!byDomain[d]) { byDomain[d] = []; order.push(d); }
|
|
4302
|
+
byDomain[d].push(list[i]);
|
|
4303
|
+
}
|
|
4304
|
+
var out = [];
|
|
4305
|
+
for (var j = 0; j < order.length; j++) out = out.concat(byDomain[order[j]]);
|
|
4306
|
+
return out;
|
|
4307
|
+
}
|
|
4308
|
+
|
|
3843
4309
|
function paint() {
|
|
3844
4310
|
while (listEl.firstChild) listEl.removeChild(listEl.firstChild);
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
4311
|
+
var shown = grouped(targets);
|
|
4312
|
+
// そのスペースの**最後の行**を覚えておく(鍵の欄はそこへ入れる)
|
|
4313
|
+
var lastRowOf = {};
|
|
4314
|
+
for (var i = 0; i < shown.length; i++) {
|
|
4315
|
+
var row = removeRow(shown[i]);
|
|
4316
|
+
listEl.appendChild(row);
|
|
4317
|
+
lastRowOf[String(shown[i].domain || "").toLowerCase()] = row;
|
|
3849
4318
|
}
|
|
3850
|
-
|
|
4319
|
+
// 🔴 **鍵の欄は作り直さない。入れ直すだけ。** ここは追加・削除の応答でも
|
|
4320
|
+
// 呼ばれるので、作り直すと**接続先を1つ足しただけで入力中の鍵と「保存中…」が消える**
|
|
4321
|
+
//(ライブ差し替えで踏んだのと同じ事故が、別の経路で復活する)。
|
|
4322
|
+
// appendChild は既存ノードを移すだけなので、入力値もイベントも保たれる
|
|
4323
|
+
for (var d in keySlots) {
|
|
4324
|
+
if (!Object.prototype.hasOwnProperty.call(keySlots, d)) continue;
|
|
4325
|
+
if (!d) continue; // 接続先が無い案件の受け皿は box 側に置いてある(行が無い)
|
|
4326
|
+
var host = lastRowOf[d];
|
|
4327
|
+
if (host) host.appendChild(keySlots[d]);
|
|
4328
|
+
else if (keySlots[d].parentNode) keySlots[d].parentNode.removeChild(keySlots[d]);
|
|
4329
|
+
}
|
|
4330
|
+
// **0件を黙って見せない。** 表示が無いと「まだ何も無い」のか「出し忘れ」なのか
|
|
4331
|
+
// 区別できない。**一覧の外**(Figma / Drive と同じ)に、件数に応じて出し入れする
|
|
4332
|
+
// ——出しっぱなしにすると、設定済みの案件にも「未設定」と書いた行が残る
|
|
4333
|
+
var here = emptyEl.parentNode === box;
|
|
4334
|
+
if (!targets.length && !here) box.insertBefore(emptyEl, listEl.nextSibling);
|
|
4335
|
+
else if (targets.length && here) box.removeChild(emptyEl);
|
|
3851
4336
|
}
|
|
3852
4337
|
|
|
3853
4338
|
/**
|
|
@@ -3870,8 +4355,40 @@ ${capabilityState.toString()}
|
|
|
3870
4355
|
return { onTargets: adoptTargets, staleNote: TARGETS_RACE_NOTE };
|
|
3871
4356
|
}
|
|
3872
4357
|
|
|
4358
|
+
// **鍵の欄の受け皿を、行のスペースごとに1つ用意する(2026-08-21・オーナー指摘)。**
|
|
4359
|
+
//
|
|
4360
|
+
// 🔴 **行のドメインから引くこと。** backlogSpacesNow() は backlogTargetsNow(null) を
|
|
4361
|
+
// 呼ぶので、fleet が接続先を持たない案件(同期ミラーのURLから1行だけ作っている案件)では
|
|
4362
|
+
// **空を返す**——行は出るのに鍵の欄が1つも付かない、という空振りになる。
|
|
4363
|
+
//
|
|
4364
|
+
// **この画面から投入できない案件(固定IP同期)には出さない。** 押しても Lambda が
|
|
4365
|
+
// 「固定IP経由のため対応していません」で断るので、導線そのものを作らない。
|
|
4366
|
+
// 判定は鍵カードを出すループの条件と同じ線(SITE.secretKinds に backlog があるか)。
|
|
4367
|
+
var keySlots = {};
|
|
4368
|
+
if (editable && !Object.keys(KEY_SLOTS.backlog).length) {
|
|
4369
|
+
// 保存時にスペースを名乗ってよいのは、名簿(fleet の backlogTarget)由来の行だけ。
|
|
4370
|
+
// 同期ミラーのURLから作った行で名乗ると、名簿とミラーがずれている案件で
|
|
4371
|
+
// **黙って別の棚に入る**(入れたのに動かない、が一番起きてほしくない形)
|
|
4372
|
+
KEY_SLOTS.backlogNamed = backlogTargetsNow(null).length > 0;
|
|
4373
|
+
var domains = [];
|
|
4374
|
+
for (var ti = 0; ti < targets.length; ti++) {
|
|
4375
|
+
var dom = String(targets[ti].domain || "").toLowerCase();
|
|
4376
|
+
if (dom && domains.indexOf(dom) === -1) domains.push(dom);
|
|
4377
|
+
}
|
|
4378
|
+
// **0件の案件にも1つ出す。** 「接続先を足してからでないと鍵を入れられない」形にすると、
|
|
4379
|
+
// 立ち上げ直後の案件が最初の一歩を踏めない(#138 で直したのと同じ穴)。
|
|
4380
|
+
// 空文字のキーは「どのスペースとも結び付いていない受け皿」で、行の中には入らない
|
|
4381
|
+
if (!domains.length) domains.push("");
|
|
4382
|
+
for (var di = 0; di < domains.length; di++) keySlots[domains[di]] = el("div", { class: "ds-keyrow" });
|
|
4383
|
+
KEY_SLOTS.backlog = keySlots;
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4386
|
+
// **box を先に作る。** paint() は 0件の1行を box へ出し入れするので、
|
|
4387
|
+
// 箱が無いと最初の描画で「未設定」の行が出ない
|
|
4388
|
+
var box = el("div", {}, [listEl]);
|
|
3873
4389
|
paint();
|
|
3874
|
-
|
|
4390
|
+
// 接続先がまだ無い案件の受け皿は、0件の1行の直後に置く(行が無いので中へ入れられない)
|
|
4391
|
+
if (keySlots[""]) box.appendChild(keySlots[""]);
|
|
3875
4392
|
if (editable) {
|
|
3876
4393
|
box.appendChild(addForm({
|
|
3877
4394
|
// **「追加」に戻す(#127)。** 1件しか持てなかった頃は「保存」(置き換え)だったが、
|
|
@@ -3879,7 +4396,27 @@ ${capabilityState.toString()}
|
|
|
3879
4396
|
title: "+ 接続先を追加",
|
|
3880
4397
|
placeholder: "https://<スペース>.backlog.jp/projects/<プロジェクトキー>",
|
|
3881
4398
|
requiredNote: "BacklogのURLを入力してください(プロジェクトキーが入った形。数字だけのURLは受け付けません)。",
|
|
3882
|
-
|
|
4399
|
+
// **手順のリストにする(2026-08-20・Slack からの横展開)。**
|
|
4400
|
+
// **リスト(ol.sec-steps)そのものは維持する**——他の能力の手順と形を揃える。
|
|
4401
|
+
//
|
|
4402
|
+
// **鍵の発行手順は二重に持たない。** 正本は接続先の行の下にある鍵の欄
|
|
4403
|
+
//(SECRET_FORMS.backlog の how)で、ここからは参照するだけ。
|
|
4404
|
+
//
|
|
4405
|
+
// ## 4行 → 2行に圧縮した(2026-08-21・オーナー指摘「何も変わってない気がする」)
|
|
4406
|
+
//
|
|
4407
|
+
// **この欄は URL を貼るだけ**なので、4行の説明が読む負担に見合わない。
|
|
4408
|
+
// ただし**落としてよいのは1行目だけ**だった(欄を見れば分かる内容)。残り3つは
|
|
4409
|
+
// ここ以外に置き場が無いので、**消さずに2行へ畳んでいる**:
|
|
4410
|
+
// - 「起票先は変わりません」… 追加の確認をやめたとき(2026-08-20)に
|
|
4411
|
+
// ここへ移してきたもの。落とすと知る手段が無くなる
|
|
4412
|
+
// - 「スペースごとに別のキー」… 鍵の欄からは読めない。1スペースの案件は
|
|
4413
|
+
// 行が1本しか無いので、これから2つ目を足す人に「別の鍵が要る」が届かない
|
|
4414
|
+
// - 「案件専用URLの登録」… 救出先の realtimeSyncCard() は稼働中の案件では
|
|
4415
|
+
// 手順一式を <details> に畳むので、**いちばん要る人に対して閉じている**
|
|
4416
|
+
hint: [
|
|
4417
|
+
"URL を貼ると同期先が増えます。ビューアからの起票先は変わりません(スペースごとに別のAPIキーが要ります)。",
|
|
4418
|
+
"リアルタイム同期を使うなら、追加したプロジェクトにも案件専用URLの登録が要ります。",
|
|
4419
|
+
],
|
|
3883
4420
|
build: function (url) {
|
|
3884
4421
|
return { op: "backlog-target-add", url: url, baseGeneration: targetsGenerationOf(targets) };
|
|
3885
4422
|
},
|
|
@@ -4013,15 +4550,11 @@ ${capabilityState.toString()}
|
|
|
4013
4550
|
box.appendChild(el("p", { class: "sec-how", text: "共有資料の取り込み設定を読み取れないため、この画面からは変更できません。cortex の担当者にご連絡ください。" }));
|
|
4014
4551
|
used = true;
|
|
4015
4552
|
} else if (s.driveState) {
|
|
4016
|
-
//
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
requiredNote: "フォルダのURLを入力してください。",
|
|
4022
|
-
hint: "このフォルダの中身が 共有資料 にコピーされ、Markdown 化されます。取り込み用アカウントをそのフォルダの閲覧者に招待しておいてください(招待が無いと読めません)。",
|
|
4023
|
-
build: function (url, name) { return { op: "add-drive-folder", url: url, name: name }; },
|
|
4024
|
-
}));
|
|
4553
|
+
// **レコードが先・追加フォームが後(2026-08-21)。** Slack / GitHub と同じ並びに揃える。
|
|
4554
|
+
// それまではフォームが先だった。理由は「フォルダが1件も無いのに ON/OFF だけ出しても
|
|
4555
|
+
// 意味が無いから」だったが、**その ON/OFF トグルは既に廃止されている**(下の注記)。
|
|
4556
|
+
// 理由が消えたのに順序だけ残っていた。デザインと課題管理は元から「レコード → フォーム」。
|
|
4557
|
+
//
|
|
4025
4558
|
// **ON/OFFのトグルは出さない。** フォルダを追加した時点で取り込みは始まる
|
|
4026
4559
|
// (applyAddDriveFolder が enabled を立てる)ので「始める」を押す機会が無い。
|
|
4027
4560
|
// 止めたいならフォルダを外す——登録そのものが意思表示、という会議と同じ考え方。
|
|
@@ -4029,11 +4562,19 @@ ${capabilityState.toString()}
|
|
|
4029
4562
|
// 名前は任意。**無ければIDを出す**(既存の案件は名前を持っていない)
|
|
4030
4563
|
var fnames = s.driveFolderNames || {};
|
|
4031
4564
|
if (folders.length) {
|
|
4032
|
-
var dlist = el("div", { class: "ds-
|
|
4565
|
+
var dlist = el("div", { class: "ds-list" });
|
|
4033
4566
|
folders.forEach(function (id) {
|
|
4034
4567
|
var fname = fnames[id];
|
|
4035
|
-
|
|
4036
|
-
|
|
4568
|
+
// **Slack / GitHub の行と同じ構造にする(ds-card > ds-card-main >
|
|
4569
|
+
// ds-icon + ds-type + ds-name)。** extSourceCard は呼ばない——
|
|
4570
|
+
// あちらは type / gate / origin など外部ソース固有の判断を抱えている。
|
|
4571
|
+
// ds-type に入れるのは**ツール名**(能力名を入れると上の見出しと重複する)。
|
|
4572
|
+
var row = el("div", { class: "ds-card" }, [
|
|
4573
|
+
el("div", { class: "ds-card-main" }, [
|
|
4574
|
+
el("span", { class: "ds-icon", text: "📁" }),
|
|
4575
|
+
el("span", { class: "ds-type", text: "Google Drive" }),
|
|
4576
|
+
dsNameEl(fname || id, "https://drive.google.com/drive/folders/" + id),
|
|
4577
|
+
]),
|
|
4037
4578
|
]);
|
|
4038
4579
|
// **名前を出したときはIDも併記する。** 同名のフォルダを見分けられなくなるのと、
|
|
4039
4580
|
// 「このIDを外す」という確認文と画面の表示が食い違うのを防ぐ
|
|
@@ -4054,12 +4595,41 @@ ${capabilityState.toString()}
|
|
|
4054
4595
|
return lines;
|
|
4055
4596
|
},
|
|
4056
4597
|
build: function () { return { op: "remove-drive-folder", id: id }; },
|
|
4057
|
-
|
|
4598
|
+
// **クラスのハード代入をやめる**(片方だけ直し忘れる形を構造的に消す)
|
|
4599
|
+
onDone: function () { row.classList.add("ds-removed"); },
|
|
4058
4600
|
}));
|
|
4059
4601
|
dlist.appendChild(row);
|
|
4060
4602
|
});
|
|
4061
4603
|
box.appendChild(dlist);
|
|
4604
|
+
} else if (s.driveState === "empty") {
|
|
4605
|
+
// **0件を黙って見せない。** 追加フォームだけだと「まだ登録していない」のか
|
|
4606
|
+
// 「読めていない」のか区別できない。
|
|
4607
|
+
//
|
|
4608
|
+
// **判定は driveState === "empty" にする。** engine(fleet-status.mjs)は
|
|
4609
|
+
// driveFolderIds を「1件以上あるときだけ」出すので、キーの有無では
|
|
4610
|
+
// 未取得(unset / broken)と0件を見分けられない。unset / broken は
|
|
4611
|
+
// 上の分岐で先に返しているので、ここへ来る empty は「読めていて0件」だけ。
|
|
4612
|
+
box.appendChild(el("p", { class: "ds-empty", text: "取り込み対象のフォルダはまだ登録されていません。" }));
|
|
4062
4613
|
}
|
|
4614
|
+
box.appendChild(addForm({
|
|
4615
|
+
title: "+ Google Drive のフォルダを追加",
|
|
4616
|
+
placeholder: "https://drive.google.com/drive/folders/…",
|
|
4617
|
+
namePlaceholder: "メモ(任意)",
|
|
4618
|
+
requiredNote: "フォルダのURLを入力してください。",
|
|
4619
|
+
// **手順のリストにする(2026-08-20・Slack からの横展開)。**
|
|
4620
|
+
//
|
|
4621
|
+
// **取り込み用アカウントのアドレスを出す(オーナー判断・分類A)。**
|
|
4622
|
+
// それまでは「取り込み用アカウントを招待してください」としか書いておらず、
|
|
4623
|
+
// **誰を招待すればいいのかが画面から分からなかった**——担当者に聞かないと
|
|
4624
|
+
// 完了できない手順になっていた。
|
|
4625
|
+
// 招待されない限り何も読めないアカウントなので、出す判断をした。
|
|
4626
|
+
hint: [
|
|
4627
|
+
{ text: "読み取りたい Google Drive のフォルダを開き、下のアカウントを閲覧者として招待します(招待が無いと読めません)。", node: copyRow(DRIVE_INGEST_ACCOUNT) },
|
|
4628
|
+
"そのフォルダのURLを下の欄に貼って「追加」を押します。",
|
|
4629
|
+
"追加したフォルダの中身が 共有資料 にコピーされ、Markdown 化されます。止めるときは、その行の「このフォルダを外す」を押します。",
|
|
4630
|
+
],
|
|
4631
|
+
build: function (url, name) { return { op: "add-drive-folder", url: url, name: name }; },
|
|
4632
|
+
}));
|
|
4063
4633
|
used = true;
|
|
4064
4634
|
}
|
|
4065
4635
|
}
|
|
@@ -4073,10 +4643,18 @@ ${capabilityState.toString()}
|
|
|
4073
4643
|
// 描画時点の件数で判定すると、3件を1件ずつ外していったとき最後の1件でも警告が出ない。
|
|
4074
4644
|
var figsLeft = figs.length;
|
|
4075
4645
|
if (figs.length) {
|
|
4076
|
-
var flist = el("div", { class: "ds-
|
|
4646
|
+
var flist = el("div", { class: "ds-list" });
|
|
4077
4647
|
figs.forEach(function (f) {
|
|
4078
|
-
|
|
4079
|
-
|
|
4648
|
+
// **Slack / GitHub の行と同じ構造にする(ds-card > ds-card-main >
|
|
4649
|
+
// ds-icon + ds-type + ds-name)。** extSourceCard は呼ばない——
|
|
4650
|
+
// あちらは type / gate / origin など外部ソース固有の判断を抱えている。
|
|
4651
|
+
// ds-type に入れるのは**ツール名**(能力名を入れると上の見出しと重複する)。
|
|
4652
|
+
var row = el("div", { class: "ds-card" }, [
|
|
4653
|
+
el("div", { class: "ds-card-main" }, [
|
|
4654
|
+
el("span", { class: "ds-icon", text: "🎨" }),
|
|
4655
|
+
el("span", { class: "ds-type", text: "Figma" }),
|
|
4656
|
+
dsNameEl(f.name || f.key, "https://www.figma.com/design/" + f.key),
|
|
4657
|
+
]),
|
|
4080
4658
|
]);
|
|
4081
4659
|
row.appendChild(removeButton({
|
|
4082
4660
|
label: "このファイルを外す",
|
|
@@ -4100,7 +4678,8 @@ ${capabilityState.toString()}
|
|
|
4100
4678
|
},
|
|
4101
4679
|
build: function () { return { op: "remove-figma-file", key: f.key }; },
|
|
4102
4680
|
onDone: function () {
|
|
4103
|
-
|
|
4681
|
+
// **クラスのハード代入をやめる**(片方だけ直し忘れる形を構造的に消す)
|
|
4682
|
+
row.classList.add("ds-removed");
|
|
4104
4683
|
figsLeft -= 1;
|
|
4105
4684
|
},
|
|
4106
4685
|
}));
|
|
@@ -4112,12 +4691,32 @@ ${capabilityState.toString()}
|
|
|
4112
4691
|
// 「読めていない」のか区別できない(Driveは driveState で理由まで出している)
|
|
4113
4692
|
box.appendChild(el("p", { class: "ds-empty", text: "同期対象のFigmaファイルはまだ登録されていません。" }));
|
|
4114
4693
|
}
|
|
4694
|
+
// **鍵の欄は一覧の直後に1つ(2026-08-21・オーナー指摘)。**
|
|
4695
|
+
// Backlog と違い、Figma の鍵は**案件に1本**(ファイルごとではない)。
|
|
4696
|
+
// 行ごとに出すと同じ欄が並ぶだけなので、一覧をひとまとまりと見て、その下に置く。
|
|
4697
|
+
// **中身を作るのはここではない**——SECRET_FORMS のループが差し込む
|
|
4698
|
+
//(intake / OFF のゲートをループ側に残すため。KEY_SLOTS のコメント参照)
|
|
4699
|
+
if (!KEY_SLOTS.figma) {
|
|
4700
|
+
KEY_SLOTS.figma = el("div", { class: "ds-keyrow ds-keyrow-list" });
|
|
4701
|
+
box.appendChild(KEY_SLOTS.figma);
|
|
4702
|
+
}
|
|
4115
4703
|
box.appendChild(addForm({
|
|
4116
4704
|
title: "+ Figmaファイルを追加",
|
|
4117
4705
|
placeholder: "https://www.figma.com/design/…",
|
|
4118
4706
|
namePlaceholder: "メモ(任意)",
|
|
4119
4707
|
requiredNote: "FigmaのURLを入力してください。",
|
|
4120
|
-
|
|
4708
|
+
// **手順のリストにする(2026-08-20・Slack からの横展開)。**
|
|
4709
|
+
// 一続きの文章だと、読む人が「自分がいま何をすべきか」を自分で切り出すことになる。
|
|
4710
|
+
//
|
|
4711
|
+
// **手順1・2は要約にとどめ、正本は上の鍵の欄に置く**(SECRET_FORMS.figma の
|
|
4712
|
+
// how / note)。全文をここに移すと二重になり、片方だけ直る形になる
|
|
4713
|
+
// ——カードは接続マップとタイルの注記と条件を揃えているので、動かすと壊れやすい。
|
|
4714
|
+
hint: [
|
|
4715
|
+
"Figma でトークンを発行します(読み取りだけ。スコープ2つ)。手順は上の「Figma のトークン」の欄にあります。",
|
|
4716
|
+
"発行したアカウントを、読み取りたい Figma ファイルに閲覧者として招待します(招待が無いと、トークンが正しくても読めません)。",
|
|
4717
|
+
"そのファイルのURLを下の欄に貼って「追加」を押します。",
|
|
4718
|
+
"追加したファイルは、画面名と Figma へのリンクが毎晩同期されます(画像は取り込まれません)。",
|
|
4719
|
+
],
|
|
4121
4720
|
build: function (url, name) { return { op: "add-figma-file", url: url, name: name }; },
|
|
4122
4721
|
}));
|
|
4123
4722
|
used = true;
|
|
@@ -4215,7 +4814,21 @@ ${capabilityState.toString()}
|
|
|
4215
4814
|
placeholder: "owner/repo または https://github.com/owner/repo",
|
|
4216
4815
|
namePlaceholder: "メモ(任意)",
|
|
4217
4816
|
requiredNote: "リポジトリを入力してください。",
|
|
4218
|
-
|
|
4817
|
+
// **手順のリストにする(2026-08-20・Slack からの横展開)。**
|
|
4818
|
+
//
|
|
4819
|
+
// **App の導線をここに常設する(#138 の再発防止・唯一の防波堤)。**
|
|
4820
|
+
// それまでは「組織ごとの接続状況」という独立した一覧の中にしか
|
|
4821
|
+
// 導線が無く、**まだ何も繋いでいない案件=一番 App を入れてほしい案件**の
|
|
4822
|
+
// 画面に App へ行く道が1本も無かった(実機で踏んだ)。
|
|
4823
|
+
//
|
|
4824
|
+
// **行が0件でも、この手順は必ず出る**(追加フォームはグループの外にある)。
|
|
4825
|
+
// 組織ごとの案内は行が無いと出ないので、**常設の正本はこちら**。
|
|
4826
|
+
// 「案内側に導線があるから手順側は省く」とやると即再発する。
|
|
4827
|
+
hint: [
|
|
4828
|
+
{ text: "読み取りたいリポジトリがある組織に、Cortex の GitHub App を入れます(Issues の読み取りだけ)。", node: appInstallLink() },
|
|
4829
|
+
"そのリポジトリを下の欄に入れて「追加」を押します(owner/repo でも、GitHub のURLでも構いません)。",
|
|
4830
|
+
"追加したリポジトリの Issues が、毎晩の Gold 昇格の材料になります。やめるときは、その行の「登録から削除」を押します。",
|
|
4831
|
+
],
|
|
4219
4832
|
build: function (repo, name) { return { op: "add-github-source", repo: repo, name: name }; },
|
|
4220
4833
|
adder: "github",
|
|
4221
4834
|
}));
|
|
@@ -4458,39 +5071,30 @@ ${capabilityState.toString()}
|
|
|
4458
5071
|
}
|
|
4459
5072
|
|
|
4460
5073
|
/**
|
|
4461
|
-
* ON/OFF
|
|
4462
|
-
*
|
|
5074
|
+
* ⚠ **ON/OFF のトグル(stateToggle)は関数ごと撤去した(2026-08-21・オーナー判断)。**
|
|
5075
|
+
*
|
|
5076
|
+
* 唯一の利用者が GitHub の「読み取りを止める/始める」だった。オーナー指摘:
|
|
5077
|
+
* 「登録から削除っていうボタンがあるのに、これがある理由がわかんないです」。
|
|
5078
|
+
*
|
|
5079
|
+
* 作った理由は「**自動で見つかったリポジトリ(derived)は登録簿から消しても
|
|
5080
|
+
* 翌日また現れるので、止めることだけはできるようにする**」だったが、
|
|
5081
|
+
* #119 以降に生成されたデータの github は必ず explicit で、全9案件36リポジトリの
|
|
5082
|
+
* 実測でも derived は0件・excluded も0件だった。
|
|
5083
|
+
*
|
|
5084
|
+
* **残さずに消す。** 呼び出しが1つも無い関数を残すと、壊しても何も起きない
|
|
5085
|
+
* =変異検証の網から静かに漏れる(このリポジトリが繰り返し踏んでいる形)。
|
|
5086
|
+
* 同じ理由で「ds-toggle-btn is-on」(押した向きを示すクラス)の生成元も無くなった。
|
|
5087
|
+
*
|
|
5088
|
+
* ⚠ **confirmOn(広げる向きだけ確認する)の利用者もこれだけだった。**
|
|
5089
|
+
* 「広げる向きの確認を await し損ねていないか」を見ていた検査は**引き継げない**
|
|
5090
|
+
* ——removeButton は向きに関わらず必ず確認するので、同じ性質を持たない。
|
|
5091
|
+
*
|
|
5092
|
+
* ⚠ **サーバ側の受け口(op=set-github-source-enabled)は残してある。**
|
|
5093
|
+
* 理由は logic.mjs の RETIRED_CONFIG_OPS のコメントに書いた。
|
|
4463
5094
|
*/
|
|
4464
|
-
function stateToggle(opts) {
|
|
4465
|
-
var wrap = el("div", { class: "ds-toggle" });
|
|
4466
|
-
var on = opts.on === true;
|
|
4467
|
-
var btn = el("button", { class: "ds-toggle-btn" + (on ? " is-on" : ""), type: "button" });
|
|
4468
|
-
var msg = el("div", { class: "ds-toggle-msg" });
|
|
4469
|
-
var paint = function () {
|
|
4470
|
-
btn.textContent = on ? opts.labelOn : opts.labelOff;
|
|
4471
|
-
btn.className = "ds-toggle-btn" + (on ? " is-on" : "");
|
|
4472
|
-
};
|
|
4473
|
-
paint();
|
|
4474
|
-
|
|
4475
|
-
btn.addEventListener("click", async function () {
|
|
4476
|
-
var next = !on;
|
|
4477
|
-
// 読み始める方向(危険)だけ確認する。止める方向は素通し
|
|
4478
|
-
if (next && opts.confirmOn && !(await confirmDanger(opts.confirmOn, { returnTo: btn }))) { msg.textContent = ""; return; }
|
|
4479
|
-
sendConfig(opts.build(next), msg, btn, function () {
|
|
4480
|
-
// **押した内容をボタンに反映し、逆向きの操作を残す。**
|
|
4481
|
-
// **カードごと作り直さない。** 上の msg に出した結果表示が消えてしまう
|
|
4482
|
-
on = next;
|
|
4483
|
-
paint();
|
|
4484
|
-
});
|
|
4485
|
-
});
|
|
4486
|
-
wrap.appendChild(btn);
|
|
4487
|
-
wrap.appendChild(msg);
|
|
4488
|
-
return wrap;
|
|
4489
|
-
}
|
|
4490
5095
|
|
|
4491
5096
|
/**
|
|
4492
|
-
*
|
|
4493
|
-
* 向きに関わらず取り消せないので常に確認する)。
|
|
5097
|
+
* 削除ボタン。**必ず確認を出す**(取り消せないので、向きに関わらず確認する)。
|
|
4494
5098
|
*
|
|
4495
5099
|
* 成功しても一覧からは消さない。接続状況は夜間バッチのスナップショットで、消したつもりの行が
|
|
4496
5100
|
* 翌朝まで残るのが正しい状態のため——行に取り消し線を引き、ボタンだけを無効にする
|
|
@@ -4699,15 +5303,30 @@ ${capabilityState.toString()}
|
|
|
4699
5303
|
var ORIGIN_LABEL = { explicit: "明示登録", derived: "自動検出", both: "明示登録+自動検出" };
|
|
4700
5304
|
var ORIGIN_HELP = {
|
|
4701
5305
|
explicit: "開発の登録ファイル(dev-sources.json)に登録されているリポジトリです。ここから登録を削除できます。",
|
|
4702
|
-
|
|
5306
|
+
// **「読み取りを止めることはできます」は書かない(2026-08-21)。** そのボタンを
|
|
5307
|
+
// 撤去したので嘘になる。この行は画面からは変えられない(dev-sources.json の
|
|
5308
|
+
// exclude を直接編集する)——そう書いておかないと、無い操作を探させることになる
|
|
5309
|
+
derived: ".gitmodules から自動で見つかったリポジトリです。登録ファイルに無いので、この画面からは変更できません。",
|
|
4703
5310
|
both: "登録ファイルにも書かれていて、.gitmodules からも見つかっているリポジトリです。",
|
|
4704
5311
|
};
|
|
4705
5312
|
|
|
4706
5313
|
function extSourceCard(s, meta) {
|
|
4707
5314
|
var badges = el("div", { class: "ds-badges" });
|
|
4708
5315
|
// **Gold 対象かのバッジは持たない。** 一覧に並ぶ Slack チャンネルは例外なく全て対象で、
|
|
4709
|
-
// 行ごとに「対象です」と書いても情報が増えない。
|
|
4710
|
-
//
|
|
5316
|
+
// 行ごとに「対象です」と書いても情報が増えない。
|
|
5317
|
+
//
|
|
5318
|
+
// 🔴 **github の除外(goldState: "excluded")だけは印を出す(2026-08-21)。**
|
|
5319
|
+
// それまでは行のトグル(「読み取りを始める/止める」)が**向きで示していた**ので、
|
|
5320
|
+
// トグルを撤去すると**読み取られていないのに印が1つも無い行**になる。
|
|
5321
|
+
// sourceNeedsAttention も excluded を警告から外すので、他に気づく手掛かりが無い。
|
|
5322
|
+
// 実測では0件だが、exclude は dev-sources.json に手で書けるので「今日は0件」でしかない
|
|
5323
|
+
if (String(s.type).indexOf("github") === 0 && s.goldState === "excluded") {
|
|
5324
|
+
badges.appendChild(el("span", {
|
|
5325
|
+
class: "badge ds-excluded",
|
|
5326
|
+
text: "読み取り停止中",
|
|
5327
|
+
title: "このリポジトリは読み取り対象から除外されています(開発の登録ファイル dev-sources.json の exclude)。この画面からは戻せません。",
|
|
5328
|
+
}));
|
|
5329
|
+
}
|
|
4711
5330
|
if (s.notify === true) badges.appendChild(el("span", { class: "badge ds-notify", text: "通知先" }));
|
|
4712
5331
|
// **どのワークスペースのチャンネルかを、必ず行に出す(#104・2026-08-20 に社内も)。**
|
|
4713
5332
|
//
|
|
@@ -4747,6 +5366,30 @@ ${capabilityState.toString()}
|
|
|
4747
5366
|
// ようになった(explicit には出さない)が、Slack で explicit なのは登録ファイルに
|
|
4748
5367
|
// 直接書いた例外的な行だけで、バッジのために文面をもう一組増やすには釣り合わない。
|
|
4749
5368
|
// #119 以降、新しいデータの github は必ず explicit(詳細は ORIGIN_LABEL)
|
|
5369
|
+
// **どの組織のリポジトリかを行に出す(2026-08-20)。**
|
|
5370
|
+
// 組織ごとの独立した一覧をやめたので、**組織を言うのは行のラベルだけ**になった。
|
|
5371
|
+
// トークンは組織ごとにしか効かないので、これが判断の単位になる
|
|
5372
|
+
if (String(s.type).indexOf("github") === 0 && s.ref) {
|
|
5373
|
+
var ghOwner = String(s.ref).split("/")[0];
|
|
5374
|
+
if (ghOwner) {
|
|
5375
|
+
// **何で読んでいるかを添える。** 台帳に無ければ何も言わない。
|
|
5376
|
+
//
|
|
5377
|
+
// **添えるのは App のときだけ(2026-08-21・読み取りトークンの廃止で判断し直した)。**
|
|
5378
|
+
// かつては「App/個人トークン」で直し方が違ったが、個人トークンは廃止した。
|
|
5379
|
+
// いま App が付かない行は 「workflow」(ワークフロー自身のトークンで読めた=
|
|
5380
|
+
// だいたい公開リポジトリ)で、**読めている以上その人に直す作業は無い**。
|
|
5381
|
+
// ここに「(ワークフローのトークン)」のような札を足すと、直しようのない
|
|
5382
|
+
// 内部事情を全行に並べることになる——押す必要が無いものを説明する側の混雑。
|
|
5383
|
+
// 一方 App の札は「この組織はもう繋いである」という**運用上の意味**を持つので残す。
|
|
5384
|
+
var ghMeta = githubOwnerMeta(ghOwner);
|
|
5385
|
+
var via = ghMeta && ghMeta.source === "app" ? "(GitHub App)" : "";
|
|
5386
|
+
badges.appendChild(el("span", {
|
|
5387
|
+
class: "badge ds-workspace" + (ghMeta && ghMeta.source === "unknown" ? " ds-workspace-unknown" : ""),
|
|
5388
|
+
text: ghOwner + via,
|
|
5389
|
+
title: "トークンは組織ごとにしか効きません(Fine-grained PAT も GitHub App のインストールトークンも1組織分)。",
|
|
5390
|
+
}));
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
4750
5393
|
if (String(s.type).indexOf("github") === 0 && ORIGIN_LABEL[s.origin]) {
|
|
4751
5394
|
badges.appendChild(el("span", {
|
|
4752
5395
|
class: "badge ds-origin",
|
|
@@ -4779,28 +5422,16 @@ ${capabilityState.toString()}
|
|
|
4779
5422
|
if (SITE.intake && s.type === "slack" && s.ref && s.origin !== "explicit") {
|
|
4780
5423
|
card.appendChild(removeChannelButton(s, card));
|
|
4781
5424
|
}
|
|
4782
|
-
// GitHub
|
|
5425
|
+
// GitHubリポの登録から削除。**ON/OFF のトグルは撤去した(2026-08-21)**
|
|
5426
|
+
//(stateToggle のコメント参照)。
|
|
4783
5427
|
if (SITE.intake && s.type.indexOf("github") === 0 && s.ref) {
|
|
4784
|
-
card.appendChild(stateToggle({
|
|
4785
|
-
on: s.goldState !== "excluded",
|
|
4786
|
-
labelOn: "読み取りを止める",
|
|
4787
|
-
labelOff: "読み取りを始める",
|
|
4788
|
-
confirmOn: [
|
|
4789
|
-
"このリポジトリの Issues を、Gold 昇格の材料に戻します。",
|
|
4790
|
-
"",
|
|
4791
|
-
"Issues の内容から、Decision・用語集が作られます。",
|
|
4792
|
-
"",
|
|
4793
|
-
s.ref,
|
|
4794
|
-
"",
|
|
4795
|
-
"有効にしますか?",
|
|
4796
|
-
],
|
|
4797
|
-
build: function (next) {
|
|
4798
|
-
return { op: "set-github-source-enabled", repo: s.ref, value: next };
|
|
4799
|
-
},
|
|
4800
|
-
}));
|
|
4801
5428
|
// **削除は「手で登録したもの」にだけ出す。** 自動で見つかったリポは
|
|
4802
5429
|
// 登録ファイルから消しても翌日また現れる(=消えないのに消せたように見える)。
|
|
4803
|
-
//
|
|
5430
|
+
//
|
|
5431
|
+
// ⚠ **トグルを撤去したので、derived / both / 由来不明の行には操作が1つも無くなる**
|
|
5432
|
+
//(分類B・2026-08-21 に記録)。実測で derived は0件だが、.gitmodules からの
|
|
5433
|
+
// 導出経路が消えたわけではない。再び現れたら、その行は**画面からは止められない**
|
|
5434
|
+
// ——dev-sources.json の exclude を直接編集する。
|
|
4804
5435
|
//
|
|
4805
5436
|
// **#119 以降、新しいデータの github は必ず explicit** なので、この条件は
|
|
4806
5437
|
// いずれ常に真になる。それまでは残す——再生成前のスナップショットには derived が
|
|
@@ -4812,7 +5443,10 @@ ${capabilityState.toString()}
|
|
|
4812
5443
|
return [
|
|
4813
5444
|
"「" + s.ref + "」を、読み取り対象の登録から削除します。",
|
|
4814
5445
|
"",
|
|
4815
|
-
|
|
5446
|
+
// **「読み取りを止める」への案内は消した(2026-08-21)。** そのボタンごと
|
|
5447
|
+
// 撤去したので、指す先が画面に無い。**代わりの手段は書かない**
|
|
5448
|
+
//——削除がその手段そのもので、他に無い
|
|
5449
|
+
"次回の Gold 昇格から、このリポジトリの Issues は読み取られません。",
|
|
4816
5450
|
"",
|
|
4817
5451
|
"すでに作られた Decision・用語集は消えません。",
|
|
4818
5452
|
"",
|
|
@@ -5118,7 +5752,12 @@ ${capabilityState.toString()}
|
|
|
5118
5752
|
return el("div", { class: "ops-card rt-card is-live" }, [
|
|
5119
5753
|
el("div", { class: "ops-card-head" }, [
|
|
5120
5754
|
el("span", { class: "ops-card-icon", text: "⚡" }),
|
|
5121
|
-
|
|
5755
|
+
// **「(任意)」を付ける(2026-08-21・オーナー指摘「リアルタイム同期は
|
|
5756
|
+
// オプションなので、一番下に配置してほしい」)。** 設定しなくても毎晩の同期で
|
|
5757
|
+
// 反映されるので、必須の手順と並べると「まだ終わっていない」と読まれる。
|
|
5758
|
+
// ⚠ **改名箇所は2つある**(稼働中の枝と未設定の枝)。片方だけ直すと、
|
|
5759
|
+
// **これから設定する人にだけ「(任意)」が付かない**=一番読ませたい人に届かない
|
|
5760
|
+
el("h3", { class: "ops-card-title", text: "リアルタイム同期(任意)" }),
|
|
5122
5761
|
el("span", { class: "rt-live-badge", text: "✓ 稼働中" }),
|
|
5123
5762
|
]),
|
|
5124
5763
|
lines,
|
|
@@ -5130,18 +5769,33 @@ ${capabilityState.toString()}
|
|
|
5130
5769
|
return el("div", { class: "ops-card rt-card" }, [
|
|
5131
5770
|
el("div", { class: "ops-card-head" }, [
|
|
5132
5771
|
el("span", { class: "ops-card-icon", text: "⚡" }),
|
|
5133
|
-
|
|
5772
|
+
// **稼働中の枝と同じ見出しにする**(上の ⚠ 参照。片方だけ直すと、
|
|
5773
|
+
// これから設定する人にだけ「(任意)」が付かない)
|
|
5774
|
+
el("h3", { class: "ops-card-title", text: "リアルタイム同期(任意)" }),
|
|
5134
5775
|
]),
|
|
5135
5776
|
el("p", { class: "ops-card-desc", text: "Backlog で課題やコメントが変わったときに、その内容をすぐ取り込みます(毎晩の同期を待たずに反映されます)。Backlog 側で一度だけ設定してください。" }),
|
|
5136
5777
|
].concat(steps));
|
|
5137
5778
|
}
|
|
5138
5779
|
|
|
5139
|
-
/**
|
|
5780
|
+
/**
|
|
5781
|
+
* 鍵の入力欄に出す説明。kind は Lambda 側(resolveSecretTarget)と綴りを合わせること。
|
|
5782
|
+
*
|
|
5783
|
+
* **発行の手順(how / note / selfServe.note)は <details> に畳む**
|
|
5784
|
+
*(2026-08-21・オーナー指摘「カードが長すぎる」)。**文言は消していない**——
|
|
5785
|
+
* 畳んだ中に全部残っており、summary を開けば読める。
|
|
5786
|
+
* 畳まないのは .sec-state / .sec-preferred / .sec-input(secretCard 側の 🔴 コメント参照)。
|
|
5787
|
+
*
|
|
5788
|
+
* **「畳まない種別」の枝は置いていない。** 当初は fold: true の opt-in にしていたが、
|
|
5789
|
+
* 2026-08-21 に external-sources(GitHub の読み取りトークン)が廃止され、
|
|
5790
|
+
* **残る2種別が両方とも畳む=その枝が到達不能になった**。
|
|
5791
|
+
* 到達不能な枝は**壊しても何も起きない**ので、変異検証の網から静かに漏れる
|
|
5792
|
+
* ——このリポジトリが繰り返し踏んでいる形なので、枝ごと落とした。
|
|
5793
|
+
* **畳んではいけない種別を足すときに、テストと一緒に枝を戻すこと。**
|
|
5794
|
+
*/
|
|
5140
5795
|
var SECRET_FORMS = {
|
|
5141
5796
|
"figma": {
|
|
5142
5797
|
icon: "🎨",
|
|
5143
5798
|
title: "Figma のトークン",
|
|
5144
|
-
desc: "デザインの画面インベントリと、Figma に付いたコメント(指摘)を毎晩同期するために使います。",
|
|
5145
5799
|
// **必要なスコープは実装が叩くAPIから決まる。** sync-designs は
|
|
5146
5800
|
// GET /v1/files/{key} → file_content:read(画面インベントリ)
|
|
5147
5801
|
// GET /v1/files/{key}/comments → file_comments:read(指摘の同期)
|
|
@@ -5158,7 +5812,6 @@ ${capabilityState.toString()}
|
|
|
5158
5812
|
"backlog": {
|
|
5159
5813
|
icon: "📋",
|
|
5160
5814
|
title: "Backlog のAPIキー",
|
|
5161
|
-
desc: "課題・Wiki・ドキュメントを毎晩同期するために使います。",
|
|
5162
5815
|
how: "Backlog → 個人設定 → API で発行(この案件のプロジェクトが見えるアカウントで)",
|
|
5163
5816
|
// **案件の担当者が自分で繋ぐ。** 以前は艦隊共通の読み取りアカウントを1つ運用していたが、
|
|
5164
5817
|
// 案件が増えるたびに「その1人がプロジェクトへ参加追加してキーを配る」ことになり、
|
|
@@ -5175,21 +5828,6 @@ ${capabilityState.toString()}
|
|
|
5175
5828
|
"(前の担当者のアカウントが無効になると同期が止まります)。",
|
|
5176
5829
|
},
|
|
5177
5830
|
},
|
|
5178
|
-
"external-sources": {
|
|
5179
|
-
icon: "🐙",
|
|
5180
|
-
title: "GitHub の読み取りトークン",
|
|
5181
|
-
desc: "開発リポジトリの Issues / Discussions を読み、Gold の原料にするために使います。",
|
|
5182
|
-
// **第一の案内は GitHub App(#138)。** 実装の本線は App のインストールトークンで、
|
|
5183
|
-
// 個人トークンは App を入れられない組織のフォールバックでしかない(既存案件は
|
|
5184
|
-
// すでに App で読めている)。画面が個人トークンを勧め続けると、発行と入れ直しが
|
|
5185
|
-
// 要る側に人が流れ続け、**入れ直しの要らない仕組みへ移れない**。
|
|
5186
|
-
// 順序を入れ替えるだけで、どちらも残す——App を入れられない組織は実在する。
|
|
5187
|
-
appFirst: {
|
|
5188
|
-
text: "まず、読み取りたいリポジトリのある組織に Cortex の GitHub App を入れてください。トークンの発行も、期限が来たときの入れ直しも要りません。",
|
|
5189
|
-
linkText: "組織に GitHub App をインストール →",
|
|
5190
|
-
},
|
|
5191
|
-
how: "App を入れられない組織では、代わりにトークンを使います。GitHub → Settings → Developer settings → Personal access tokens で、対象リポジトリに Contents / Issues の Read-only を付けて発行",
|
|
5192
|
-
},
|
|
5193
5831
|
};
|
|
5194
5832
|
|
|
5195
5833
|
/**
|
|
@@ -5202,27 +5840,82 @@ ${capabilityState.toString()}
|
|
|
5202
5840
|
* カードは #101 で能力モーダルの中へ移した(buildDataSources の pushCap 経由)。
|
|
5203
5841
|
* まとめて並べる renderSecrets() は呼び出し元が無くなったので消してある。
|
|
5204
5842
|
*/
|
|
5205
|
-
function secretPayload(intake, kind, value) {
|
|
5843
|
+
function secretPayload(intake, kind, value, cardSpace) {
|
|
5206
5844
|
var body = { projectKey: intake.projectKey, kind: kind, value: value };
|
|
5207
5845
|
if (kind === "backlog") {
|
|
5208
|
-
|
|
5846
|
+
// **カードが担当するスペースを最優先する(2026-08-20)。**
|
|
5847
|
+
// 複数スペースのときは欄がスペースごとに分かれているので、
|
|
5848
|
+
// どの棚へ入れるかは**そのカードが知っている**。
|
|
5849
|
+
// 1枚だけのときは従来どおり(1つに定まるなら名乗る・定まらなければ名簿に倒す)
|
|
5850
|
+
var space = cardSpace || backlogSecretSpace();
|
|
5209
5851
|
if (space) body.space = space;
|
|
5210
5852
|
}
|
|
5211
5853
|
return body;
|
|
5212
5854
|
}
|
|
5213
5855
|
|
|
5214
|
-
|
|
5215
|
-
|
|
5856
|
+
/**
|
|
5857
|
+
* 鍵が登録されているかを、そのカードが担当する範囲で答える(2026-08-21)。
|
|
5858
|
+
*
|
|
5859
|
+
* 返す値は "yes" / "no" / "unknown" の**3つ**。
|
|
5860
|
+
*
|
|
5861
|
+
* 🔴 **"unknown" を潰さないこと。** スペースごとの登録状況(secretSpaces)を出すのは
|
|
5862
|
+
* engine 側で、配布は**画面が先・engine が後**——secretSpaces を知らない生成物を
|
|
5863
|
+
* 画面が読む期間が必ずある。そこで「未登録」に倒すと、
|
|
5864
|
+
* **入っている鍵を「入っていない」と断定して、要らない貼り直しをさせる。**
|
|
5865
|
+
*
|
|
5866
|
+
* @returns { known, src } src は取得元の文字列("yes" のときだけ意味を持つ)
|
|
5867
|
+
*/
|
|
5868
|
+
function secretStateOf(kind, stateSpace, spaceCount) {
|
|
5869
|
+
var perKind = (fleetVal("secretSources") || {})[kind] || "";
|
|
5870
|
+
var spaces = fleetVal("secretSpaces");
|
|
5871
|
+
if (kind === "backlog" && stateSpace && spaces && typeof spaces === "object") {
|
|
5872
|
+
var v = spaces[stateSpace];
|
|
5873
|
+
if (v === "new") return { known: "yes", src: "Secrets Manager" };
|
|
5874
|
+
if (v === "legacy") return { known: "yes", src: "Secrets Manager(旧名)" };
|
|
5875
|
+
if (v === "false") return { known: "no", src: "" };
|
|
5876
|
+
}
|
|
5877
|
+
// **スペースが1つに定まるなら、種別ごとの値で答えてよい。** 取り違えようがないので、
|
|
5878
|
+
// engine が secretSpaces を出す前から今までどおりの表示を保てる
|
|
5879
|
+
if ((spaceCount || 0) <= 1) return { known: perKind ? "yes" : "no", src: perKind };
|
|
5880
|
+
// 複数スペースなのに、スペース別の答えが無い。**片方だけ入れた状態を表せない**ので
|
|
5881
|
+
// 断定しない(「登録済み」も「未登録」も、どちらかのスペースで嘘になる)
|
|
5882
|
+
return { known: "unknown", src: "" };
|
|
5883
|
+
}
|
|
5884
|
+
|
|
5885
|
+
/**
|
|
5886
|
+
* @param opts { space, stateSpace, spaceCount, inRow }
|
|
5887
|
+
* space … 保存時に名乗る Backlog スペース(名乗らないときは空)
|
|
5888
|
+
* stateSpace … 状態を引くスペース(画面の行のドメイン)
|
|
5889
|
+
* spaceCount … 画面に出ているスペースの数(1つなら種別ごとの値で答えられる)
|
|
5890
|
+
* inRow … レコードの行の中に置く(枠と影を持たない見た目にする)
|
|
5891
|
+
*/
|
|
5892
|
+
function secretCard(kind, meta, opts) {
|
|
5893
|
+
var cardSpace = (opts && opts.space) || "";
|
|
5894
|
+
var stateSpace = (opts && opts.stateSpace) || "";
|
|
5895
|
+
var spaceCount = (opts && opts.spaceCount) || 0;
|
|
5896
|
+
var inRow = !!(opts && opts.inRow);
|
|
5897
|
+
// **いま登録されているか**を先に出す。入れ直したのに反映されていない状態が
|
|
5216
5898
|
// 画面で分かるようにする(接続状況は夜間バッチのスナップショットなので、
|
|
5217
5899
|
// 保存の直後は前日の値のまま。時刻は上の節に出している)。
|
|
5218
|
-
var
|
|
5900
|
+
var st = secretStateOf(kind, stateSpace, spaceCount);
|
|
5901
|
+
var src = st.known === "yes" ? st.src : "";
|
|
5902
|
+
var cardTitle = meta.title;
|
|
5903
|
+
// 🔴 **「登録済み」は「読めている」を意味しない。** 鍵が入っていても、そのアカウントから
|
|
5904
|
+
// プロジェクトが見えなければ同期は失敗する。**「接続OK」「同期OK」とは書かないこと**
|
|
5905
|
+
//(同期できているかのバッジは、夜間処理が接続先ごとの成否を保存してからの別作業)。
|
|
5906
|
+
//
|
|
5219
5907
|
// **前方一致で見る。** #105 の移行期は「Secrets Manager(旧名)」も来る。
|
|
5220
5908
|
// 完全一致にすると、旧名で動いている案件だけが repo secret と同じ見た目になり、
|
|
5221
5909
|
// 「管理下にあるのに未移行」という一番知りたい状態が画面から消える
|
|
5222
|
-
var state =
|
|
5910
|
+
var state = st.known === "yes"
|
|
5223
5911
|
? el("p", { class: "sec-state" + (src.indexOf("Secrets Manager") === 0 ? " is-managed" : ""),
|
|
5224
|
-
text: "
|
|
5225
|
-
:
|
|
5912
|
+
text: "登録済み(" + src + " から取得中)" })
|
|
5913
|
+
: st.known === "no"
|
|
5914
|
+
? el("p", { class: "sec-state is-none", text: "未登録" })
|
|
5915
|
+
// **断定しない(レビュー指摘)。** 黙って消すと、利用者は
|
|
5916
|
+
// 「入っているのか未登録なのか」も「なぜ表示が無いのか」も知る手段が無い
|
|
5917
|
+
: el("p", { class: "sec-state is-unknown",
|
|
5918
|
+
text: "登録状況を確認中です(スペースごとの状況は、次回の自動チェックのあとに表示されます)" });
|
|
5226
5919
|
|
|
5227
5920
|
var input = el("input", { class: "sec-input", type: "password", placeholder: "トークンを貼り付け", autocomplete: "off" });
|
|
5228
5921
|
var btn = el("button", { class: "ds-toggle-btn", type: "button", text: "保存" });
|
|
@@ -5246,7 +5939,7 @@ ${capabilityState.toString()}
|
|
|
5246
5939
|
// こちらが渡すのは「どのスペースの鍵か」という材料だけ。
|
|
5247
5940
|
// **押した時点で読む。** 組み立て時に固めると、接続先を登録した直後に
|
|
5248
5941
|
// 貼った鍵が「スペースを特定できません」で断られる
|
|
5249
|
-
body: JSON.stringify(secretPayload(intake, kind, value)),
|
|
5942
|
+
body: JSON.stringify(secretPayload(intake, kind, value, cardSpace)),
|
|
5250
5943
|
});
|
|
5251
5944
|
var j = await res.json().catch(function () { return {}; });
|
|
5252
5945
|
if (!res.ok) {
|
|
@@ -5272,38 +5965,65 @@ ${capabilityState.toString()}
|
|
|
5272
5965
|
}
|
|
5273
5966
|
});
|
|
5274
5967
|
|
|
5275
|
-
//
|
|
5276
|
-
|
|
5277
|
-
el("div", { class: "ops-card-head" }, [
|
|
5278
|
-
el("span", { class: "ops-card-icon", text: meta.icon }),
|
|
5279
|
-
el("h3", { class: "ops-card-title", text: meta.title }),
|
|
5280
|
-
]),
|
|
5281
|
-
el("p", { class: "ops-card-desc", text: meta.desc }),
|
|
5282
|
-
state,
|
|
5283
|
-
// **未設定のときだけ、先に試すべき手を出す。** 既に動いているカードに
|
|
5284
|
-
// 「まずこれをやれ」と出すと、直す必要が無いものを触らせることになる
|
|
5285
|
-
!src && meta.selfServe ? el("p", { class: "sec-preferred", text: meta.selfServe.text }) : null,
|
|
5286
|
-
// **本線(App)はトークンの手順より先に、いつでも出す(#138)。**
|
|
5287
|
-
// トークンで動いている案件こそ App へ移してほしいので、selfServe と違って
|
|
5288
|
-
// 「未設定のときだけ」にはしない
|
|
5289
|
-
meta.appFirst
|
|
5290
|
-
? el("p", { class: "sec-preferred" }, [
|
|
5291
|
-
document.createTextNode(meta.appFirst.text + " "),
|
|
5292
|
-
el("a", { href: GITHUB_APP_INSTALL_URL, target: "_blank", rel: "noopener", text: meta.appFirst.linkText }),
|
|
5293
|
-
])
|
|
5294
|
-
: null,
|
|
5968
|
+
// 発行の手順ひとそろい。**<details> に畳む**(文言は消さない。畳んだ中に全部残る)
|
|
5969
|
+
var guidance = [
|
|
5295
5970
|
el("p", { class: "sec-how", text: meta.how }),
|
|
5296
5971
|
// **鍵の作り方に付随する注意(招待漏れ等)。** 発行手順(how)とは別に出す——
|
|
5297
5972
|
// 「トークンは正しいのに読めない」は権限の問題に見えないので、切り分けに時間がかかる。
|
|
5298
5973
|
meta.note ? el("p", { class: "sec-how", text: meta.note }) : null,
|
|
5299
5974
|
meta.selfServe ? el("p", { class: "sec-how", text: meta.selfServe.note }) : null,
|
|
5300
|
-
|
|
5975
|
+
].filter(Boolean);
|
|
5976
|
+
// **「畳んである中に何があるか」を summary に書く。** ただの「詳細」だと、
|
|
5977
|
+
// 発行のしかたを探している人がここを開く手掛かりを持てない(rt カードと同じ流儀)
|
|
5978
|
+
var guidanceBox = el("details", { class: "sec-fold" }, [el("summary", { text: "発行のしかた" })]);
|
|
5979
|
+
for (var gi = 0; gi < guidance.length; gi++) guidanceBox.appendChild(guidance[gi]);
|
|
5980
|
+
|
|
5981
|
+
// **押すまで入力欄を出さない(2026-08-21・オーナー指摘)。**
|
|
5982
|
+
// 「今のAPIキーのセクション、欄があると思うんだけど…押すとフォームだけ出てくる」。
|
|
5983
|
+
//
|
|
5984
|
+
// 🔴 **前回とは向きが逆。** 前回は「.sec-input は畳まない」と決めていたが、
|
|
5985
|
+
// 鍵の欄がレコードの行の下へ移り、**行に常時ぶら下がる入力欄**になったため、
|
|
5986
|
+
// 一覧の見通しを取り戻す側へ倒した。**状態(.sec-state)は畳まない**ので、
|
|
5987
|
+
// 「保存したのに反映されていない」は開かなくても読める。
|
|
5988
|
+
//
|
|
5989
|
+
// ⚠ **DOM には常に置く**(押すまで生成しない作りにしない)。ライブ差し替えは
|
|
5990
|
+
// input のノードを直接触るし、テストも card.querySelector("input.sec-input") で掴む。
|
|
5991
|
+
// ⚠ **<summary> は button ではない**ので、「保存」を掴む既存の取り方は変わらない。
|
|
5992
|
+
var inputFold = el("details", { class: "sec-input-fold" }, [
|
|
5993
|
+
el("summary", { class: "sec-input-summary", text: st.known === "yes" ? "入れ直す" : "登録する" }),
|
|
5994
|
+
]);
|
|
5995
|
+
inputFold.appendChild(input);
|
|
5996
|
+
inputFold.appendChild(el("div", { class: "ds-toggle" }, [btn, msg]));
|
|
5997
|
+
|
|
5998
|
+
// ライブ取得後に状態の行だけを差し替えるための目印(カードごと作り直すと入力が消える)
|
|
5999
|
+
//
|
|
6000
|
+
// **並びは「状態 → 貼る(畳む) → 畳んだ手順」。**
|
|
6001
|
+
//
|
|
6002
|
+
// 🔴 **.sec-state / .sec-preferred は <details> の外に置くこと。**
|
|
6003
|
+
// - .sec-state … 保存したのに反映されていない状態が分かる唯一の手段。
|
|
6004
|
+
// 押すまで見えないと成立しない
|
|
6005
|
+
// - .sec-preferred … 「誰のアカウントで発行するのか」を**手順より先に**伝える行。
|
|
6006
|
+
// 未登録のときだけ出る=これから貼る人にだけ出るので、畳むと存在理由が消える
|
|
6007
|
+
return el("div", { class: "ops-card" + (inRow ? " ds-keycard" : ""), "data-secret-kind": kind }, [
|
|
6008
|
+
el("div", { class: "ops-card-head" }, [
|
|
6009
|
+
el("span", { class: "ops-card-icon", text: meta.icon }),
|
|
6010
|
+
el("h3", { class: "ops-card-title", text: cardTitle }),
|
|
6011
|
+
]),
|
|
6012
|
+
// **desc は無い種別がある(2026-08-21)。** el() は text をそのまま textContent へ
|
|
6013
|
+
// 代入するので、無条件に出すと画面に文字列 undefined が出る
|
|
6014
|
+
meta.desc ? el("p", { class: "ops-card-desc", text: meta.desc }) : null,
|
|
6015
|
+
state,
|
|
6016
|
+
// **未登録のときだけ、先に試すべき手を出す。** 既に動いているカードに
|
|
6017
|
+
// 「まずこれをやれ」と出すと、直す必要が無いものを触らせることになる。
|
|
6018
|
+
// **「確認中」にも出さない**——入っているかもしれないものを触らせない
|
|
6019
|
+
st.known === "no" && meta.selfServe ? el("p", { class: "sec-preferred", text: meta.selfServe.text }) : null,
|
|
6020
|
+
inputFold,
|
|
6021
|
+
guidanceBox,
|
|
5301
6022
|
// **扱いの説明はカードに持たせる。** 節の見出しの下に置いていたときは、
|
|
5302
6023
|
// #101 でカードだけがモーダルへ移り、説明だけが画面から消えた。
|
|
5303
6024
|
// 顧客にトークンの貼り付けを求める画面で、貼った値がどう扱われるかの
|
|
5304
6025
|
// 説明が落ちるのは、いちばん落としてはいけない種類の欠落
|
|
5305
6026
|
el("p", { class: "sec-note", text: "入れた値はここには表示されません(保存だけできます)。保存先は案件ごとに分かれているので、他の案件には影響しません。" }),
|
|
5306
|
-
el("div", { class: "ds-toggle" }, [btn, msg]),
|
|
5307
6027
|
]);
|
|
5308
6028
|
}
|
|
5309
6029
|
|
|
@@ -5446,10 +6166,10 @@ ${capabilityState.toString()}
|
|
|
5446
6166
|
* モーダルを app に載せて、中へフォーカスを移す。
|
|
5447
6167
|
*
|
|
5448
6168
|
* **「最初の focusable」に載せてはいけない。** 一覧の先頭に来るのは
|
|
5449
|
-
*
|
|
5450
|
-
*
|
|
5451
|
-
*
|
|
5452
|
-
*
|
|
6169
|
+
* 「登録を解除」「このファイルを外す」といった設定を書き換えるボタンで、
|
|
6170
|
+
* タイルを Enter で開いてもう一度 Enter を押しただけで、そこへ手が届く。
|
|
6171
|
+
* いま並んでいるものは確認を必ず出すが、**確認を出さない操作が1つ増えるだけで
|
|
6172
|
+
* この形は復活する**ので、載せ先の側で塞いでおく。
|
|
5453
6173
|
* 移す先は閉じるボタン——押しても何も壊れないものにする。
|
|
5454
6174
|
*/
|
|
5455
6175
|
/**
|