@takagaki/cortex-decisions-viewer 0.12.214 → 0.12.217
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/render.js +221 -265
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -2336,8 +2336,8 @@ const SECRET_NOW_STATES = ["registered", "missing", "unknown"];
|
|
|
2336
2336
|
/**
|
|
2337
2337
|
* `secretsNow`(鍵が登録されているか・列2)の許可リスト。
|
|
2338
2338
|
*
|
|
2339
|
-
* 応答の1行は `{ adapter, kind, state, source, space? }`。画面が使うのは kind / state /
|
|
2340
|
-
* space だけで、**adapter は使わない**(鍵カードは種別で引く)。source は「どの棚が
|
|
2339
|
+
* 応答の1行は `{ adapter, kind, state, source, space?, savedAt? }`。画面が使うのは kind / state /
|
|
2340
|
+
* space / savedAt だけで、**adapter は使わない**(鍵カードは種別で引く)。source は「どの棚が
|
|
2341
2341
|
* 答えたか」の内部語なので、画面に出す語へ畳むのは読み出し側(`secretStateFromNow`)。
|
|
2342
2342
|
*/
|
|
2343
2343
|
function sanitizeSecretsNow(v) {
|
|
@@ -2359,6 +2359,9 @@ function sanitizeSecretsNow(v) {
|
|
|
2359
2359
|
// 揃えないと**入っている鍵を「未登録」と言う**(`issuesRefOf` と同じ理由)
|
|
2360
2360
|
if (typeof r.space === "string" && r.space)
|
|
2361
2361
|
row.space = r.space.toLowerCase();
|
|
2362
|
+
// 保存日時(受付が Secrets Manager の LastChangedDate から載せる ISO)。日付として読める形だけ通す(札の「M/D に保存」の材料・便 KU)
|
|
2363
|
+
if (typeof r.savedAt === "string" && /^\d{4}-\d{2}-\d{2}T[\d:.]+(Z|[+-]\d{2}:?\d{2})$/.test(r.savedAt) && !isNaN(new Date(r.savedAt).getTime()))
|
|
2364
|
+
row.savedAt = r.savedAt;
|
|
2362
2365
|
out.push(row);
|
|
2363
2366
|
}
|
|
2364
2367
|
return out.length ? out : null;
|
|
@@ -2393,7 +2396,7 @@ function secretStateFromNow(rows, kind, space) {
|
|
|
2393
2396
|
hit = mine[0];
|
|
2394
2397
|
}
|
|
2395
2398
|
if (hit.state === "registered")
|
|
2396
|
-
return { known: "yes", src: "Secrets Manager" };
|
|
2399
|
+
return hit.savedAt ? { known: "yes", src: "Secrets Manager", savedAt: hit.savedAt } : { known: "yes", src: "Secrets Manager" };
|
|
2397
2400
|
if (hit.state === "missing")
|
|
2398
2401
|
return { known: "no", src: "" };
|
|
2399
2402
|
return null;
|
|
@@ -5734,7 +5737,6 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
5734
5737
|
.ds-more { margin-top: 14px; }
|
|
5735
5738
|
.ds-more > summary { cursor: pointer; color: var(--muted); font-size: 12px; }
|
|
5736
5739
|
.ds-more[open] > summary { margin-bottom: 8px; }
|
|
5737
|
-
.ds-more-key { margin: 6px 0 0; font-size: 12.5px; color: var(--text); display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
|
|
5738
5740
|
/* 行の状態に添える「次に誰が何をするか」(2026-08-18)。**必ず自分の行を占める**
|
|
5739
5741
|
(flex: 1 1 100%)——状態バッジの横に押し込むと、いちばん読ませたい一文が
|
|
5740
5742
|
カード幅に負けて省略される。状態の語より弱く、しかし読める大きさで出す */
|
|
@@ -5794,7 +5796,10 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
5794
5796
|
.ops-intro { color: var(--muted); font-size: 14px; line-height: 1.8; margin: 4px 0 8px; }
|
|
5795
5797
|
.ops-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
|
|
5796
5798
|
.sec-state { font-size: 12.5px; font-weight: 600; margin: 0 0 8px; color: var(--muted); }
|
|
5797
|
-
.sec-state.is-managed { color: #1a7f37; }
|
|
5799
|
+
.sec-state.is-managed, .sec-state.is-ok { color: #1a7f37; }
|
|
5800
|
+
.sec-state.is-failed { color: #b42318; }
|
|
5801
|
+
.sec-state.is-checking { color: var(--muted); font-weight: 400; font-style: italic; }
|
|
5802
|
+
.sec-saved { margin: 6px 0 0; }
|
|
5798
5803
|
.sec-state.is-none { color: var(--muted); font-weight: 400; }
|
|
5799
5804
|
/* 登録されているか分からない(engine がスペース別の状況をまだ出していない)。
|
|
5800
5805
|
**未登録と同じ見た目にしない**——断定していないことが色でも分かるようにする */
|
|
@@ -5830,16 +5835,6 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
5830
5835
|
.ops-card.ds-keycard > .ops-card-head { gap: 8px; }
|
|
5831
5836
|
.ops-card.ds-keycard .ops-card-icon { font-size: 16px; }
|
|
5832
5837
|
.ops-card.ds-keycard .ops-card-title { font-size: 13px; }
|
|
5833
|
-
/* 押すまで入力欄を出さない(2026-08-21・オーナー指摘)。summary はボタンに見せる */
|
|
5834
|
-
.sec-input-fold { border: none; margin: 0; }
|
|
5835
|
-
.sec-input-fold > summary {
|
|
5836
|
-
cursor: pointer; display: inline-block; list-style: none;
|
|
5837
|
-
padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border);
|
|
5838
|
-
background: #fff; color: var(--text); font-size: 12.5px; font-weight: 600;
|
|
5839
|
-
}
|
|
5840
|
-
.sec-input-fold > summary::-webkit-details-marker { display: none; }
|
|
5841
|
-
.sec-input-fold > summary:hover { border-color: var(--accent); color: var(--accent); }
|
|
5842
|
-
.sec-input-fold[open] > summary { margin-bottom: 8px; }
|
|
5843
5838
|
.ds-addform { border: 1px dashed var(--border); border-radius: 8px; padding: 12px 14px; margin-top: 10px; background: #fff; }
|
|
5844
5839
|
.ds-addform-title { font-size: 13px; font-weight: 700; color: var(--text); margin-bottom: 6px; }
|
|
5845
5840
|
.ds-addform .sec-input { margin-bottom: 6px; }
|
|
@@ -10156,7 +10151,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
10156
10151
|
// 🔴 **Backlog の行の一手(c-07 の 2 本目)。** 行の中身(そのスペースのキーの有無・同期経路・
|
|
10157
10152
|
// スペースの数)で決まるので関数で持つ。row は { domain, projectKey, gate }。
|
|
10158
10153
|
// DS_GATE_CAP.issues は札(APIキーが未登録です)だけを持ち、help を持たせない(一手の置き場は 1 か所)。
|
|
10159
|
-
// 部品の型は 文字列 / { copy, bare } / { act: "backlog-
|
|
10154
|
+
// 部品の型は 文字列 / { copy, bare } / { act: "backlog-route-on", label }
|
|
10160
10155
|
backlog: {
|
|
10161
10156
|
no_token: {
|
|
10162
10157
|
resting: function (row) { return backlogRowHelpParts(row); },
|
|
@@ -10298,21 +10293,16 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
10298
10293
|
/**
|
|
10299
10294
|
* 行の一手に置くボタン(c-07)。**押せないボタンは作らない**(null)。
|
|
10300
10295
|
* - "connect" … [接続する]。Slack の承認画面へ送る(slackConnectInline)。投入の口が無ければ null
|
|
10301
|
-
*
|
|
10302
|
-
*
|
|
10303
|
-
* 受け皿が無いスペースには作らない(別のスペースの欄へ落とさない)
|
|
10296
|
+
* 🔴 **鍵を入れるボタンは作らない(便 KU)。** 鍵の欄は接続先の行の中に最初から見えている(secretCard)ので、
|
|
10297
|
+
* 「入れる」の入口を行の一手に重ねない(同じ鍵に[入れる]が 3 か所あった)
|
|
10304
10298
|
* - "backlog-route-on" … [切り替える]。同期経路を固定 IP 経由にする(setBacklogRoute)
|
|
10305
10299
|
* @param label 省略時は既定の語
|
|
10306
|
-
* @param arg
|
|
10300
|
+
* @param arg 部品が要る材料(今は使う一手が無い)
|
|
10307
10301
|
*/
|
|
10308
10302
|
function actNode(act, label, arg) {
|
|
10309
10303
|
if (!SITE.intake) return null;
|
|
10310
10304
|
if (act === "connect") return slackConnectInline(label || "接続する");
|
|
10311
|
-
// Backlog の行の一手(c-07 の 2 本目)。arg はスペース(ドメイン)。**受け皿が無ければ作らない**
|
|
10312
|
-
if (act === "backlog-key") return backlogKeyJump(arg, label || "入れる");
|
|
10313
10305
|
if (act === "backlog-route-on") return backlogRouteOnButton(label || "切り替える");
|
|
10314
|
-
// 鍵の欄(KEY_SLOTS.figma)が無い構成では、移る先が無いので出さない
|
|
10315
|
-
if (act === "figma-key") return secretKindsShown().indexOf("figma") >= 0 ? figmaKeyJump(label || "トークンを入れる") : null;
|
|
10316
10306
|
return null;
|
|
10317
10307
|
}
|
|
10318
10308
|
/**
|
|
@@ -10488,13 +10478,12 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
10488
10478
|
},
|
|
10489
10479
|
issues: { no_token: { text: "APIキーが未登録です", cls: "ds-gate-muted" } },
|
|
10490
10480
|
design: {
|
|
10491
|
-
// 🔴 **鍵が無い行の一手は、行の中の 1 行(c-07)。**
|
|
10481
|
+
// 🔴 **鍵が無い行の一手は、行の中の 1 行(c-07)。** 一手の文が下の「Figma のトークン」の欄を指す(ボタンは無い・便 KU)
|
|
10492
10482
|
no_token: {
|
|
10493
10483
|
text: "トークンが未登録です",
|
|
10494
10484
|
cls: "ds-gate-muted",
|
|
10495
|
-
help: "Figma
|
|
10485
|
+
help: "Figma のトークンを、下の欄に入れてください。",
|
|
10496
10486
|
helpLink: { href: FIGMA_SETTINGS_URL, label: "Figma の設定でトークンを発行する →" },
|
|
10497
|
-
act: "figma-key",
|
|
10498
10487
|
},
|
|
10499
10488
|
// 「アクセス不可」では、トークンの失効なのか(403)ファイルを共有していないのか(404)が
|
|
10500
10489
|
// 画面から見分けられない(理由が文字の中だけ=機械の語に依存した分岐は書かない・c-07)。
|
|
@@ -10505,9 +10494,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
10505
10494
|
unreachable: {
|
|
10506
10495
|
text: "ファイルを読めません",
|
|
10507
10496
|
cls: "ds-gate-warn",
|
|
10508
|
-
help: "
|
|
10509
|
-
act: "figma-key",
|
|
10510
|
-
actLabel: "トークンを入れ直す",
|
|
10497
|
+
help: "このファイルに、トークンを発行したアカウントを閲覧者として招待してください(トークンが切れているときは、下の欄に入れ直してください)。",
|
|
10511
10498
|
},
|
|
10512
10499
|
},
|
|
10513
10500
|
};
|
|
@@ -10516,6 +10503,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
10516
10503
|
* 知らない値は 「DS_GATE」 と同じく「不明」(engine が新しい語を足したのに画面が知らない、
|
|
10517
10504
|
* という事実を黙って消さない)。
|
|
10518
10505
|
*/
|
|
10506
|
+
/** 接続の状態と[接続を確認]を鍵の部品が持つ能力か(Backlog=issues・Figma=design)。行はこの 2 つを持たない(便 KU) */
|
|
10507
|
+
function keyCardOwnsStatus(capId) { return capId === "issues" || capId === "design"; }
|
|
10508
|
+
|
|
10519
10509
|
function dsGateForCap(capId, status) {
|
|
10520
10510
|
var byCap = DS_GATE_CAP[capId];
|
|
10521
10511
|
if (byCap && byCap[status]) return byCap[status];
|
|
@@ -11109,24 +11099,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
11109
11099
|
return wrap;
|
|
11110
11100
|
}
|
|
11111
11101
|
|
|
11112
|
-
/**
|
|
11113
|
-
* [トークンを入れる]/[トークンを入れ直す](Figma の行の一手・c-07)。
|
|
11114
|
-
* 一覧の直後にある「Figma のトークン」の欄(KEY_SLOTS.figma)の入力へ移って focus する。
|
|
11115
|
-
* **欄は 0 件のあいだ畳まれている**が、行がある=ファイルが 1 件以上あるので畳まれていない。
|
|
11116
|
-
* 入力が見つからなければ何もしない(鍵の欄を作る口が無い構成)。
|
|
11117
|
-
*/
|
|
11118
|
-
function figmaKeyJump(label) {
|
|
11119
|
-
var btn = el("button", { class: "ds-toggle-btn ds-act-inline", type: "button", text: label || "トークンを入れる" });
|
|
11120
|
-
btn.addEventListener("click", function () {
|
|
11121
|
-
var slot = KEY_SLOTS.figma;
|
|
11122
|
-
var input = slot && slot.querySelector("input, textarea");
|
|
11123
|
-
if (!input) return;
|
|
11124
|
-
try { if (input.scrollIntoView) input.scrollIntoView({ block: "center" }); } catch (e) { /* 動かせなくても focus は試す */ }
|
|
11125
|
-
input.focus();
|
|
11126
|
-
});
|
|
11127
|
-
return btn;
|
|
11128
|
-
}
|
|
11129
|
-
|
|
11130
11102
|
/** 台帳から、そのワークスペースの接続状態を引く(無ければ null=断定しない) */
|
|
11131
11103
|
function tokenStateOf(workspaces, teamId) {
|
|
11132
11104
|
var list = workspaces || [];
|
|
@@ -12425,32 +12397,15 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
12425
12397
|
// **対応表に無い種別は隠さない**(keyTargetCount の既定と同じく出す側に倒す)。
|
|
12426
12398
|
// 3つ目の鍵が足されて分岐を書き忘れた場合は key-card-visibility の [全種0件] が落ちる
|
|
12427
12399
|
var hide = shown[KEY_CARDS[i].kind] === false;
|
|
12428
|
-
// 🔴 **Backlog の行の中のカードは、0 件の判定(上)に加えて「見せる理由があるとき」だけ見せる**
|
|
12429
|
-
//(c-07 の 2 本目)。0 件が勝つ——0 件のあいだは理由があっても出さない(順序の逆な案内になる)
|
|
12430
|
-
if (!hide && KEY_CARDS[i].compact) hide = !backlogKeyCardWanted(KEY_CARDS[i]);
|
|
12431
12400
|
KEY_CARDS[i].el.hidden = hide;
|
|
12432
|
-
|
|
12401
|
+
// 🔴 札は見せる瞬間に当て直す(作ったときの答えは古いことがある。取り直しが後から届く・#227)
|
|
12402
|
+
if (!hide && KEY_CARDS[i].refresh) KEY_CARDS[i].refresh();
|
|
12433
12403
|
}
|
|
12434
12404
|
eachKeySlot(function (slot) {
|
|
12435
12405
|
slot.hidden = !slot.querySelector("[data-secret-kind]:not([hidden])");
|
|
12436
12406
|
});
|
|
12437
12407
|
}
|
|
12438
12408
|
|
|
12439
|
-
/**
|
|
12440
|
-
* Backlog の行の中の鍵カードを、いま見せるか(c-07 の 2 本目・スペースごとの判定)。次の 4 つのどれか:
|
|
12441
|
-
* ① キーが要る(backlogKeyNeededForSpace=登録状況が「未登録」・足した直後で答えがまだ無い等)
|
|
12442
|
-
* ② 一手の[入れる]/[入れ直す]・「その他」の[入れ直す]が押された(forced)
|
|
12443
|
-
* ③ 触り始めた(開いた・値がある・結果の文がある)。🔴 **保存直後の「✓ 保存しました」と入力中の値を畳まない**(#223)
|
|
12444
|
-
* 使えているスペースのカードは、ふだん隠れている(DOM には常に在る=入力中の値・結果は消えない)。
|
|
12445
|
-
*/
|
|
12446
|
-
function backlogKeyCardWanted(ent) {
|
|
12447
|
-
if (ent.forced) return true;
|
|
12448
|
-
if (ent.fold && ent.fold.open) return true;
|
|
12449
|
-
if (ent.input && ent.input.value !== "") return true;
|
|
12450
|
-
if (ent.msg && ent.msg.textContent !== "") return true;
|
|
12451
|
-
return backlogKeyNeededForSpace(ent.space);
|
|
12452
|
-
}
|
|
12453
|
-
|
|
12454
12409
|
/** いま在る鍵の受け皿(.ds-keyrow)を順に渡す。置き場の正本は KEY_SLOTS */
|
|
12455
12410
|
function eachKeySlot(fn) {
|
|
12456
12411
|
var slots = KEY_SLOTS.backlog || {};
|
|
@@ -13046,6 +13001,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
13046
13001
|
KEY_CARDS = [];
|
|
13047
13002
|
// Backlog の節の行の控え・結果の帯・描き直しの口も作り直す(切り離された古い節を掴んだままにしない)
|
|
13048
13003
|
BACKLOG_UI = { rows: [], msg: null, repaintRows: null };
|
|
13004
|
+
FIGMA_UI = { keys: [] };
|
|
13049
13005
|
// 作り直しはスナップショットから描き直すこと。応答で採った件数はここで捨てる
|
|
13050
13006
|
ADOPTED_TARGET_COUNT = null;
|
|
13051
13007
|
var internals = fleetVal("internalSources") || [];
|
|
@@ -14501,6 +14457,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
14501
14457
|
MERGED = null;
|
|
14502
14458
|
repaintOpenLists();
|
|
14503
14459
|
refreshDataSources();
|
|
14460
|
+
syncKeyCardVisibility(); // 鍵の札(接続OK/失敗)も同じ結果で当て直す
|
|
14504
14461
|
}
|
|
14505
14462
|
// 本物の行を 1 回だけ取りに行く(据え置きのまま・「reloadLiveState」の項)
|
|
14506
14463
|
reloadLiveState();
|
|
@@ -15452,7 +15409,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15452
15409
|
}
|
|
15453
15410
|
var ipLabel = ip ? "固定の送信元 IP(" + ip + ")" : "固定の送信元 IP";
|
|
15454
15411
|
if (keyState === "no") {
|
|
15455
|
-
return "同期は" + ipLabel + "から行います。お客様にこの IP
|
|
15412
|
+
return "同期は" + ipLabel + "から行います。お客様にこの IP の許可を依頼し、接続先の行の下の欄に API キーを貼って[保存して接続を確認]を押すと同期が始まります。";
|
|
15456
15413
|
}
|
|
15457
15414
|
// 2 文に収める(実装レビューの指摘)。押した直後の帯(サーバの文面)も「許可を依頼」を言うが、
|
|
15458
15415
|
// 帯は数秒で読み終える結果で、この行は次に開いたときも残る状態——役目が違うので両方に置く
|
|
@@ -15551,7 +15508,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15551
15508
|
* 部品の置き場:
|
|
15552
15509
|
* - 一手 … DS_GATE_RESTING_HELP.backlog → backlogRowHelpParts(行の中身で決まる)
|
|
15553
15510
|
* - キーの欄 … これまでと同じスペースごとの受け皿(KEY_SLOTS.backlog・#223)に同じカード。
|
|
15554
|
-
* 変えるのは見え方だけ(syncKeyCardVisibility
|
|
15511
|
+
* 変えるのは見え方だけ(syncKeyCardVisibility)
|
|
15555
15512
|
* - 同期経路の切り替え … setBacklogRoute に 1 本化。入口はタイルの一手・[接続を確認]の結果・「その他」のスイッチ
|
|
15556
15513
|
* - 札(事実)… 経路札「固定 IP 経由」・リアルタイム札(appendBacklogChips)
|
|
15557
15514
|
* ------------------------------------------------------------------------- */
|
|
@@ -15562,6 +15519,8 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15562
15519
|
* 🔴 **鍵の置き場の正本は KEY_SLOTS。ここは行の控えだけ**(#223 の「節の中に受け皿の控えを持たない」は守る)。
|
|
15563
15520
|
*/
|
|
15564
15521
|
var BACKLOG_UI = { rows: [], msg: null, repaintRows: null };
|
|
15522
|
+
/** Figma の鍵が効くファイル(鍵カードの札が引く。一覧を描くときに入れ替える) */
|
|
15523
|
+
var FIGMA_UI = { keys: [] };
|
|
15565
15524
|
|
|
15566
15525
|
/** いま見えている行のスペース(小文字・重複なし) */
|
|
15567
15526
|
function backlogDomainsNow() {
|
|
@@ -15614,27 +15573,13 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15614
15573
|
return false;
|
|
15615
15574
|
}
|
|
15616
15575
|
|
|
15617
|
-
/** そのスペースの鍵カードを見せるか(行のどれかが要るか。行が無ければ要らない) */
|
|
15618
|
-
function backlogKeyNeededForSpace(space) {
|
|
15619
|
-
var domains = backlogDomainsNow();
|
|
15620
|
-
var dom = space || (domains.length === 1 ? domains[0] : "");
|
|
15621
|
-
if (!dom) return false;
|
|
15622
|
-
var rows = BACKLOG_UI.rows || [];
|
|
15623
|
-
for (var i = 0; i < rows.length; i++) {
|
|
15624
|
-
if (String(rows[i].domain || "").toLowerCase() !== dom) continue;
|
|
15625
|
-
var r = reachableStateOf("issues", issuesRefOf(rows[i].domain, rows[i].projectKey));
|
|
15626
|
-
if (backlogKeyNeeded(dom, r ? r.status : null)) return true;
|
|
15627
|
-
}
|
|
15628
|
-
return false;
|
|
15629
|
-
}
|
|
15630
|
-
|
|
15631
15576
|
/**
|
|
15632
15577
|
* Backlog の行に出す一手のパーツ(無ければ null)。**スペースをまたがない**(ボタンはその行のスペースの受け皿だけを引く)。
|
|
15633
15578
|
*
|
|
15634
|
-
* キーが要る → 「API
|
|
15635
|
-
* 読めない・通常経路 →
|
|
15636
|
-
* 読めない・固定 IP → 「お客様に固定の送信元 IP(…)の許可を依頼してください。[コピー]
|
|
15637
|
-
* 読めない・経路不明 →
|
|
15579
|
+
* キーが要る → 「API キーを、下の欄に入れてください。」(複数スペースならスペース名つき)
|
|
15580
|
+
* 読めない・通常経路 → 「読めません。下の欄に API キーを入れ直してください。 Backlog に IP 制限があるなら、固定 IP 経由で読んでください。[切り替える]」
|
|
15581
|
+
* 読めない・固定 IP → 「お客様に固定の送信元 IP(…)の許可を依頼してください。[コピー] 許可済みなら、下の欄に API キーを入れ直してください。」
|
|
15582
|
+
* 読めない・経路不明 → 「読めません。下の欄に API キーを入れ直してください。」(切り替えが押せるか分からないので[切り替える]は出さない)
|
|
15638
15583
|
*
|
|
15639
15584
|
* 🔴 **理由の語(HTTP の番号等)には依存しない。** 401・403・404 は画面から見分けられないので、読めない行は広い方の 1 行。
|
|
15640
15585
|
* IP 制限と確定できるのは[接続を確認]の応答の reason だけ(appendBacklogProbeSwitch)。
|
|
@@ -15646,10 +15591,10 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15646
15591
|
var dom = String(row.domain || "").toLowerCase();
|
|
15647
15592
|
var multi = backlogDomainsNow().length > 1;
|
|
15648
15593
|
if (backlogKeyNeeded(dom, row.gate)) {
|
|
15649
|
-
|
|
15594
|
+
// 🔴 鍵の欄は接続先の行の中に最初から見えている(便 KU)。ここは指す文だけでボタンは置かない
|
|
15595
|
+
return [(multi ? dom + " の " : "") + "API キーを、下の欄に入れてください。"];
|
|
15650
15596
|
}
|
|
15651
15597
|
if (row.gate !== "unreachable") return null;
|
|
15652
|
-
var reenter = { act: "backlog-key", space: dom, label: "入れ直す" };
|
|
15653
15598
|
var route = LIVE_BACKLOG_ROUTE;
|
|
15654
15599
|
if (route === "fixed-ip") {
|
|
15655
15600
|
// IP が取れていなければ IP も[コピー]も出さない(嘘の値を書かない・#516)
|
|
@@ -15657,9 +15602,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15657
15602
|
var head = ip
|
|
15658
15603
|
? ["お客様に固定の送信元 IP(" + ip + ")の許可を依頼してください。", { copy: ip, bare: true }]
|
|
15659
15604
|
: ["お客様に固定の送信元 IP の許可を依頼してください。"];
|
|
15660
|
-
return head.concat(["
|
|
15605
|
+
return head.concat([" 許可済みなら、下の欄に API キーを入れ直してください。"]);
|
|
15661
15606
|
}
|
|
15662
|
-
var base = ["
|
|
15607
|
+
var base = ["読めません。下の欄に API キーを入れ直してください。"];
|
|
15663
15608
|
if (route === "runner") {
|
|
15664
15609
|
// 切り替えは案件全体の経路(スペースごとではない)。複数スペースでは強めに言う
|
|
15665
15610
|
var scope = multi
|
|
@@ -15690,54 +15635,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15690
15635
|
return appendReachableReason(row, "issues", ref);
|
|
15691
15636
|
}
|
|
15692
15637
|
|
|
15693
|
-
/** そのスペースの鍵の受け皿(無ければ null)。名無しの受け皿は、スペースが 1 つ以下のあいだだけ代わりを務める(ensureKeySlots の項) */
|
|
15694
|
-
function backlogKeySlotFor(space) {
|
|
15695
|
-
var slots = KEY_SLOTS.backlog || {};
|
|
15696
|
-
var d = String(space || "").toLowerCase();
|
|
15697
|
-
if (d && slots[d]) return slots[d];
|
|
15698
|
-
if (slots[""] && backlogDomainsNow().length <= 1) return slots[""];
|
|
15699
|
-
return null;
|
|
15700
|
-
}
|
|
15701
|
-
|
|
15702
|
-
/** そのスペースの鍵カードの控え(無ければ null)。**ほかのスペースのカードへ落とさない** */
|
|
15703
|
-
function backlogKeyEntryFor(space) {
|
|
15704
|
-
var d = String(space || "").toLowerCase();
|
|
15705
|
-
var list = [];
|
|
15706
|
-
for (var i = 0; i < KEY_CARDS.length; i++) {
|
|
15707
|
-
if (KEY_CARDS[i].kind === "backlog" && KEY_CARDS[i].compact) list.push(KEY_CARDS[i]);
|
|
15708
|
-
}
|
|
15709
|
-
for (var j = 0; j < list.length; j++) if (d && list[j].space === d) return list[j];
|
|
15710
|
-
if (backlogDomainsNow().length <= 1) {
|
|
15711
|
-
for (var k = 0; k < list.length; k++) if (list[k].space === "") return list[k];
|
|
15712
|
-
}
|
|
15713
|
-
return null;
|
|
15714
|
-
}
|
|
15715
|
-
|
|
15716
|
-
/** そのスペースの鍵カードを見せて、入力へ移る([入れる]・[入れ直す])。見つからなければ false */
|
|
15717
|
-
function openBacklogKeyCard(space) {
|
|
15718
|
-
var ent = backlogKeyEntryFor(space);
|
|
15719
|
-
if (!ent) return false;
|
|
15720
|
-
ent.forced = true;
|
|
15721
|
-
ent.fold.open = true;
|
|
15722
|
-
syncKeyCardVisibility();
|
|
15723
|
-
try { if (ent.input.scrollIntoView) ent.input.scrollIntoView({ block: "center" }); } catch (e) { /* 動かせなくても focus は試す */ }
|
|
15724
|
-
ent.input.focus();
|
|
15725
|
-
return true;
|
|
15726
|
-
}
|
|
15727
|
-
|
|
15728
|
-
/**
|
|
15729
|
-
* [入れる]/[入れ直す]。**そのスペースの受け皿が無ければ作らない**(別のスペースの欄へ移さない)。
|
|
15730
|
-
* 🔴 **作る条件は受け皿(KEY_SLOTS)だけ。カードの控えは押した時点で引く**——節は鍵カードより先に組み立てられる
|
|
15731
|
-
*(buildDataSources の順序)ので、行を描く時点ではカードがまだ無い。受け皿は節が先に作っている
|
|
15732
|
-
*/
|
|
15733
|
-
function backlogKeyJump(space, label) {
|
|
15734
|
-
if (secretKindsShown().indexOf("backlog") < 0) return null;
|
|
15735
|
-
if (!backlogKeySlotFor(space)) return null;
|
|
15736
|
-
var btn = el("button", { class: "ds-toggle-btn ds-act-inline", type: "button", text: label || "入れる" });
|
|
15737
|
-
btn.addEventListener("click", function () { openBacklogKeyCard(space); });
|
|
15738
|
-
return btn;
|
|
15739
|
-
}
|
|
15740
|
-
|
|
15741
15638
|
/**
|
|
15742
15639
|
* 同期経路の切り替え(固定 IP 経由 ⇄ 通常)。**スイッチ(「その他」)とタイルの[切り替える]が同じこの関数を呼ぶ**
|
|
15743
15640
|
* ——操作を 2 本書かない(op・値・確認なし・応答の route を正とする・changed:false の取り直しは 1 つだけ持つ)。
|
|
@@ -16079,6 +15976,8 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16079
15976
|
* 行の組み立ての最後に 「appendReachableReason」 を呼ぶ。
|
|
16080
15977
|
*/
|
|
16081
15978
|
function appendReachableChip(row, capId, ref, workspace) {
|
|
15979
|
+
// 🔴 鍵で読む能力(Backlog・Figma)の接続の状態は、鍵の部品(secretCard)の札 1 か所だけ(便 KU)。行にも出すと同じ材料の札が窓の中で 2 か所に見える
|
|
15980
|
+
if (keyCardOwnsStatus(capId)) return row;
|
|
16082
15981
|
var r = reachableStateOf(capId, ref, workspace);
|
|
16083
15982
|
if (!r) return row;
|
|
16084
15983
|
var gate = dsGateForCap(capId, r.status);
|
|
@@ -16273,7 +16172,8 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16273
16172
|
// 🔴 表の案件(組み直した案件)には起こす同期が無い(押すと「確認を開始できませんでした」になる)。2 つとも出さない。
|
|
16274
16173
|
// 見分けは設定の画面と同じ 1 か所(viewMode)。今までの案件(file)はここを素通り=画面は 1 バイトも変わらない
|
|
16275
16174
|
if (viewMode() === "table") return row;
|
|
16276
|
-
|
|
16175
|
+
// 鍵で読む能力の[接続を確認]は鍵の部品の[保存して接続を確認]だけ(便 KU)。行には[今すぐ同期]だけ残す
|
|
16176
|
+
var checkBtn = keyCardOwnsStatus(capId) ? null : el("button", { class: "ds-toggle-btn", type: "button", text: "接続を確認" });
|
|
16277
16177
|
var syncBtn = el("button", { class: "ds-toggle-btn", type: "button", text: "今すぐ同期" });
|
|
16278
16178
|
var note = el("p", { class: "ds-probe-wait" });
|
|
16279
16179
|
var phase = probeWaitPhaseOf(capId, ref);
|
|
@@ -16282,7 +16182,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16282
16182
|
else if (phase === "timeout") note.textContent = PROBE_WAIT_TIMEOUT_TEXT;
|
|
16283
16183
|
else note.hidden = true;
|
|
16284
16184
|
|
|
16285
|
-
checkBtn.addEventListener("click", async function () {
|
|
16185
|
+
if (checkBtn) checkBtn.addEventListener("click", async function () {
|
|
16286
16186
|
// 押している間は**ボタンだけ**が「確認中…」になる。行の中身は変えない(#1328)。
|
|
16287
16187
|
// 前回の返事(「同期を開始しました」等)は押した時点で消す
|
|
16288
16188
|
var endBusy = beginBusy(checkBtn, "確認中…");
|
|
@@ -16349,7 +16249,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16349
16249
|
endBusy();
|
|
16350
16250
|
});
|
|
16351
16251
|
|
|
16352
|
-
row.appendChild(checkBtn);
|
|
16252
|
+
if (checkBtn) row.appendChild(checkBtn);
|
|
16353
16253
|
row.appendChild(syncBtn);
|
|
16354
16254
|
row.appendChild(note);
|
|
16355
16255
|
return row;
|
|
@@ -16881,7 +16781,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16881
16781
|
// 🔴 **追加の欄は URL の入力と[追加]だけ(c-07 の 2 本目)。** 手順の文は置かない(hint を渡さない)。
|
|
16882
16782
|
// 外した情報の行き先:
|
|
16883
16783
|
// - 「起票先は変わりません」「毎晩同期します」「外すには」… 上部の説明文(openCapabilityModal)
|
|
16884
|
-
// - 「スペースごとに別のAPIキー」…
|
|
16784
|
+
// - 「スペースごとに別のAPIキー」… 足した行の中のスペースごとの鍵の欄(札つき)
|
|
16885
16785
|
// - 「専用 URL の登録が要ります」… 追加した行のリアルタイム札(未受信)と、一覧の下の一手[設定する]
|
|
16886
16786
|
build: function (url) {
|
|
16887
16787
|
return { op: "backlog-target-add", url: url, baseGeneration: targetsGenerationOf(targets) };
|
|
@@ -16940,21 +16840,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16940
16840
|
box.appendChild(rtBox);
|
|
16941
16841
|
|
|
16942
16842
|
var routeWrap = backlogRouteSwitch();
|
|
16943
|
-
var keyRows = liveList("backlog-key-rows", function () {
|
|
16944
|
-
var ds = backlogDomainsNow();
|
|
16945
|
-
return JSON.stringify(ds.map(function (d) { return [d, secretStateOf("backlog", d, ds.length).known]; }));
|
|
16946
|
-
}, function (b) {
|
|
16947
|
-
var ds = backlogDomainsNow();
|
|
16948
|
-
ds.forEach(function (d) {
|
|
16949
|
-
var st = secretStateOf("backlog", d, ds.length);
|
|
16950
|
-
var word = st.known === "yes" ? "登録済みです" : st.known === "no" ? "未登録です" : "確認中です";
|
|
16951
|
-
// ボタンはそのスペースの鍵カードを開く(受け皿が無ければ作らない)
|
|
16952
|
-
b.appendChild(el("p", { class: "ds-more-key" }, [
|
|
16953
|
-
el("span", { text: d + ":API キーは" + word }),
|
|
16954
|
-
backlogKeyJump(d, st.known === "no" ? "入れる" : "入れ直す"),
|
|
16955
|
-
]));
|
|
16956
|
-
});
|
|
16957
|
-
});
|
|
16958
16843
|
var rtMore = liveList("backlog-realtime-more", function () {
|
|
16959
16844
|
var st = backlogRealtimeState();
|
|
16960
16845
|
return JSON.stringify([st ? [st.total, st.live] : null, backlogFactsSigOf()]);
|
|
@@ -16970,7 +16855,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16970
16855
|
moreEl = el("details", { class: "ds-more" }, [
|
|
16971
16856
|
el("summary", { text: "その他" }),
|
|
16972
16857
|
routeWrap,
|
|
16973
|
-
keyRows,
|
|
16974
16858
|
rtMore,
|
|
16975
16859
|
]);
|
|
16976
16860
|
box.appendChild(moreEl);
|
|
@@ -16984,7 +16868,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16984
16868
|
moreEl.hidden = !(keyTargetCount("課題管理") > 0 || LIVE_BACKLOG_ROUTE === "fixed-ip");
|
|
16985
16869
|
rtBox.__rebuild();
|
|
16986
16870
|
if (routeWrap.__live) routeWrap.__live.__rebuild();
|
|
16987
|
-
keyRows.__rebuild();
|
|
16988
16871
|
rtMore.__rebuild();
|
|
16989
16872
|
}
|
|
16990
16873
|
}
|
|
@@ -17328,6 +17211,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
17328
17211
|
// サーバが削除を認めた印なので、ここから先に同じ鍵が現れたら**貼り直された別の登録**
|
|
17329
17212
|
var figKeys = figs.map(function (f) { return f.key; });
|
|
17330
17213
|
figsRemoved = figsRemoved.filter(function (k) { return figKeys.indexOf(k) >= 0; });
|
|
17214
|
+
FIGMA_UI.keys = figKeys.filter(function (k) { return figsRemoved.indexOf(k) < 0; });
|
|
17331
17215
|
// **残り件数は「押した時点」で数える。** 一覧(figs)は夜間バッチのスナップショットで、
|
|
17332
17216
|
// このページを開いている間はもちろん、その日のうちに再読み込みしても更新されない。
|
|
17333
17217
|
// 描画時点の件数で判定すると、3件を1件ずつ外していったとき最後の1件でも警告が出ない。
|
|
@@ -19585,6 +19469,8 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19585
19469
|
"figma": {
|
|
19586
19470
|
icon: "🎨",
|
|
19587
19471
|
title: "Figma のトークン",
|
|
19472
|
+
// 欄の案内(placeholder)。窓の他の文言・発行のしかたと同じ語(便 KU)
|
|
19473
|
+
paste: "アクセストークンを貼り付け",
|
|
19588
19474
|
// **必要なスコープは実装が叩くAPIから決まる。** sync-designs は
|
|
19589
19475
|
// GET /v1/files/{key} → file_content:read(画面インベントリ)
|
|
19590
19476
|
// GET /v1/files/{key}/comments → file_comments:read(指摘の同期)
|
|
@@ -19674,6 +19560,8 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19674
19560
|
"backlog": {
|
|
19675
19561
|
icon: "📋",
|
|
19676
19562
|
title: "Backlog のAPIキー",
|
|
19563
|
+
// 欄の案内(placeholder)。窓の他の文言・発行のしかたと同じ語(便 KU)
|
|
19564
|
+
paste: "API キーを貼り付け",
|
|
19677
19565
|
how: "Backlog → 個人設定 → API で発行(同期先の Backlog プロジェクトが見えるアカウントで)",
|
|
19678
19566
|
// ⚠ **desc は足さない。** 「毎晩同期するために使います」の 1 行は「カードが長すぎる」で
|
|
19679
19567
|
// 外した経緯があり、secret-card-guidance.test.mjs が空の段落ごと見張っている。
|
|
@@ -19875,9 +19763,8 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19875
19763
|
var stateSpace = (opts && opts.stateSpace) || "";
|
|
19876
19764
|
var spaceCount = (opts && opts.spaceCount) || 0;
|
|
19877
19765
|
var inRow = !!(opts && opts.inRow);
|
|
19878
|
-
// 🔴 **Backlog
|
|
19879
|
-
//
|
|
19880
|
-
// 触り始めた後だけ見える(syncKeyCardVisibility)。旧カード(行の外・intake 無しの案件)と Figma は従来どおり。
|
|
19766
|
+
// 🔴 **Backlog の行の中のカードは見出しを持たない**(行の中なので「何の鍵か」は札と欄が言う)。
|
|
19767
|
+
// 接続先が 1 件以上あるあいだは常に見える(0 件のときだけ syncKeyCardVisibility が畳む)。
|
|
19881
19768
|
var compact = kind === "backlog" && inRow;
|
|
19882
19769
|
/**
|
|
19883
19770
|
* 鍵がどこまで効くのか(#229)。**置き場所だけでは伝わらないので、言葉にする。**
|
|
@@ -19892,11 +19779,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19892
19779
|
// **いま登録されているか**を先に出す。入れ直したのに反映されていない状態が
|
|
19893
19780
|
// 画面で分かるようにする(接続状況は夜間バッチのスナップショットなので、
|
|
19894
19781
|
// 保存の直後は前日の値のまま。時刻は上の節に出している)。
|
|
19895
|
-
var st = secretStateOf(kind, stateSpace, spaceCount);
|
|
19896
19782
|
var cardTitle = meta.title;
|
|
19897
|
-
// 🔴 **「登録済み」は「読めている」を意味しない。**
|
|
19898
|
-
//
|
|
19899
|
-
//(同期できているかのバッジは、夜間処理が接続先ごとの成否を保存してからの別作業)。
|
|
19783
|
+
// 🔴 **「登録済み」は「読めている」を意味しない。** 「接続OK」を札に出してよいのは、そのスペース(Figma は全ファイル)の
|
|
19784
|
+
// 行の「届くか」がすべて ok のときだけ(statusOf)。測っていなければ「登録済み」止まり。
|
|
19900
19785
|
//
|
|
19901
19786
|
// **前方一致で見る。** #105 の移行期は「Secrets Manager(旧名)」も来る。
|
|
19902
19787
|
// 完全一致にすると、旧名で動いている案件だけが repo secret と同じ見た目になり、
|
|
@@ -19907,27 +19792,146 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19907
19792
|
// 同じ 1 語にし、**生の値は data-src に置く**(判定の is-managed は生の値のまま)。
|
|
19908
19793
|
// 知らない値が来ても生で出さない——project-wording.test.mjs が画面の語を見張る
|
|
19909
19794
|
var state = el("p", { class: "sec-state" });
|
|
19910
|
-
|
|
19911
|
-
|
|
19912
|
-
|
|
19795
|
+
// 🔴 **鍵の窓は 1 か所・欄は最初から見えている・ボタンは 1 つ(便 KU)。** 以前は[入れる]で開く畳み+[保存]+別の[接続を確認]の 3 段で、
|
|
19796
|
+
// 同じ鍵の[入れる]が行の一手・「その他」・畳みの 3 か所にあった。いまは 状態の札 → 伏せ字の欄(空のまま)→ [保存して接続を確認]。
|
|
19797
|
+
// 保存した値は読み戻さない(書き込み専用)。登録済みでも欄は空で、入れ直すときだけ貼る(伏せ字を欄に入れて伏せ字ごと保存する事故を避ける)
|
|
19798
|
+
var cap = kind === "backlog" ? "issues" : "design";
|
|
19799
|
+
var input = el("input", { class: "sec-input", type: "password", placeholder: meta.paste || "トークンを貼り付け", autocomplete: "off", spellcheck: "false" });
|
|
19913
19800
|
var btn = el("button", { class: "ds-toggle-btn", type: "button", text: "保存" });
|
|
19914
19801
|
var msg = el("div", { class: "ds-toggle-msg" });
|
|
19802
|
+
var savedNote = el("p", { class: "sec-note sec-saved" });
|
|
19803
|
+
// 札が読む材料の控え。checking=保存〜確認の最中、savedHere=この画面で保存した(正本 secretsNow は最大 10 秒古い答えを返すので、registered を返すまで「登録済み」以上に固定する)
|
|
19804
|
+
var ent = { kind: kind, el: null, compact: compact, space: stateSpace, input: input, msg: msg, checking: false, savedHere: false };
|
|
19805
|
+
|
|
19806
|
+
function spaceCountNow() { return kind === "backlog" ? backlogDomainsNow().length : spaceCount; }
|
|
19807
|
+
/** この鍵が効く接続先の ref(Backlog=そのスペースの行・Figma=一覧のファイル)。登録済みの一覧だけを引く=孤児の行を混ぜない */
|
|
19808
|
+
function refsNow() {
|
|
19809
|
+
var out = [];
|
|
19810
|
+
if (kind === "backlog") {
|
|
19811
|
+
var ds = backlogDomainsNow();
|
|
19812
|
+
var dom = stateSpace || (ds.length === 1 ? ds[0] : "");
|
|
19813
|
+
var rows = BACKLOG_UI.rows || [];
|
|
19814
|
+
for (var i = 0; i < rows.length; i++) {
|
|
19815
|
+
if (dom && String(rows[i].domain || "").toLowerCase() === dom) out.push(issuesRefOf(rows[i].domain, rows[i].projectKey));
|
|
19816
|
+
}
|
|
19817
|
+
} else {
|
|
19818
|
+
out = (FIGMA_UI.keys || []).slice();
|
|
19819
|
+
}
|
|
19820
|
+
return out;
|
|
19821
|
+
}
|
|
19822
|
+
/** 接続の確認の口があるか。組み直した案件(表)も同じ口(受付 op=probe の direct・同期を起こさずその場で 1 本叩く)で確かめる */
|
|
19823
|
+
function probeOk() { return !!SITE.intake && !!dispatchProbeTypeOf(cap); }
|
|
19824
|
+
/** 「M/D に保存」。受付の savedAt(Secrets Manager の LastChangedDate)から出す。ブラウザには覚えない(端末が変わると消えるため) */
|
|
19825
|
+
function savedDate(st) {
|
|
19826
|
+
var d = st && st.savedAt ? new Date(st.savedAt) : null;
|
|
19827
|
+
return d && !isNaN(d.getTime()) ? (d.getMonth() + 1) + "/" + d.getDate() : "";
|
|
19828
|
+
}
|
|
19829
|
+
function secretNow() {
|
|
19830
|
+
var s = secretStateOf(kind, stateSpace, spaceCountNow());
|
|
19831
|
+
if (ent.savedHere) {
|
|
19832
|
+
if (s.known === "yes") ent.savedHere = false; // 正本が追いついた
|
|
19833
|
+
else return { known: "yes", src: "" };
|
|
19834
|
+
}
|
|
19835
|
+
return s;
|
|
19836
|
+
}
|
|
19837
|
+
/**
|
|
19838
|
+
* 札 1 つの決め方。**未登録/確認中/接続OK〈時刻〉/失敗〈理由の一言〉/登録済み**。
|
|
19839
|
+
* 「失敗」の一言は行の札の語(dsGateForCap)をそのまま使う。測っていない行・鍵が無かった頃の古い行(no_token)は数えず、
|
|
19840
|
+
* 一部だけ測れているときも「接続OK」と言い切らない(登録済みに倒す)。
|
|
19841
|
+
*/
|
|
19842
|
+
function statusOf(st) {
|
|
19843
|
+
if (ent.checking) return ["is-checking", "確認中"];
|
|
19844
|
+
if (st.known === "no") return ["is-none", "未登録"];
|
|
19845
|
+
if (st.known !== "yes") return ["is-unknown", "確認中"];
|
|
19846
|
+
var refs = refsNow(), bad = null, ok = 0, latest = "";
|
|
19847
|
+
for (var i = 0; i < refs.length; i++) {
|
|
19848
|
+
var r = reachableStateOf(cap, refs[i]);
|
|
19849
|
+
if (!r || r.status === "no_token") continue;
|
|
19850
|
+
if (r.status === "ok") { ok++; if (String(r.at || "") > latest) latest = String(r.at || ""); }
|
|
19851
|
+
else if (!bad) bad = r;
|
|
19852
|
+
}
|
|
19853
|
+
if (bad) return ["is-failed", "失敗(" + dsGateForCap(cap, bad.status).text + ")"];
|
|
19854
|
+
if (ok && ok === refs.length) {
|
|
19855
|
+
var t = dsFmtTime(latest);
|
|
19856
|
+
return ["is-ok", "接続OK" + (t ? "(" + t + ")" : "")];
|
|
19857
|
+
}
|
|
19858
|
+
return null; // 登録済み
|
|
19859
|
+
}
|
|
19860
|
+
function paint() {
|
|
19861
|
+
var st = secretNow();
|
|
19862
|
+
var s = statusOf(st);
|
|
19863
|
+
if (s) {
|
|
19864
|
+
// 取得元は札の語に関わらず data-src に置く(判定の is-managed は生の値の前方一致・#841)
|
|
19865
|
+
var srcRaw = st.known === "yes" ? (st.src || "") : "";
|
|
19866
|
+
state.className = "sec-state " + s[0] + (srcRaw.indexOf("Secrets Manager") === 0 ? " is-managed" : "");
|
|
19867
|
+
if (srcRaw) state.setAttribute("data-src", srcRaw); else state.removeAttribute("data-src");
|
|
19868
|
+
state.textContent = s[1];
|
|
19869
|
+
} else {
|
|
19870
|
+
applySecretState(state, st);
|
|
19871
|
+
}
|
|
19872
|
+
var reg = st.known === "yes";
|
|
19873
|
+
var d = savedDate(st);
|
|
19874
|
+
savedNote.hidden = !reg;
|
|
19875
|
+
savedNote.textContent = reg ? "登録済み" + (d ? "(" + d + " に保存)" : "") + "。入れ直すときだけ貼ってください" : "";
|
|
19876
|
+
if (!btn.disabled) btn.textContent = probeOk() ? "保存して接続を確認" : "保存";
|
|
19877
|
+
if (preferred) {
|
|
19878
|
+
var want = st.known === "no";
|
|
19879
|
+
if (want && !preferred.parentNode && card) card.insertBefore(preferred, input);
|
|
19880
|
+
else if (!want && preferred.parentNode) preferred.parentNode.removeChild(preferred);
|
|
19881
|
+
}
|
|
19882
|
+
}
|
|
19883
|
+
/** 保存のあとの接続の確認。結果は行と同じ形で置く(applyProbeResult)。返すのは添える 1 文(無ければ空) */
|
|
19884
|
+
var ipReason = false;
|
|
19885
|
+
async function checkAfterSave() {
|
|
19886
|
+
ipReason = false;
|
|
19887
|
+
var type = dispatchProbeTypeOf(cap);
|
|
19888
|
+
// Figma は回数制限(1 分あたりの枠)に収まるよう先頭の 2 ファイルだけ。残りは各行の[接続を確認]
|
|
19889
|
+
var refs = refsNow().slice(0, kind === "figma" ? 2 : 20);
|
|
19890
|
+
for (var i = 0; i < refs.length; i++) {
|
|
19891
|
+
// 無応答で札が「確認中」のまま固まらないよう、1 本ごとに 15 秒で見切る
|
|
19892
|
+
var ctrl = typeof AbortController === "function" ? new AbortController() : null;
|
|
19893
|
+
var giveUp = ctrl ? setTimeout(function () { ctrl.abort(); }, 15000) : null;
|
|
19894
|
+
try {
|
|
19895
|
+
var res = await callIntake("probe", { type: type, ref: refs[i] }, ctrl ? { signal: ctrl.signal } : undefined);
|
|
19896
|
+
var j = await res.json().catch(function () { return {}; });
|
|
19897
|
+
if (giveUp != null) clearTimeout(giveUp);
|
|
19898
|
+
if (res.ok && j.gate) {
|
|
19899
|
+
applyProbeResult(cap, refs[i], "", { gate: j.gate, checkedAt: j.checkedAt, needed: "", detail: j.detail || "" });
|
|
19900
|
+
} else if (!res.ok) {
|
|
19901
|
+
return "接続の確認はできませんでした:" + ((j && j.message) || "少し待ってからもう一度お試しください。");
|
|
19902
|
+
} else if (j.reason === "ip-restricted") {
|
|
19903
|
+
// 原因が分かる応答は、固定文ではなく原因の文を出す。[切り替える]は呼び出し側が添える
|
|
19904
|
+
ipReason = true;
|
|
19905
|
+
return j.message || "この場では確認できませんでした(IP 制限の可能性)。";
|
|
19906
|
+
} else {
|
|
19907
|
+
return "接続の確認は少し後に札へ出ます。";
|
|
19908
|
+
}
|
|
19909
|
+
} catch (e) {
|
|
19910
|
+
if (giveUp != null) clearTimeout(giveUp);
|
|
19911
|
+
return "接続の確認は通信に失敗しました。";
|
|
19912
|
+
}
|
|
19913
|
+
}
|
|
19914
|
+
return "";
|
|
19915
|
+
}
|
|
19915
19916
|
|
|
19916
19917
|
btn.addEventListener("click", async function () {
|
|
19917
19918
|
var value = input.value;
|
|
19918
|
-
if (!value.trim()) {
|
|
19919
|
+
if (!value.trim()) {
|
|
19920
|
+
msg.className = "ds-toggle-msg";
|
|
19921
|
+
// 登録済みで空のまま押しても何も変えない(置き換えるのは、貼ったときだけ)
|
|
19922
|
+
msg.textContent = secretNow().known === "yes" ? "何も変えていません。入れ直すときだけ値を貼ってください。" : "";
|
|
19923
|
+
if (secretNow().known !== "yes") { msg.className = "ds-toggle-msg is-error"; msg.textContent = "⚠ トークンを入力してください。"; }
|
|
19924
|
+
return;
|
|
19925
|
+
}
|
|
19919
19926
|
|
|
19920
|
-
//
|
|
19927
|
+
// 保存〜確認の全体を 1 回の busy で囲む(#222・beginBusy の項)
|
|
19921
19928
|
var endBusy = beginBusy(btn);
|
|
19922
19929
|
msg.className = "ds-toggle-msg";
|
|
19923
19930
|
msg.textContent = "保存中…";
|
|
19924
19931
|
var intake = SITE.intake;
|
|
19925
19932
|
try {
|
|
19926
19933
|
// **シークレット名は送らない。** どの連携かだけを送り、書き込み先はサーバが案件から決める。
|
|
19927
|
-
//
|
|
19928
|
-
// こちらが渡すのは「どのスペースの鍵か」という材料だけ。
|
|
19929
|
-
// **押した時点で読む。** 組み立て時に固めると、接続先を登録した直後に
|
|
19930
|
-
// 貼った鍵が「スペースを特定できません」で断られる
|
|
19934
|
+
// **押した時点で読む。** 組み立て時に固めると、接続先を登録した直後に貼った鍵が「スペースを特定できません」で断られる
|
|
19931
19935
|
var res = await callIntake("secret", secretPayload(intake, kind, value, cardSpace));
|
|
19932
19936
|
var j = await res.json().catch(function () { return {}; });
|
|
19933
19937
|
if (!res.ok) {
|
|
@@ -19937,30 +19941,39 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19937
19941
|
return;
|
|
19938
19942
|
}
|
|
19939
19943
|
msg.className = "ds-toggle-msg is-ok";
|
|
19940
|
-
// 🔴 **「保存中…」を消してから成功を書く(#220)。**
|
|
19941
|
-
// 画面に「保存中…✓ 保存しました。同期を開始しました。」と**2つの状態が同居**して
|
|
19942
|
-
// いた。appendChild は足すだけなので、消す一文が要る(sendConfig 側には在った)。
|
|
19943
|
-
// **語を書く前に必ずここを通すこと**——次に文面を足す人が同じ形で踏む
|
|
19944
|
+
// 🔴 **「保存中…」を消してから成功を書く(#220)。** appendChild は足すだけなので、消す一文が要る
|
|
19944
19945
|
msg.textContent = "";
|
|
19945
19946
|
msg.appendChild(document.createTextNode("✓ " + (j.message || "保存しました。")));
|
|
19946
|
-
// 起動できたときだけ、実行状況への導線を出す(鍵を入れた直後に効いたか確かめられる)
|
|
19947
19947
|
if (j.runsUrl) {
|
|
19948
19948
|
msg.appendChild(document.createTextNode(" "));
|
|
19949
19949
|
msg.appendChild(el("a", { href: j.runUrl || j.runsUrl, target: "_blank", rel: "noopener", title: "GitHub Actions の実行ログを開きます(プロジェクトリポジトリへのアクセスが要ります)", text: "実行状況を見る →" })); // その run を特定できていればそれ、無ければ一覧
|
|
19950
19950
|
}
|
|
19951
19951
|
// 入れた値は画面に残さない(肩越しに見えるのを防ぐ)
|
|
19952
19952
|
input.value = "";
|
|
19953
|
-
|
|
19954
|
-
|
|
19955
|
-
|
|
19956
|
-
|
|
19957
|
-
|
|
19958
|
-
|
|
19953
|
+
ent.savedHere = true;
|
|
19954
|
+
var willCheck = probeOk() && refsNow().length > 0;
|
|
19955
|
+
ent.checking = willCheck;
|
|
19956
|
+
paint();
|
|
19957
|
+
// 🔴 Backlog の行の一手は登録状況の正本に合わせて当て直す。正本(secretsNow)は取り直しで届く
|
|
19958
|
+
if (compact && typeof BACKLOG_UI.repaintRows === "function") BACKLOG_UI.repaintRows();
|
|
19959
|
+
if (willCheck) {
|
|
19960
|
+
var note = await checkAfterSave();
|
|
19961
|
+
if (note) msg.appendChild(document.createTextNode(" " + note));
|
|
19962
|
+
if (ipReason) appendBacklogProbeSwitch(msg, cap, { reason: "ip-restricted" });
|
|
19959
19963
|
}
|
|
19964
|
+
ent.checking = false;
|
|
19965
|
+
endBusy();
|
|
19966
|
+
paint();
|
|
19967
|
+
loadLiveFleet(true);
|
|
19960
19968
|
} catch (e) {
|
|
19961
|
-
|
|
19962
|
-
|
|
19969
|
+
ent.checking = false;
|
|
19970
|
+
// 保存が済んだあとの不調を「通信に失敗」と言わない(貼り直しに誘導しない)
|
|
19971
|
+
if (!ent.savedHere) {
|
|
19972
|
+
msg.className = "ds-toggle-msg is-error";
|
|
19973
|
+
msg.textContent = "✗ 通信に失敗しました。";
|
|
19974
|
+
}
|
|
19963
19975
|
endBusy();
|
|
19976
|
+
paint();
|
|
19964
19977
|
}
|
|
19965
19978
|
});
|
|
19966
19979
|
|
|
@@ -19972,21 +19985,17 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19972
19985
|
meta.note ? el("p", { class: "sec-how", text: meta.note }) : null,
|
|
19973
19986
|
meta.selfServe ? el("p", { class: "sec-how", text: meta.selfServe.note }) : null,
|
|
19974
19987
|
].filter(Boolean);
|
|
19975
|
-
// **「畳んである中に何があるか」を summary に書く。**
|
|
19976
|
-
// 発行のしかたを探している人がここを開く手掛かりを持てない(rt カードと同じ流儀)
|
|
19988
|
+
// **「畳んである中に何があるか」を summary に書く。**
|
|
19977
19989
|
var guidanceBox = el("details", { class: "sec-fold" }, [el("summary", { text: "発行のしかた" })]);
|
|
19978
19990
|
for (var gi = 0; gi < guidance.length; gi++) guidanceBox.appendChild(guidance[gi]);
|
|
19979
|
-
// **手順の動画+画像(#547・#1353)。**
|
|
19980
|
-
// meta.guide を持つ種別(Figma)はカルーセル1つに乗せる。meta.guide も meta.shots も
|
|
19981
|
-
// 持たない種別(Backlog)ではこの節は素通りする
|
|
19991
|
+
// **手順の動画+画像(#547・#1353)。** meta.guide を持つ種別(Figma)はカルーセル1つに乗せる
|
|
19982
19992
|
if (meta.guide && meta.guideInModal) {
|
|
19983
19993
|
// モーダルの上に出している種別(Backlog・Figma)は、ここには重ねない
|
|
19984
19994
|
} else if (meta.guide) {
|
|
19985
19995
|
var carousel = buildGuideCarousel(kind, meta.guide);
|
|
19986
19996
|
if (carousel) guidanceBox.appendChild(carousel);
|
|
19987
19997
|
} else if (meta.shots) {
|
|
19988
|
-
//
|
|
19989
|
-
// この口に載せ替えるまでの踏み板として残す
|
|
19998
|
+
// 後方互換(旧形)
|
|
19990
19999
|
for (var si = 0; si < meta.shots.length; si++) {
|
|
19991
20000
|
var shot = meta.shots[si];
|
|
19992
20001
|
guidanceBox.appendChild(el("p", { class: "sec-how", text: shot.heading }));
|
|
@@ -19994,86 +20003,33 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19994
20003
|
}
|
|
19995
20004
|
}
|
|
19996
20005
|
|
|
19997
|
-
//
|
|
19998
|
-
//
|
|
19999
|
-
//
|
|
20000
|
-
// 🔴 **前回とは向きが逆。** 前回は「.sec-input は畳まない」と決めていたが、
|
|
20001
|
-
// 鍵の欄がレコードの行の下へ移り、**行に常時ぶら下がる入力欄**になったため、
|
|
20002
|
-
// 一覧の見通しを取り戻す側へ倒した。**状態(.sec-state)は畳まない**ので、
|
|
20003
|
-
// 「保存したのに反映されていない」は開かなくても読める。
|
|
20004
|
-
//
|
|
20005
|
-
// ⚠ **DOM には常に置く**(押すまで生成しない作りにしない)。ライブ差し替えは
|
|
20006
|
-
// input のノードを直接触るし、テストも card.querySelector("input.sec-input") で掴む。
|
|
20007
|
-
// ⚠ **<summary> は button ではない**ので、「保存」を掴む既存の取り方は変わらない。
|
|
20008
|
-
var inputFold = el("details", { class: "sec-input-fold" }, [
|
|
20009
|
-
// Backlog の行の中のカードは、一手の語([入れる]・[入れ直す])と揃える。Figma は「登録する」のまま
|
|
20010
|
-
el("summary", { class: "sec-input-summary", text: st.known === "yes" ? "入れ直す" : (compact ? "入れる" : "登録する") }),
|
|
20011
|
-
]);
|
|
20012
|
-
inputFold.appendChild(input);
|
|
20013
|
-
inputFold.appendChild(el("div", { class: "ds-toggle" }, [btn, msg]));
|
|
20014
|
-
// 🔴 **値の扱いの 1 文は、開いた中に残す**(顧客に鍵の貼り付けを求める画面でいちばん落としてはいけない説明・#101)。
|
|
20015
|
-
// 短くした版(行の中のカード)。「他のプロジェクトには影響しません」は仕組みの事実で、利用者が選ぶものではないので外す
|
|
20016
|
-
if (compact) inputFold.appendChild(el("p", { class: "sec-note", text: "入れた値は保存だけでき、あとから表示されません。" }));
|
|
20017
|
-
|
|
20018
|
-
// ライブ取得後に状態の行だけを差し替えるための目印(カードごと作り直すと入力が消える)
|
|
20019
|
-
//
|
|
20020
|
-
// **並びは「状態 → 貼る(畳む) → 畳んだ手順」。**
|
|
20021
|
-
//
|
|
20022
|
-
// 🔴 **.sec-state / .sec-preferred は <details> の外に置くこと。**
|
|
20023
|
-
// - .sec-state … 保存したのに反映されていない状態が分かる唯一の手段。
|
|
20024
|
-
// 押すまで見えないと成立しない
|
|
20025
|
-
// - .sec-preferred … 「誰のアカウントで発行するのか」を**手順より先に**伝える行。
|
|
20026
|
-
// 未登録のときだけ出る=これから貼る人にだけ出るので、畳むと存在理由が消える
|
|
20006
|
+
// 🔴 **.sec-state / .sec-preferred は常に見える場所に置く。** 札は「保存したのに反映されていない」が分かる唯一の手段。
|
|
20007
|
+
// .sec-preferred は「誰のアカウントで発行するのか」を手順より先に伝える行(未登録のときだけ出る)
|
|
20027
20008
|
var preferred = meta.selfServe ? el("p", { class: "sec-preferred", text: meta.selfServe.text }) : null;
|
|
20028
20009
|
var card = el("div", { class: "ops-card" + (inRow ? " ds-keycard" : ""), "data-secret-kind": kind }, [
|
|
20029
|
-
// 行の中の Backlog
|
|
20010
|
+
// 行の中の Backlog カードは見出しを持たない(何の鍵かは札と欄が言う)
|
|
20030
20011
|
compact ? null : el("div", { class: "ops-card-head" }, [
|
|
20031
20012
|
el("span", { class: "ops-card-icon", text: meta.icon }),
|
|
20032
20013
|
el("h3", { class: "ops-card-title", text: cardTitle }),
|
|
20033
20014
|
]),
|
|
20034
|
-
// **desc は無い種別がある(2026-08-21)。** el() は text をそのまま textContent へ
|
|
20035
|
-
// 代入するので、無条件に出すと画面に文字列 undefined が出る
|
|
20036
20015
|
meta.desc ? el("p", { class: "ops-card-desc", text: meta.desc }) : null,
|
|
20037
|
-
// **鍵の効く範囲は、登録状況より先に言う。**
|
|
20038
|
-
// 「どのファイルの話か」を確かめ直すことになる(#229)
|
|
20016
|
+
// **鍵の効く範囲は、登録状況より先に言う。** (#229)
|
|
20039
20017
|
scopeNote ? el("p", { class: "sec-scope", text: scopeNote }) : null,
|
|
20040
20018
|
state,
|
|
20041
|
-
|
|
20042
|
-
|
|
20043
|
-
|
|
20044
|
-
|
|
20045
|
-
|
|
20019
|
+
input,
|
|
20020
|
+
el("div", { class: "ds-toggle" }, [btn, msg]),
|
|
20021
|
+
savedNote,
|
|
20022
|
+
// 🔴 **値の扱いの 1 文は常に出す**(顧客に鍵の貼り付けを求める画面でいちばん落としてはいけない説明・#101)
|
|
20023
|
+
el("p", { class: "sec-note", text: compact
|
|
20024
|
+
? "入れた値は保存だけでき、あとから表示されません。"
|
|
20025
|
+
: "入れた値はここには表示されません(保存だけできます)。保存先はプロジェクトごとに分かれているので、他のプロジェクトには影響しません。" }),
|
|
20046
20026
|
guidanceBox,
|
|
20047
|
-
// **扱いの説明はカードに持たせる。** 節の見出しの下に置いていたときは、
|
|
20048
|
-
// #101 でカードだけがモーダルへ移り、説明だけが画面から消えた。
|
|
20049
|
-
// 顧客にトークンの貼り付けを求める画面で、貼った値がどう扱われるかの
|
|
20050
|
-
// 説明が落ちるのは、いちばん落としてはいけない種類の欠落
|
|
20051
|
-
// 行の中の Backlog カードは、同じ 1 文を開いた中(上の inputFold)に短くして持つ
|
|
20052
|
-
compact ? null : el("p", { class: "sec-note", text: "入れた値はここには表示されません(保存だけできます)。保存先はプロジェクトごとに分かれているので、他のプロジェクトには影響しません。" }),
|
|
20053
20027
|
]);
|
|
20054
|
-
|
|
20055
|
-
|
|
20056
|
-
|
|
20057
|
-
//
|
|
20058
|
-
|
|
20059
|
-
// fold/input/msg=触り始めたかの判定と、入力への移動・refresh=見せる瞬間の状態の当て直し
|
|
20060
|
-
var entry = { kind: kind, el: card, compact: compact, space: stateSpace, forced: false, fold: inputFold, input: input, msg: msg };
|
|
20061
|
-
if (compact) {
|
|
20062
|
-
entry.refresh = function () {
|
|
20063
|
-
// 作ったときの答えは古いことがある(取り直しが後から届く)。見せる瞬間に状態の行と summary と
|
|
20064
|
-
// 「自分で繋げばよい」の 1 行を当て直す(入れた直後に前の答えのまま出さない・#227)
|
|
20065
|
-
var now = secretStateOf(kind, stateSpace, backlogDomainsNow().length);
|
|
20066
|
-
applySecretState(state, now);
|
|
20067
|
-
var sum = inputFold.querySelector(".sec-input-summary");
|
|
20068
|
-
if (sum) sum.textContent = now.known === "yes" ? "入れ直す" : "入れる";
|
|
20069
|
-
if (preferred) {
|
|
20070
|
-
var want = now.known === "no";
|
|
20071
|
-
if (want && !preferred.parentNode) card.insertBefore(preferred, inputFold);
|
|
20072
|
-
else if (!want && preferred.parentNode) preferred.parentNode.removeChild(preferred);
|
|
20073
|
-
}
|
|
20074
|
-
};
|
|
20075
|
-
}
|
|
20076
|
-
KEY_CARDS.push(entry);
|
|
20028
|
+
ent.el = card;
|
|
20029
|
+
ent.refresh = paint;
|
|
20030
|
+
paint();
|
|
20031
|
+
// **作った鍵カードは1枚残らずここに載せる。** 出し入れ(接続先が0件のときに畳む)は DOM 検索ではなくこの控えで回す
|
|
20032
|
+
KEY_CARDS.push(ent);
|
|
20077
20033
|
return card;
|
|
20078
20034
|
}
|
|
20079
20035
|
|
package/package.json
CHANGED