@takagaki/cortex-decisions-viewer 0.12.214 → 0.12.215
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 +201 -262
- 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
|
};
|
|
@@ -11109,24 +11096,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
11109
11096
|
return wrap;
|
|
11110
11097
|
}
|
|
11111
11098
|
|
|
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
11099
|
/** 台帳から、そのワークスペースの接続状態を引く(無ければ null=断定しない) */
|
|
11131
11100
|
function tokenStateOf(workspaces, teamId) {
|
|
11132
11101
|
var list = workspaces || [];
|
|
@@ -12425,32 +12394,15 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
12425
12394
|
// **対応表に無い種別は隠さない**(keyTargetCount の既定と同じく出す側に倒す)。
|
|
12426
12395
|
// 3つ目の鍵が足されて分岐を書き忘れた場合は key-card-visibility の [全種0件] が落ちる
|
|
12427
12396
|
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
12397
|
KEY_CARDS[i].el.hidden = hide;
|
|
12432
|
-
|
|
12398
|
+
// 🔴 札は見せる瞬間に当て直す(作ったときの答えは古いことがある。取り直しが後から届く・#227)
|
|
12399
|
+
if (!hide && KEY_CARDS[i].refresh) KEY_CARDS[i].refresh();
|
|
12433
12400
|
}
|
|
12434
12401
|
eachKeySlot(function (slot) {
|
|
12435
12402
|
slot.hidden = !slot.querySelector("[data-secret-kind]:not([hidden])");
|
|
12436
12403
|
});
|
|
12437
12404
|
}
|
|
12438
12405
|
|
|
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
12406
|
/** いま在る鍵の受け皿(.ds-keyrow)を順に渡す。置き場の正本は KEY_SLOTS */
|
|
12455
12407
|
function eachKeySlot(fn) {
|
|
12456
12408
|
var slots = KEY_SLOTS.backlog || {};
|
|
@@ -13046,6 +12998,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
13046
12998
|
KEY_CARDS = [];
|
|
13047
12999
|
// Backlog の節の行の控え・結果の帯・描き直しの口も作り直す(切り離された古い節を掴んだままにしない)
|
|
13048
13000
|
BACKLOG_UI = { rows: [], msg: null, repaintRows: null };
|
|
13001
|
+
FIGMA_UI = { keys: [] };
|
|
13049
13002
|
// 作り直しはスナップショットから描き直すこと。応答で採った件数はここで捨てる
|
|
13050
13003
|
ADOPTED_TARGET_COUNT = null;
|
|
13051
13004
|
var internals = fleetVal("internalSources") || [];
|
|
@@ -14501,6 +14454,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
14501
14454
|
MERGED = null;
|
|
14502
14455
|
repaintOpenLists();
|
|
14503
14456
|
refreshDataSources();
|
|
14457
|
+
syncKeyCardVisibility(); // 鍵の札(接続OK/失敗)も同じ結果で当て直す
|
|
14504
14458
|
}
|
|
14505
14459
|
// 本物の行を 1 回だけ取りに行く(据え置きのまま・「reloadLiveState」の項)
|
|
14506
14460
|
reloadLiveState();
|
|
@@ -15452,7 +15406,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15452
15406
|
}
|
|
15453
15407
|
var ipLabel = ip ? "固定の送信元 IP(" + ip + ")" : "固定の送信元 IP";
|
|
15454
15408
|
if (keyState === "no") {
|
|
15455
|
-
return "同期は" + ipLabel + "から行います。お客様にこの IP
|
|
15409
|
+
return "同期は" + ipLabel + "から行います。お客様にこの IP の許可を依頼し、接続先の行の下の欄に API キーを貼って[保存して接続を確認]を押すと同期が始まります。";
|
|
15456
15410
|
}
|
|
15457
15411
|
// 2 文に収める(実装レビューの指摘)。押した直後の帯(サーバの文面)も「許可を依頼」を言うが、
|
|
15458
15412
|
// 帯は数秒で読み終える結果で、この行は次に開いたときも残る状態——役目が違うので両方に置く
|
|
@@ -15551,7 +15505,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15551
15505
|
* 部品の置き場:
|
|
15552
15506
|
* - 一手 … DS_GATE_RESTING_HELP.backlog → backlogRowHelpParts(行の中身で決まる)
|
|
15553
15507
|
* - キーの欄 … これまでと同じスペースごとの受け皿(KEY_SLOTS.backlog・#223)に同じカード。
|
|
15554
|
-
* 変えるのは見え方だけ(syncKeyCardVisibility
|
|
15508
|
+
* 変えるのは見え方だけ(syncKeyCardVisibility)
|
|
15555
15509
|
* - 同期経路の切り替え … setBacklogRoute に 1 本化。入口はタイルの一手・[接続を確認]の結果・「その他」のスイッチ
|
|
15556
15510
|
* - 札(事実)… 経路札「固定 IP 経由」・リアルタイム札(appendBacklogChips)
|
|
15557
15511
|
* ------------------------------------------------------------------------- */
|
|
@@ -15562,6 +15516,8 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15562
15516
|
* 🔴 **鍵の置き場の正本は KEY_SLOTS。ここは行の控えだけ**(#223 の「節の中に受け皿の控えを持たない」は守る)。
|
|
15563
15517
|
*/
|
|
15564
15518
|
var BACKLOG_UI = { rows: [], msg: null, repaintRows: null };
|
|
15519
|
+
/** Figma の鍵が効くファイル(鍵カードの札が引く。一覧を描くときに入れ替える) */
|
|
15520
|
+
var FIGMA_UI = { keys: [] };
|
|
15565
15521
|
|
|
15566
15522
|
/** いま見えている行のスペース(小文字・重複なし) */
|
|
15567
15523
|
function backlogDomainsNow() {
|
|
@@ -15614,27 +15570,13 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15614
15570
|
return false;
|
|
15615
15571
|
}
|
|
15616
15572
|
|
|
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
15573
|
/**
|
|
15632
15574
|
* Backlog の行に出す一手のパーツ(無ければ null)。**スペースをまたがない**(ボタンはその行のスペースの受け皿だけを引く)。
|
|
15633
15575
|
*
|
|
15634
|
-
* キーが要る → 「API
|
|
15635
|
-
* 読めない・通常経路 →
|
|
15636
|
-
* 読めない・固定 IP → 「お客様に固定の送信元 IP(…)の許可を依頼してください。[コピー]
|
|
15637
|
-
* 読めない・経路不明 →
|
|
15576
|
+
* キーが要る → 「API キーを、下の欄に入れてください。」(複数スペースならスペース名つき)
|
|
15577
|
+
* 読めない・通常経路 → 「読めません。下の欄に API キーを入れ直してください。 Backlog に IP 制限があるなら、固定 IP 経由で読んでください。[切り替える]」
|
|
15578
|
+
* 読めない・固定 IP → 「お客様に固定の送信元 IP(…)の許可を依頼してください。[コピー] 許可済みなら、下の欄に API キーを入れ直してください。」
|
|
15579
|
+
* 読めない・経路不明 → 「読めません。下の欄に API キーを入れ直してください。」(切り替えが押せるか分からないので[切り替える]は出さない)
|
|
15638
15580
|
*
|
|
15639
15581
|
* 🔴 **理由の語(HTTP の番号等)には依存しない。** 401・403・404 は画面から見分けられないので、読めない行は広い方の 1 行。
|
|
15640
15582
|
* IP 制限と確定できるのは[接続を確認]の応答の reason だけ(appendBacklogProbeSwitch)。
|
|
@@ -15646,10 +15588,10 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15646
15588
|
var dom = String(row.domain || "").toLowerCase();
|
|
15647
15589
|
var multi = backlogDomainsNow().length > 1;
|
|
15648
15590
|
if (backlogKeyNeeded(dom, row.gate)) {
|
|
15649
|
-
|
|
15591
|
+
// 🔴 鍵の欄は接続先の行の中に最初から見えている(便 KU)。ここは指す文だけでボタンは置かない
|
|
15592
|
+
return [(multi ? dom + " の " : "") + "API キーを、下の欄に入れてください。"];
|
|
15650
15593
|
}
|
|
15651
15594
|
if (row.gate !== "unreachable") return null;
|
|
15652
|
-
var reenter = { act: "backlog-key", space: dom, label: "入れ直す" };
|
|
15653
15595
|
var route = LIVE_BACKLOG_ROUTE;
|
|
15654
15596
|
if (route === "fixed-ip") {
|
|
15655
15597
|
// IP が取れていなければ IP も[コピー]も出さない(嘘の値を書かない・#516)
|
|
@@ -15657,9 +15599,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15657
15599
|
var head = ip
|
|
15658
15600
|
? ["お客様に固定の送信元 IP(" + ip + ")の許可を依頼してください。", { copy: ip, bare: true }]
|
|
15659
15601
|
: ["お客様に固定の送信元 IP の許可を依頼してください。"];
|
|
15660
|
-
return head.concat(["
|
|
15602
|
+
return head.concat([" 許可済みなら、下の欄に API キーを入れ直してください。"]);
|
|
15661
15603
|
}
|
|
15662
|
-
var base = ["
|
|
15604
|
+
var base = ["読めません。下の欄に API キーを入れ直してください。"];
|
|
15663
15605
|
if (route === "runner") {
|
|
15664
15606
|
// 切り替えは案件全体の経路(スペースごとではない)。複数スペースでは強めに言う
|
|
15665
15607
|
var scope = multi
|
|
@@ -15690,54 +15632,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15690
15632
|
return appendReachableReason(row, "issues", ref);
|
|
15691
15633
|
}
|
|
15692
15634
|
|
|
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
15635
|
/**
|
|
15742
15636
|
* 同期経路の切り替え(固定 IP 経由 ⇄ 通常)。**スイッチ(「その他」)とタイルの[切り替える]が同じこの関数を呼ぶ**
|
|
15743
15637
|
* ——操作を 2 本書かない(op・値・確認なし・応答の route を正とする・changed:false の取り直しは 1 つだけ持つ)。
|
|
@@ -16881,7 +16775,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16881
16775
|
// 🔴 **追加の欄は URL の入力と[追加]だけ(c-07 の 2 本目)。** 手順の文は置かない(hint を渡さない)。
|
|
16882
16776
|
// 外した情報の行き先:
|
|
16883
16777
|
// - 「起票先は変わりません」「毎晩同期します」「外すには」… 上部の説明文(openCapabilityModal)
|
|
16884
|
-
// - 「スペースごとに別のAPIキー」…
|
|
16778
|
+
// - 「スペースごとに別のAPIキー」… 足した行の中のスペースごとの鍵の欄(札つき)
|
|
16885
16779
|
// - 「専用 URL の登録が要ります」… 追加した行のリアルタイム札(未受信)と、一覧の下の一手[設定する]
|
|
16886
16780
|
build: function (url) {
|
|
16887
16781
|
return { op: "backlog-target-add", url: url, baseGeneration: targetsGenerationOf(targets) };
|
|
@@ -16940,21 +16834,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16940
16834
|
box.appendChild(rtBox);
|
|
16941
16835
|
|
|
16942
16836
|
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
16837
|
var rtMore = liveList("backlog-realtime-more", function () {
|
|
16959
16838
|
var st = backlogRealtimeState();
|
|
16960
16839
|
return JSON.stringify([st ? [st.total, st.live] : null, backlogFactsSigOf()]);
|
|
@@ -16970,7 +16849,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16970
16849
|
moreEl = el("details", { class: "ds-more" }, [
|
|
16971
16850
|
el("summary", { text: "その他" }),
|
|
16972
16851
|
routeWrap,
|
|
16973
|
-
keyRows,
|
|
16974
16852
|
rtMore,
|
|
16975
16853
|
]);
|
|
16976
16854
|
box.appendChild(moreEl);
|
|
@@ -16984,7 +16862,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16984
16862
|
moreEl.hidden = !(keyTargetCount("課題管理") > 0 || LIVE_BACKLOG_ROUTE === "fixed-ip");
|
|
16985
16863
|
rtBox.__rebuild();
|
|
16986
16864
|
if (routeWrap.__live) routeWrap.__live.__rebuild();
|
|
16987
|
-
keyRows.__rebuild();
|
|
16988
16865
|
rtMore.__rebuild();
|
|
16989
16866
|
}
|
|
16990
16867
|
}
|
|
@@ -17328,6 +17205,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
17328
17205
|
// サーバが削除を認めた印なので、ここから先に同じ鍵が現れたら**貼り直された別の登録**
|
|
17329
17206
|
var figKeys = figs.map(function (f) { return f.key; });
|
|
17330
17207
|
figsRemoved = figsRemoved.filter(function (k) { return figKeys.indexOf(k) >= 0; });
|
|
17208
|
+
FIGMA_UI.keys = figKeys.filter(function (k) { return figsRemoved.indexOf(k) < 0; });
|
|
17331
17209
|
// **残り件数は「押した時点」で数える。** 一覧(figs)は夜間バッチのスナップショットで、
|
|
17332
17210
|
// このページを開いている間はもちろん、その日のうちに再読み込みしても更新されない。
|
|
17333
17211
|
// 描画時点の件数で判定すると、3件を1件ずつ外していったとき最後の1件でも警告が出ない。
|
|
@@ -19875,9 +19753,8 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19875
19753
|
var stateSpace = (opts && opts.stateSpace) || "";
|
|
19876
19754
|
var spaceCount = (opts && opts.spaceCount) || 0;
|
|
19877
19755
|
var inRow = !!(opts && opts.inRow);
|
|
19878
|
-
// 🔴 **Backlog
|
|
19879
|
-
//
|
|
19880
|
-
// 触り始めた後だけ見える(syncKeyCardVisibility)。旧カード(行の外・intake 無しの案件)と Figma は従来どおり。
|
|
19756
|
+
// 🔴 **Backlog の行の中のカードは見出しを持たない**(行の中なので「何の鍵か」は札と欄が言う)。
|
|
19757
|
+
// 接続先が 1 件以上あるあいだは常に見える(0 件のときだけ syncKeyCardVisibility が畳む)。
|
|
19881
19758
|
var compact = kind === "backlog" && inRow;
|
|
19882
19759
|
/**
|
|
19883
19760
|
* 鍵がどこまで効くのか(#229)。**置き場所だけでは伝わらないので、言葉にする。**
|
|
@@ -19892,11 +19769,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19892
19769
|
// **いま登録されているか**を先に出す。入れ直したのに反映されていない状態が
|
|
19893
19770
|
// 画面で分かるようにする(接続状況は夜間バッチのスナップショットなので、
|
|
19894
19771
|
// 保存の直後は前日の値のまま。時刻は上の節に出している)。
|
|
19895
|
-
var st = secretStateOf(kind, stateSpace, spaceCount);
|
|
19896
19772
|
var cardTitle = meta.title;
|
|
19897
|
-
// 🔴 **「登録済み」は「読めている」を意味しない。**
|
|
19898
|
-
//
|
|
19899
|
-
//(同期できているかのバッジは、夜間処理が接続先ごとの成否を保存してからの別作業)。
|
|
19773
|
+
// 🔴 **「登録済み」は「読めている」を意味しない。** 「接続OK」を札に出してよいのは、そのスペース(Figma は全ファイル)の
|
|
19774
|
+
// 行の「届くか」がすべて ok のときだけ(statusOf)。測っていなければ「登録済み」止まり。
|
|
19900
19775
|
//
|
|
19901
19776
|
// **前方一致で見る。** #105 の移行期は「Secrets Manager(旧名)」も来る。
|
|
19902
19777
|
// 完全一致にすると、旧名で動いている案件だけが repo secret と同じ見た目になり、
|
|
@@ -19907,27 +19782,140 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19907
19782
|
// 同じ 1 語にし、**生の値は data-src に置く**(判定の is-managed は生の値のまま)。
|
|
19908
19783
|
// 知らない値が来ても生で出さない——project-wording.test.mjs が画面の語を見張る
|
|
19909
19784
|
var state = el("p", { class: "sec-state" });
|
|
19910
|
-
|
|
19911
|
-
|
|
19912
|
-
|
|
19785
|
+
// 🔴 **鍵の窓は 1 か所・欄は最初から見えている・ボタンは 1 つ(便 KU)。** 以前は[入れる]で開く畳み+[保存]+別の[接続を確認]の 3 段で、
|
|
19786
|
+
// 同じ鍵の[入れる]が行の一手・「その他」・畳みの 3 か所にあった。いまは 状態の札 → 伏せ字の欄(空のまま)→ [保存して接続を確認]。
|
|
19787
|
+
// 保存した値は読み戻さない(書き込み専用)。登録済みでも欄は空で、入れ直すときだけ貼る(伏せ字を欄に入れて伏せ字ごと保存する事故を避ける)
|
|
19788
|
+
var cap = kind === "backlog" ? "issues" : "design";
|
|
19789
|
+
var input = el("input", { class: "sec-input", type: "password", placeholder: "トークンを貼り付け", autocomplete: "off", spellcheck: "false" });
|
|
19913
19790
|
var btn = el("button", { class: "ds-toggle-btn", type: "button", text: "保存" });
|
|
19914
19791
|
var msg = el("div", { class: "ds-toggle-msg" });
|
|
19792
|
+
var savedNote = el("p", { class: "sec-note sec-saved" });
|
|
19793
|
+
// 札が読む材料の控え。checking=保存〜確認の最中、savedHere=この画面で保存した(正本 secretsNow は最大 10 秒古い答えを返すので、registered を返すまで「登録済み」以上に固定する)
|
|
19794
|
+
var ent = { kind: kind, el: null, compact: compact, space: stateSpace, input: input, msg: msg, checking: false, savedHere: false };
|
|
19795
|
+
|
|
19796
|
+
function spaceCountNow() { return kind === "backlog" ? backlogDomainsNow().length : spaceCount; }
|
|
19797
|
+
/** この鍵が効く接続先の ref(Backlog=そのスペースの行・Figma=一覧のファイル)。登録済みの一覧だけを引く=孤児の行を混ぜない */
|
|
19798
|
+
function refsNow() {
|
|
19799
|
+
var out = [];
|
|
19800
|
+
if (kind === "backlog") {
|
|
19801
|
+
var ds = backlogDomainsNow();
|
|
19802
|
+
var dom = stateSpace || (ds.length === 1 ? ds[0] : "");
|
|
19803
|
+
var rows = BACKLOG_UI.rows || [];
|
|
19804
|
+
for (var i = 0; i < rows.length; i++) {
|
|
19805
|
+
if (dom && String(rows[i].domain || "").toLowerCase() === dom) out.push(issuesRefOf(rows[i].domain, rows[i].projectKey));
|
|
19806
|
+
}
|
|
19807
|
+
} else {
|
|
19808
|
+
out = (FIGMA_UI.keys || []).slice();
|
|
19809
|
+
}
|
|
19810
|
+
return out;
|
|
19811
|
+
}
|
|
19812
|
+
/** 接続の確認の口があるか。組み直した案件(表)も同じ口(受付 op=probe の direct・同期を起こさずその場で 1 本叩く)で確かめる */
|
|
19813
|
+
function probeOk() { return !!SITE.intake && !!dispatchProbeTypeOf(cap); }
|
|
19814
|
+
/** 「M/D に保存」。受付の savedAt(Secrets Manager の LastChangedDate)から出す。ブラウザには覚えない(端末が変わると消えるため) */
|
|
19815
|
+
function savedDate(st) {
|
|
19816
|
+
var d = st && st.savedAt ? new Date(st.savedAt) : null;
|
|
19817
|
+
return d && !isNaN(d.getTime()) ? (d.getMonth() + 1) + "/" + d.getDate() : "";
|
|
19818
|
+
}
|
|
19819
|
+
function secretNow() {
|
|
19820
|
+
var s = secretStateOf(kind, stateSpace, spaceCountNow());
|
|
19821
|
+
if (ent.savedHere) {
|
|
19822
|
+
if (s.known === "yes") ent.savedHere = false; // 正本が追いついた
|
|
19823
|
+
else return { known: "yes", src: "" };
|
|
19824
|
+
}
|
|
19825
|
+
return s;
|
|
19826
|
+
}
|
|
19827
|
+
/**
|
|
19828
|
+
* 札 1 つの決め方。**未登録/確認中/接続OK〈時刻〉/失敗〈理由の一言〉/登録済み**。
|
|
19829
|
+
* 「失敗」の一言は行の札の語(dsGateForCap)をそのまま使う。測っていない行・鍵が無かった頃の古い行(no_token)は数えず、
|
|
19830
|
+
* 一部だけ測れているときも「接続OK」と言い切らない(登録済みに倒す)。
|
|
19831
|
+
*/
|
|
19832
|
+
function statusOf(st) {
|
|
19833
|
+
if (ent.checking) return ["is-checking", "確認中"];
|
|
19834
|
+
if (st.known === "no") return ["is-none", "未登録"];
|
|
19835
|
+
if (st.known !== "yes") return ["is-unknown", "確認中"];
|
|
19836
|
+
var refs = refsNow(), bad = null, ok = 0, latest = "";
|
|
19837
|
+
for (var i = 0; i < refs.length; i++) {
|
|
19838
|
+
var r = reachableStateOf(cap, refs[i]);
|
|
19839
|
+
if (!r || r.status === "no_token") continue;
|
|
19840
|
+
if (r.status === "ok") { ok++; if (String(r.at || "") > latest) latest = String(r.at || ""); }
|
|
19841
|
+
else if (!bad) bad = r;
|
|
19842
|
+
}
|
|
19843
|
+
if (bad) return ["is-failed", "失敗(" + dsGateForCap(cap, bad.status).text + ")"];
|
|
19844
|
+
if (ok && ok === refs.length) {
|
|
19845
|
+
var t = dsFmtTime(latest);
|
|
19846
|
+
return ["is-ok", "接続OK" + (t ? "(" + t + ")" : "")];
|
|
19847
|
+
}
|
|
19848
|
+
return null; // 登録済み
|
|
19849
|
+
}
|
|
19850
|
+
function paint() {
|
|
19851
|
+
var st = secretNow();
|
|
19852
|
+
var s = statusOf(st);
|
|
19853
|
+
if (s) {
|
|
19854
|
+
// 取得元は札の語に関わらず data-src に置く(判定の is-managed は生の値の前方一致・#841)
|
|
19855
|
+
var srcRaw = st.known === "yes" ? (st.src || "") : "";
|
|
19856
|
+
state.className = "sec-state " + s[0] + (srcRaw.indexOf("Secrets Manager") === 0 ? " is-managed" : "");
|
|
19857
|
+
if (srcRaw) state.setAttribute("data-src", srcRaw); else state.removeAttribute("data-src");
|
|
19858
|
+
state.textContent = s[1];
|
|
19859
|
+
} else {
|
|
19860
|
+
applySecretState(state, st);
|
|
19861
|
+
}
|
|
19862
|
+
var reg = st.known === "yes";
|
|
19863
|
+
var d = savedDate(st);
|
|
19864
|
+
savedNote.hidden = !reg;
|
|
19865
|
+
savedNote.textContent = reg ? "登録済み" + (d ? "(" + d + " に保存)" : "") + "。入れ直すときだけ貼ってください" : "";
|
|
19866
|
+
if (!btn.disabled) btn.textContent = probeOk() ? "保存して接続を確認" : "保存";
|
|
19867
|
+
if (preferred) {
|
|
19868
|
+
var want = st.known === "no";
|
|
19869
|
+
if (want && !preferred.parentNode && card) card.insertBefore(preferred, input);
|
|
19870
|
+
else if (!want && preferred.parentNode) preferred.parentNode.removeChild(preferred);
|
|
19871
|
+
}
|
|
19872
|
+
}
|
|
19873
|
+
/** 保存のあとの接続の確認。結果は行と同じ形で置く(applyProbeResult)。返すのは添える 1 文(無ければ空) */
|
|
19874
|
+
async function checkAfterSave() {
|
|
19875
|
+
var type = dispatchProbeTypeOf(cap);
|
|
19876
|
+
// Figma は回数制限(1 分あたりの枠)に収まるよう先頭の 2 ファイルだけ。残りは各行の[接続を確認]
|
|
19877
|
+
var refs = refsNow().slice(0, kind === "figma" ? 2 : 20);
|
|
19878
|
+
for (var i = 0; i < refs.length; i++) {
|
|
19879
|
+
// 無応答で札が「確認中」のまま固まらないよう、1 本ごとに 15 秒で見切る
|
|
19880
|
+
var ctrl = typeof AbortController === "function" ? new AbortController() : null;
|
|
19881
|
+
var giveUp = ctrl ? setTimeout(function () { ctrl.abort(); }, 15000) : null;
|
|
19882
|
+
try {
|
|
19883
|
+
var res = await callIntake("probe", { type: type, ref: refs[i] }, ctrl ? { signal: ctrl.signal } : undefined);
|
|
19884
|
+
var j = await res.json().catch(function () { return {}; });
|
|
19885
|
+
if (giveUp != null) clearTimeout(giveUp);
|
|
19886
|
+
if (res.ok && j.gate) {
|
|
19887
|
+
applyProbeResult(cap, refs[i], "", { gate: j.gate, checkedAt: j.checkedAt, needed: "", detail: j.detail || "" });
|
|
19888
|
+
} else if (!res.ok) {
|
|
19889
|
+
return "接続の確認はできませんでした:" + ((j && j.message) || "少し待ってからもう一度お試しください。");
|
|
19890
|
+
} else {
|
|
19891
|
+
return "接続の確認は少し後に札へ出ます。";
|
|
19892
|
+
}
|
|
19893
|
+
} catch (e) {
|
|
19894
|
+
if (giveUp != null) clearTimeout(giveUp);
|
|
19895
|
+
return "接続の確認は通信に失敗しました。";
|
|
19896
|
+
}
|
|
19897
|
+
}
|
|
19898
|
+
return "";
|
|
19899
|
+
}
|
|
19915
19900
|
|
|
19916
19901
|
btn.addEventListener("click", async function () {
|
|
19917
19902
|
var value = input.value;
|
|
19918
|
-
if (!value.trim()) {
|
|
19903
|
+
if (!value.trim()) {
|
|
19904
|
+
msg.className = "ds-toggle-msg";
|
|
19905
|
+
// 登録済みで空のまま押しても何も変えない(置き換えるのは、貼ったときだけ)
|
|
19906
|
+
msg.textContent = secretNow().known === "yes" ? "何も変えていません。入れ直すときだけ値を貼ってください。" : "";
|
|
19907
|
+
if (secretNow().known !== "yes") { msg.className = "ds-toggle-msg is-error"; msg.textContent = "⚠ トークンを入力してください。"; }
|
|
19908
|
+
return;
|
|
19909
|
+
}
|
|
19919
19910
|
|
|
19920
|
-
//
|
|
19911
|
+
// 保存〜確認の全体を 1 回の busy で囲む(#222・beginBusy の項)
|
|
19921
19912
|
var endBusy = beginBusy(btn);
|
|
19922
19913
|
msg.className = "ds-toggle-msg";
|
|
19923
19914
|
msg.textContent = "保存中…";
|
|
19924
19915
|
var intake = SITE.intake;
|
|
19925
19916
|
try {
|
|
19926
19917
|
// **シークレット名は送らない。** どの連携かだけを送り、書き込み先はサーバが案件から決める。
|
|
19927
|
-
//
|
|
19928
|
-
// こちらが渡すのは「どのスペースの鍵か」という材料だけ。
|
|
19929
|
-
// **押した時点で読む。** 組み立て時に固めると、接続先を登録した直後に
|
|
19930
|
-
// 貼った鍵が「スペースを特定できません」で断られる
|
|
19918
|
+
// **押した時点で読む。** 組み立て時に固めると、接続先を登録した直後に貼った鍵が「スペースを特定できません」で断られる
|
|
19931
19919
|
var res = await callIntake("secret", secretPayload(intake, kind, value, cardSpace));
|
|
19932
19920
|
var j = await res.json().catch(function () { return {}; });
|
|
19933
19921
|
if (!res.ok) {
|
|
@@ -19937,30 +19925,38 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19937
19925
|
return;
|
|
19938
19926
|
}
|
|
19939
19927
|
msg.className = "ds-toggle-msg is-ok";
|
|
19940
|
-
// 🔴 **「保存中…」を消してから成功を書く(#220)。**
|
|
19941
|
-
// 画面に「保存中…✓ 保存しました。同期を開始しました。」と**2つの状態が同居**して
|
|
19942
|
-
// いた。appendChild は足すだけなので、消す一文が要る(sendConfig 側には在った)。
|
|
19943
|
-
// **語を書く前に必ずここを通すこと**——次に文面を足す人が同じ形で踏む
|
|
19928
|
+
// 🔴 **「保存中…」を消してから成功を書く(#220)。** appendChild は足すだけなので、消す一文が要る
|
|
19944
19929
|
msg.textContent = "";
|
|
19945
19930
|
msg.appendChild(document.createTextNode("✓ " + (j.message || "保存しました。")));
|
|
19946
|
-
// 起動できたときだけ、実行状況への導線を出す(鍵を入れた直後に効いたか確かめられる)
|
|
19947
19931
|
if (j.runsUrl) {
|
|
19948
19932
|
msg.appendChild(document.createTextNode(" "));
|
|
19949
19933
|
msg.appendChild(el("a", { href: j.runUrl || j.runsUrl, target: "_blank", rel: "noopener", title: "GitHub Actions の実行ログを開きます(プロジェクトリポジトリへのアクセスが要ります)", text: "実行状況を見る →" })); // その run を特定できていればそれ、無ければ一覧
|
|
19950
19934
|
}
|
|
19951
19935
|
// 入れた値は画面に残さない(肩越しに見えるのを防ぐ)
|
|
19952
19936
|
input.value = "";
|
|
19953
|
-
|
|
19954
|
-
|
|
19955
|
-
|
|
19956
|
-
|
|
19957
|
-
|
|
19958
|
-
|
|
19937
|
+
ent.savedHere = true;
|
|
19938
|
+
var willCheck = probeOk() && refsNow().length > 0;
|
|
19939
|
+
ent.checking = willCheck;
|
|
19940
|
+
paint();
|
|
19941
|
+
// 🔴 Backlog の行の一手は登録状況の正本に合わせて当て直す。正本(secretsNow)は取り直しで届く
|
|
19942
|
+
if (compact && typeof BACKLOG_UI.repaintRows === "function") BACKLOG_UI.repaintRows();
|
|
19943
|
+
if (willCheck) {
|
|
19944
|
+
var note = await checkAfterSave();
|
|
19945
|
+
if (note) msg.appendChild(document.createTextNode(" " + note));
|
|
19959
19946
|
}
|
|
19947
|
+
ent.checking = false;
|
|
19948
|
+
endBusy();
|
|
19949
|
+
paint();
|
|
19950
|
+
loadLiveFleet(true);
|
|
19960
19951
|
} catch (e) {
|
|
19961
|
-
|
|
19962
|
-
|
|
19952
|
+
ent.checking = false;
|
|
19953
|
+
// 保存が済んだあとの不調を「通信に失敗」と言わない(貼り直しに誘導しない)
|
|
19954
|
+
if (!ent.savedHere) {
|
|
19955
|
+
msg.className = "ds-toggle-msg is-error";
|
|
19956
|
+
msg.textContent = "✗ 通信に失敗しました。";
|
|
19957
|
+
}
|
|
19963
19958
|
endBusy();
|
|
19959
|
+
paint();
|
|
19964
19960
|
}
|
|
19965
19961
|
});
|
|
19966
19962
|
|
|
@@ -19972,21 +19968,17 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19972
19968
|
meta.note ? el("p", { class: "sec-how", text: meta.note }) : null,
|
|
19973
19969
|
meta.selfServe ? el("p", { class: "sec-how", text: meta.selfServe.note }) : null,
|
|
19974
19970
|
].filter(Boolean);
|
|
19975
|
-
// **「畳んである中に何があるか」を summary に書く。**
|
|
19976
|
-
// 発行のしかたを探している人がここを開く手掛かりを持てない(rt カードと同じ流儀)
|
|
19971
|
+
// **「畳んである中に何があるか」を summary に書く。**
|
|
19977
19972
|
var guidanceBox = el("details", { class: "sec-fold" }, [el("summary", { text: "発行のしかた" })]);
|
|
19978
19973
|
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)ではこの節は素通りする
|
|
19974
|
+
// **手順の動画+画像(#547・#1353)。** meta.guide を持つ種別(Figma)はカルーセル1つに乗せる
|
|
19982
19975
|
if (meta.guide && meta.guideInModal) {
|
|
19983
19976
|
// モーダルの上に出している種別(Backlog・Figma)は、ここには重ねない
|
|
19984
19977
|
} else if (meta.guide) {
|
|
19985
19978
|
var carousel = buildGuideCarousel(kind, meta.guide);
|
|
19986
19979
|
if (carousel) guidanceBox.appendChild(carousel);
|
|
19987
19980
|
} else if (meta.shots) {
|
|
19988
|
-
//
|
|
19989
|
-
// この口に載せ替えるまでの踏み板として残す
|
|
19981
|
+
// 後方互換(旧形)
|
|
19990
19982
|
for (var si = 0; si < meta.shots.length; si++) {
|
|
19991
19983
|
var shot = meta.shots[si];
|
|
19992
19984
|
guidanceBox.appendChild(el("p", { class: "sec-how", text: shot.heading }));
|
|
@@ -19994,86 +19986,33 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19994
19986
|
}
|
|
19995
19987
|
}
|
|
19996
19988
|
|
|
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
|
-
// 未登録のときだけ出る=これから貼る人にだけ出るので、畳むと存在理由が消える
|
|
19989
|
+
// 🔴 **.sec-state / .sec-preferred は常に見える場所に置く。** 札は「保存したのに反映されていない」が分かる唯一の手段。
|
|
19990
|
+
// .sec-preferred は「誰のアカウントで発行するのか」を手順より先に伝える行(未登録のときだけ出る)
|
|
20027
19991
|
var preferred = meta.selfServe ? el("p", { class: "sec-preferred", text: meta.selfServe.text }) : null;
|
|
20028
19992
|
var card = el("div", { class: "ops-card" + (inRow ? " ds-keycard" : ""), "data-secret-kind": kind }, [
|
|
20029
|
-
// 行の中の Backlog
|
|
19993
|
+
// 行の中の Backlog カードは見出しを持たない(何の鍵かは札と欄が言う)
|
|
20030
19994
|
compact ? null : el("div", { class: "ops-card-head" }, [
|
|
20031
19995
|
el("span", { class: "ops-card-icon", text: meta.icon }),
|
|
20032
19996
|
el("h3", { class: "ops-card-title", text: cardTitle }),
|
|
20033
19997
|
]),
|
|
20034
|
-
// **desc は無い種別がある(2026-08-21)。** el() は text をそのまま textContent へ
|
|
20035
|
-
// 代入するので、無条件に出すと画面に文字列 undefined が出る
|
|
20036
19998
|
meta.desc ? el("p", { class: "ops-card-desc", text: meta.desc }) : null,
|
|
20037
|
-
// **鍵の効く範囲は、登録状況より先に言う。**
|
|
20038
|
-
// 「どのファイルの話か」を確かめ直すことになる(#229)
|
|
19999
|
+
// **鍵の効く範囲は、登録状況より先に言う。** (#229)
|
|
20039
20000
|
scopeNote ? el("p", { class: "sec-scope", text: scopeNote }) : null,
|
|
20040
20001
|
state,
|
|
20041
|
-
|
|
20042
|
-
|
|
20043
|
-
|
|
20044
|
-
|
|
20045
|
-
|
|
20002
|
+
input,
|
|
20003
|
+
el("div", { class: "ds-toggle" }, [btn, msg]),
|
|
20004
|
+
savedNote,
|
|
20005
|
+
// 🔴 **値の扱いの 1 文は常に出す**(顧客に鍵の貼り付けを求める画面でいちばん落としてはいけない説明・#101)
|
|
20006
|
+
el("p", { class: "sec-note", text: compact
|
|
20007
|
+
? "入れた値は保存だけでき、あとから表示されません。"
|
|
20008
|
+
: "入れた値はここには表示されません(保存だけできます)。保存先はプロジェクトごとに分かれているので、他のプロジェクトには影響しません。" }),
|
|
20046
20009
|
guidanceBox,
|
|
20047
|
-
// **扱いの説明はカードに持たせる。** 節の見出しの下に置いていたときは、
|
|
20048
|
-
// #101 でカードだけがモーダルへ移り、説明だけが画面から消えた。
|
|
20049
|
-
// 顧客にトークンの貼り付けを求める画面で、貼った値がどう扱われるかの
|
|
20050
|
-
// 説明が落ちるのは、いちばん落としてはいけない種類の欠落
|
|
20051
|
-
// 行の中の Backlog カードは、同じ 1 文を開いた中(上の inputFold)に短くして持つ
|
|
20052
|
-
compact ? null : el("p", { class: "sec-note", text: "入れた値はここには表示されません(保存だけできます)。保存先はプロジェクトごとに分かれているので、他のプロジェクトには影響しません。" }),
|
|
20053
20010
|
]);
|
|
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);
|
|
20011
|
+
ent.el = card;
|
|
20012
|
+
ent.refresh = paint;
|
|
20013
|
+
paint();
|
|
20014
|
+
// **作った鍵カードは1枚残らずここに載せる。** 出し入れ(接続先が0件のときに畳む)は DOM 検索ではなくこの控えで回す
|
|
20015
|
+
KEY_CARDS.push(ent);
|
|
20077
20016
|
return card;
|
|
20078
20017
|
}
|
|
20079
20018
|
|
package/package.json
CHANGED