@takagaki/cortex-decisions-viewer 0.10.5 → 0.10.7

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.
Files changed (2) hide show
  1. package/dist/render.js +228 -11
  2. package/package.json +1 -1
package/dist/render.js CHANGED
@@ -12,6 +12,7 @@ exports.chatRowsToAdd = chatRowsToAdd;
12
12
  exports.devRowsToAdd = devRowsToAdd;
13
13
  exports.designRowsToAdd = designRowsToAdd;
14
14
  exports.materialRowsToAdd = materialRowsToAdd;
15
+ exports.issuesRefOf = issuesRefOf;
15
16
  exports.issueRowsToAdd = issueRowsToAdd;
16
17
  exports.unsettledRegisteredCount = unsettledRegisteredCount;
17
18
  exports.registeredRowsToAdd = registeredRowsToAdd;
@@ -734,6 +735,25 @@ function materialRowsToAdd(ids, rows) {
734
735
  }
735
736
  return out;
736
737
  }
738
+ /**
739
+ * 課題管理(Backlog)の接続先1件を1つの鍵にする。**ドメインは小文字・キーは大文字。**
740
+ *
741
+ * 🔴 **この規則の正本はここ1つ。** 設定ファイルの値は人が書いたもので大小が揃って
742
+ * いないので、揃えずに突き合わせると**同じ接続先を別物と見る**。それが起きる場所が
743
+ * 3つある——行の重複判定(`issueRowsToAdd`)、登録から消えた行の引き算
744
+ * (`subtractRemovedRegistered`)、そして接続状態ストアの行との突き合わせ
745
+ * (画面の `ingestedStateOf`。ストアの `ref` も engine 側がこの規則で書く)。
746
+ *
747
+ * **クロージャを持たないこと**(クライアントへ `.toString()` で流し込む)。
748
+ *
749
+ * ⚠ 画面の `targetsGenerationOf`(サーバへ送る世代)は同じ規則を持つが、この関数を
750
+ * 呼べない——配信物から関数1つを切り出して直接呼ぶテストがあり、外の名前を参照した
751
+ * 瞬間にそのテストが動かなくなる。あちらを直すときはここも直す。
752
+ */
753
+ function issuesRefOf(domain, projectKey) {
754
+ return String(domain == null ? "" : domain).toLowerCase() + "/" +
755
+ String(projectKey == null ? "" : projectKey).toUpperCase();
756
+ }
737
757
  /**
738
758
  * 課題管理の行で、まとめ表がまだ知らないもの。
739
759
  *
@@ -742,7 +762,7 @@ function materialRowsToAdd(ids, rows) {
742
762
  * 二重に並ぶ(片方は削除ボタンを持たない)。
743
763
  */
744
764
  function issueRowsToAdd(targets, rows) {
745
- const key = (d, k) => String(d).toLowerCase() + "/" + String(k).toUpperCase();
765
+ const key = issuesRefOf;
746
766
  const have = {};
747
767
  for (const t of targets || [])
748
768
  if (t && t.domain && t.projectKey)
@@ -899,7 +919,7 @@ function subtractRemovedRegistered(view, reg) {
899
919
  if (Array.isArray(reg.issues)) {
900
920
  // 鍵の畳み方は足す側(issueRowsToAdd)と同じにする——別の畳み方にすると
901
921
  // 大小の違いで「引いた直後に別綴りで足し直される」形になる
902
- const issueKey = (t) => String(t.domain).toLowerCase() + "/" + String(t.projectKey).toUpperCase();
922
+ const issueKey = (t) => issuesRefOf(t.domain, t.projectKey);
903
923
  const keys = {};
904
924
  for (const r of reg.issues)
905
925
  if (r)
@@ -2051,6 +2071,12 @@ a.ds-name:hover { text-decoration: underline; }
2051
2071
  .ds-all-connected { color: var(--muted); }
2052
2072
  .ds-gate { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; font-weight: 600; flex: 0 0 auto; }
2053
2073
  .ds-gate-at { font-size: 11px; color: var(--muted); flex: 0 0 auto; }
2074
+ /* 接続先1件ごとの「取り込み」(段C・2026-08-24)。**「最終同期」(.ds-sync・run単位)とは
2075
+ 別の行に並ぶ**ので、同じ強さにしない——run の時刻より弱い添え物として読ませる。
2076
+ 失敗だけは .ds-gate-warn と同じ色にする(同じ画面で警告の色が2種類あると、
2077
+ どちらが重いのか読めない) */
2078
+ .ds-ingest { font-size: 11px; color: var(--muted); flex: 0 0 auto; font-variant-numeric: tabular-nums; }
2079
+ .ds-ingest-failed { color: #b45309; font-weight: 600; }
2054
2080
  .ds-gate::before { content: ""; width: 8px; height: 8px; border-radius: 999px; background: currentColor; }
2055
2081
  .ds-gate-ok { color: #1f7a45; }
2056
2082
  .ds-gate-warn { color: #b45309; }
@@ -2324,6 +2350,7 @@ ${capabilityAdapter.toString()}
2324
2350
  ${capabilityRawState.toString()}
2325
2351
  ${capabilityDisplayState.toString()}
2326
2352
  ${backlogTargetOf.toString()}
2353
+ ${issuesRefOf.toString()}
2327
2354
  ${sourceNeedsAttention.toString()}
2328
2355
  ${capabilityState.toString()}
2329
2356
  // 反映待ち(⏳ 反映中)の判定。**期限・間隔・対応表もビルド時の定義から流し込む**
@@ -5608,6 +5635,7 @@ ${nextStateDelay.toString()}
5608
5635
  * ——食い違わないことは backlog-targets-ui.test.mjs が実物どうしで突き合わせている。
5609
5636
  *
5610
5637
  * **クロージャを持たない純関数に保つこと**(テストが配信物から切り出して直接呼ぶ)。
5638
+ * だから issuesRefOf を呼べない(規則の正本はあちら側。直すときは両方直す)。
5611
5639
  */
5612
5640
  function targetsGenerationOf(list) {
5613
5641
  return (list || [])
@@ -5710,6 +5738,116 @@ ${nextStateDelay.toString()}
5710
5738
  return domains.length === 1 ? domains[0] : "";
5711
5739
  }
5712
5740
 
5741
+ /**
5742
+ * その接続先の「取り込み」の行(接続状態ストア・段C)。**無ければ null。**
5743
+ *
5744
+ * 🔴 **overlayStateOnFleet は通らない。** あれは externalSources(チャット / 開発)に
5745
+ * 重ねる仕組みで、**Backlog の行はそこに存在しない**(まとめ表を作る側が作るのは
5746
+ * slack と github 系だけ)。だから接続先の行を描くこちらがストアを直接引く。
5747
+ *
5748
+ * **突き合わせは両側とも issuesRefOf を通す。** 設定ファイルの値は人が書いたもので
5749
+ * 大小が揃っておらず("CM1.Backlog.JP" / "pj_a" が実在する)、素の文字列で比べると
5750
+ * **取り込めているのに何も出ない**——「測っていないものは何も言わない」設計なので、
5751
+ * 突き合わせに失敗しても画面は静かに黙るだけで、誰も気づけない。
5752
+ */
5753
+ function ingestedStateOf(domain, projectKey) {
5754
+ var rows = LIVE_STATE;
5755
+ if (!rows || !rows.length || !domain || !projectKey) return null;
5756
+ var want = issuesRefOf(domain, projectKey);
5757
+ for (var i = 0; i < rows.length; i++) {
5758
+ var r = rows[i];
5759
+ // cap と question の両方で絞る。片方だけだと、同じ ref を持つ別の問い
5760
+ //(将来 issues に別の question が増えたとき)の行を取り込みとして読む
5761
+ if (!r || r.cap !== "issues" || r.question !== "ingested") continue;
5762
+ var at = String(r.ref || "").indexOf("/");
5763
+ if (at < 0) continue;
5764
+ if (issuesRefOf(String(r.ref).slice(0, at), String(r.ref).slice(at + 1)) === want) return r;
5765
+ }
5766
+ return null;
5767
+ }
5768
+
5769
+ /**
5770
+ * 接続先1件の「取り込み」の表示。**測っていなければ何も出さない(null)。**
5771
+ *
5772
+ * 段A・段Bと同じ原則。行が無いのは「取り込みが動いていない」ではなく
5773
+ * 「まだ誰も書いていない」(engine の版が古い案件・一度も同期していない案件)で、
5774
+ * そこに「未取り込み」と書くと**直す必要があると読ませる嘘**になる。
5775
+ *
5776
+ * **「最終同期」(.ds-sync)を置き換えない。** あちらは run 全体の最終成功時刻で、
5777
+ * どの接続先のことか分からない。こちらは接続先1件の成否。意味が違うので併記する。
5778
+ */
5779
+ function ingestedEl(r) {
5780
+ if (!r) return null;
5781
+ var when = rtAgo(r.at);
5782
+ var text = "";
5783
+ if (r.status === "ok") text = when ? "取り込み: " + when + "に成功" : "取り込み: 成功";
5784
+ else if (r.status === "failed") text = when ? "取り込み: " + when + "に失敗" : "取り込み: 失敗";
5785
+ else if (r.status === "skipped") text = "取り込み: スキップ";
5786
+ if (!text) return null;
5787
+ return el("span", {
5788
+ class: "ds-ingest" + (r.status === "failed" ? " ds-ingest-failed" : ""),
5789
+ text: text,
5790
+ });
5791
+ }
5792
+
5793
+ /**
5794
+ * いま一覧に出ている接続先の「取り込み」をひとつの文字列にする(差し替えの要否の判定用)。
5795
+ *
5796
+ * 🔴 **接続先の世代(targetsGenerationOf)だけでは足りない。** モーダルを開くと
5797
+ * その能力の状況をもう一度取りに行くので、**応答が返る前に開いた人は取り込みの行を
5798
+ * 1件も持っていない**。届いた応答で接続先の集合が変わっていなければ、世代だけを見る
5799
+ * 早期return が描き直しを飛ばし、**閉じて開き直すまで空のまま**になる。
5800
+ * 空表示は「まだ誰も測っていない」と区別が付かないので、**取り込みの失敗を黙る**という
5801
+ * この機能が殺そうとしている欠陥そのものが、別の経路で復活する。
5802
+ */
5803
+ function ingestSigOf(list) {
5804
+ return (list || []).map(function (t) {
5805
+ var r = ingestedStateOf(t.domain, t.projectKey);
5806
+ return r ? r.status + "@" + r.at : "-";
5807
+ }).join(",");
5808
+ }
5809
+
5810
+ /**
5811
+ * Figmaファイル1件の「取り込み」の行(接続状態ストア・段C第二弾)。**無ければ null。**
5812
+ * 表示は Backlog と同じ ingestedEl を通す(状態から文言を決める規則は1つだけ持つ)。
5813
+ *
5814
+ * 🔴 **鍵は正規化しない**——ingestedStateOf(課題管理)との意図的な違い。Figma の
5815
+ * ファイルキーは**大小を区別する不透明ID**で、揃えにいくと別のファイルを同じものと見る。
5816
+ * logic.mjs の figmaFileKey も trim だけで大小を保ち、applyAddFigmaFile の重複判定も完全一致。
5817
+ * 突き合わせが成立する根拠は「人が大小を揃えること」ではなく、**書き手(同期ジョブ)と
5818
+ * 画面(figmaFiles)が同じ figma.json の同じ値を読むこと**。
5819
+ */
5820
+ function designIngestedStateOf(key) {
5821
+ var rows = LIVE_STATE;
5822
+ var want = String(key || "");
5823
+ if (!rows || !rows.length || !want) return null;
5824
+ for (var i = 0; i < rows.length; i++) {
5825
+ var r = rows[i];
5826
+ // cap と question の両方で絞る。片方だけだと、同じ ref を持つ別の問いの行
5827
+ //(別能力の行・将来 design に増える別の question)を取り込みとして読む
5828
+ if (!r || r.cap !== "design" || r.question !== "ingested") continue;
5829
+ if (r.ref === want) return r;
5830
+ }
5831
+ return null;
5832
+ }
5833
+
5834
+ /**
5835
+ * いま一覧に出ている Figma ファイルの「取り込み」をひとつの文字列にする(liveList の sig 用)。
5836
+ *
5837
+ * 🔴 **ファイル一覧のJSONだけでは足りない。** モーダルを開くとその能力の状況をもう一度
5838
+ * 取りに行くので、**応答が返る前に開いた人は取り込みの行を1件も持っていない**。届いた応答で
5839
+ * ファイルの集合は変わらないため、一覧だけを署名にすると liveList の早期return が描き直しを
5840
+ * 飛ばし、**閉じて開き直すまで空のまま**になる。空表示は「まだ誰も測っていない」と
5841
+ * 見分けが付かないので、この機能が殺そうとしている「取り込みの失敗を黙る」欠陥が
5842
+ * 別の経路で復活する(課題管理側の ingestSigOf と同じ理由)。
5843
+ */
5844
+ function designIngestSigOf(list) {
5845
+ return (list || []).map(function (f) {
5846
+ var r = designIngestedStateOf(f && f.key);
5847
+ return r ? r.status + "@" + r.at : "-";
5848
+ }).join(",");
5849
+ }
5850
+
5713
5851
  /**
5714
5852
  * 「課題管理」カードの接続先(一覧+追加+削除・#127)。
5715
5853
  *
@@ -5768,6 +5906,8 @@ ${nextStateDelay.toString()}
5768
5906
  el("span", { class: "ds-type", text: "Backlog" }),
5769
5907
  dsNameEl(t.domain + " / " + t.projectKey, "https://" + t.domain + "/projects/" + t.projectKey),
5770
5908
  ]),
5909
+ // この接続先の取り込みが最後にどうなったか(段C)。測っていなければ null
5910
+ ingestedEl(ingestedStateOf(t.domain, t.projectKey)),
5771
5911
  ]);
5772
5912
  if (!editable) return row;
5773
5913
  var btn = el("button", { class: "ds-toggle-btn ds-danger", type: "button", text: "この接続先を外す" });
@@ -5912,6 +6052,8 @@ ${nextStateDelay.toString()}
5912
6052
  // 箱が無いと最初の描画で「未設定」の行が出ない
5913
6053
  var box = el("div", { "data-live-cap": REGISTERED_CAP_NAMES.issues }, [listEl]);
5914
6054
  paint();
6055
+ /** いま描いてある取り込みの状態(段C)。接続先の集合とは別に変わるので、別に覚える */
6056
+ var lastIngestSig = ingestSigOf(targets);
5915
6057
  /**
5916
6058
  * 取り直しで新しい値が届いたときの差し替え(段階1)。**一覧だけを描き直す。**
5917
6059
  *
@@ -5923,8 +6065,13 @@ ${nextStateDelay.toString()}
5923
6065
  // 🔴 応答に添えられた一覧(adoptTargets)のほうが新しい。上書きしない
5924
6066
  if (adopted) return;
5925
6067
  var next = backlogTargetsNow(internalSourceOf(REGISTERED_CAP_NAMES.issues));
5926
- if (targetsGenerationOf(next) === targetsGenerationOf(targets)) return;
6068
+ // 🔴 **変化が無いと言えるのは、接続先の集合と取り込みの状態が両方同じときだけ(段C)。**
6069
+ // 世代だけで判断すると、**応答を待たずにモーダルを開いた人には取り込みが永久に出ない**
6070
+ //(届いた応答で集合は変わらないので、ここで飛ばされる)。ingestSigOf の項に経緯
6071
+ var sig = ingestSigOf(next);
6072
+ if (targetsGenerationOf(next) === targetsGenerationOf(targets) && sig === lastIngestSig) return;
5927
6073
  targets = next;
6074
+ lastIngestSig = sig;
5928
6075
  paint();
5929
6076
  };
5930
6077
  // 接続先がまだ無い案件の受け皿は、0件の1行の直後に置く(行が無いので中へ入れられない)
@@ -6189,15 +6336,57 @@ ${nextStateDelay.toString()}
6189
6336
  // **一覧は開いたままでも差し替わる箱に入れる(段階1)。** 追加は「モーダルを開いたまま」
6190
6337
  // 行われるので、ここが固定だと足したファイルは閉じるまで画面に出ない
6191
6338
  var figsOf = function () { return (internalSourceOf("デザイン") || {}).figmaFiles || []; };
6192
- box.appendChild(liveList("デザイン", function () { return JSON.stringify(figsOf()); }, function (listBox) {
6339
+ /**
6340
+ * 外し終えたファイルの鍵。**一覧の箱の外に置く(段C第二弾)。**
6341
+ *
6342
+ * 外した行には取り消し線を引き、ボタンだけを無効にする。その印は行の closure に
6343
+ * あるので**描き直しで作り直される**——取り込みの状態を署名に混ぜたことで
6344
+ * LIVE_STATE の到着でも描き直しが走るようになり、ここに覚えておかないと
6345
+ * **外したばかりの行が生き返り、二度押しで「登録されていません」になる**
6346
+ *(削除は取り消せないので、押せる見た目に戻すのがいちばん悪い)。
6347
+ *
6348
+ * **効くのは短い。** 段A補(subtractRemovedRegistered)以降、外した行は次の
6349
+ * op=state が返った時点で一覧から消える。だからこの印が要るのは
6350
+ * **①保存の応答から次の op=state までの数秒**と、**②op=state が取れない案件**
6351
+ *(古い Lambda・通信失敗で、夜間の一覧が翌朝まで残る)だけ。
6352
+ *
6353
+ * 🔴 **一覧から消えた鍵は落とす(下の prune)。** 消えた=サーバが削除を認めた
6354
+ * ということなので、この印は役目を終えている。**持ち続けると、押し間違いに気づいて
6355
+ * 同じファイルを貼り直した人の行が、復活した瞬間に「外し済み」で描かれて操作不能に
6356
+ * なる**(回復手段はモーダルを開き直すことだけで、その手掛かりが画面に無い)。
6357
+ * 追加の口から鍵を落とす手もあるが、あちらが受け取るのは URL で、鍵に直すには
6358
+ * サーバ側の figmaFileKey を画面にもう1つ持つことになる(同じ規則が2箇所に増える)。
6359
+ */
6360
+ var figsRemoved = [];
6361
+ /**
6362
+ * いま送信中の行(鍵 → 行の節点)。**描き直しでも作り直さず、この節点を使い続ける。**
6363
+ *
6364
+ * 取り込みの状態を署名に混ぜたことで、**op=config の応答待ちの最中に op=state が
6365
+ * 届くと行が作り直される**窓ができた。作り直すと「保存中…」と押せない状態を持つ
6366
+ * 節点が捨てられ、**返事が来る前にもう一度押せてしまう**。押している当人の行だけを
6367
+ * 据え置き、他の行の取り込み表示は普段どおり追いつかせる(removeButton の onBusy)。
6368
+ */
6369
+ var figSending = {};
6370
+ // **署名に取り込みの状態も混ぜる(段C第二弾)。** 一覧のJSONだけだと、応答が返る前に
6371
+ // モーダルを開いた人には取り込みが1件も出ない(designIngestSigOf の項に経緯)
6372
+ box.appendChild(liveList("デザイン", function () {
6373
+ return JSON.stringify(figsOf()) + "|" + designIngestSigOf(figsOf());
6374
+ }, function (listBox) {
6193
6375
  var figs = figsOf();
6376
+ // **一覧から消えた鍵は「外し済み」から落とす**(figsRemoved の項に経緯)。
6377
+ // サーバが削除を認めた印なので、ここから先に同じ鍵が現れたら**貼り直された別の登録**
6378
+ var figKeys = figs.map(function (f) { return f.key; });
6379
+ figsRemoved = figsRemoved.filter(function (k) { return figKeys.indexOf(k) >= 0; });
6194
6380
  // **残り件数は「押した時点」で数える。** 一覧(figs)は夜間バッチのスナップショットで、
6195
6381
  // このページを開いている間はもちろん、その日のうちに再読み込みしても更新されない。
6196
6382
  // 描画時点の件数で判定すると、3件を1件ずつ外していったとき最後の1件でも警告が出ない。
6197
- var figsLeft = figs.length;
6383
+ // **描き直しでも外した分を引いたままにする**(figsRemoved の項に経緯)
6384
+ var figsLeft = figs.filter(function (f) { return figsRemoved.indexOf(f.key) < 0; }).length;
6198
6385
  if (figs.length) {
6199
6386
  var flist = el("div", { class: "ds-list" });
6200
6387
  figs.forEach(function (f) {
6388
+ // 送信中の行は作り直さない(figSending の項に経緯)
6389
+ if (figSending[f.key]) { flist.appendChild(figSending[f.key]); return; }
6201
6390
  // **Slack / GitHub の行と同じ構造にする(ds-card > ds-card-main >
6202
6391
  // ds-icon + ds-type + ds-name)。** extSourceCard は呼ばない——
6203
6392
  // あちらは type / gate / origin など外部ソース固有の判断を抱えている。
@@ -6208,6 +6397,8 @@ ${nextStateDelay.toString()}
6208
6397
  el("span", { class: "ds-type", text: "Figma" }),
6209
6398
  dsNameEl(f.name || f.key, "https://www.figma.com/design/" + f.key),
6210
6399
  ]),
6400
+ // このファイルの取り込みが最後にどうなったか(段C)。測っていなければ null
6401
+ ingestedEl(designIngestedStateOf(f.key)),
6211
6402
  ]);
6212
6403
  row.appendChild(removeButton({
6213
6404
  label: "このファイルを外す",
@@ -6233,9 +6424,21 @@ ${nextStateDelay.toString()}
6233
6424
  onDone: function () {
6234
6425
  // **クラスのハード代入をやめる**(片方だけ直し忘れる形を構造的に消す)
6235
6426
  row.classList.add("ds-removed");
6427
+ if (figsRemoved.indexOf(f.key) < 0) figsRemoved.push(f.key);
6236
6428
  figsLeft -= 1;
6237
6429
  },
6430
+ // 確認〜応答のあいだ、この行だけ描き直しの対象から外す(figSending の項に経緯)
6431
+ onBusy: function (on) {
6432
+ if (on) figSending[f.key] = row;
6433
+ else delete figSending[f.key];
6434
+ },
6238
6435
  }));
6436
+ // 描き直しのあとも「外した」ことが分かる形に戻す(figsRemoved の項に経緯)
6437
+ if (figsRemoved.indexOf(f.key) >= 0) {
6438
+ row.classList.add("ds-removed");
6439
+ var doneBtn = row.querySelector(".ds-toggle-btn");
6440
+ if (doneBtn) doneBtn.disabled = true;
6441
+ }
6239
6442
  flist.appendChild(row);
6240
6443
  });
6241
6444
  listBox.appendChild(flist);
@@ -6669,7 +6872,14 @@ ${nextStateDelay.toString()}
6669
6872
  * 成功しても一覧からは消さない。接続状況は夜間バッチのスナップショットで、消したつもりの行が
6670
6873
  * 翌朝まで残るのが正しい状態のため——行に取り消し線を引き、ボタンだけを無効にする
6671
6874
  * (二度押しすると「登録されていません」で失敗するので、押せなくする)。
6672
- * @param opts { label, confirmLines(), build(), onDone() }
6875
+ * **押している間(確認〜応答)を呼び出し側に知らせる(onBusy)。**
6876
+ * 一覧を差し替える口では、この間に描き直しが走るとこの行ごと作り直され、
6877
+ * 「保存中…」と押せない状態を持つ節点が捨てられる——**二度押しできる見た目に戻る**。
6878
+ * 削除は取り消せないので、行を差し替える側はこの間だけ元の節点を使い続けること。
6879
+ * **確認の前から数える**(確認モーダルの戻り先もこの節点なので、途中で捨てると
6880
+ * 「いいえ」を押した人のフォーカスの戻り先が消える)。
6881
+ *
6882
+ * @param opts { label, confirmLines(), build(), onDone(), onBusy(bool) }
6673
6883
  */
6674
6884
  function removeButton(opts) {
6675
6885
  var wrap = el("div", { class: "ds-toggle" });
@@ -6677,11 +6887,18 @@ ${nextStateDelay.toString()}
6677
6887
  var msg = el("div", { class: "ds-toggle-msg" });
6678
6888
 
6679
6889
  btn.addEventListener("click", async function () {
6680
- if (!(await confirmDanger(opts.confirmLines(), { returnTo: btn }))) { msg.textContent = ""; return; }
6681
- sendConfig(opts.build(), msg, btn, function () {
6682
- btn.disabled = true;
6683
- if (opts.onDone) opts.onDone();
6684
- });
6890
+ if (opts.onBusy) opts.onBusy(true);
6891
+ // **finally で必ず倒す。** 断られた・通信に失敗した経路で立てっぱなしにすると、
6892
+ // 呼び出し側はその行を永久に差し替えられなくなる(sendConfig は自分で捕まえるので投げない)
6893
+ try {
6894
+ if (!(await confirmDanger(opts.confirmLines(), { returnTo: btn }))) { msg.textContent = ""; return; }
6895
+ await sendConfig(opts.build(), msg, btn, function () {
6896
+ btn.disabled = true;
6897
+ if (opts.onDone) opts.onDone();
6898
+ });
6899
+ } finally {
6900
+ if (opts.onBusy) opts.onBusy(false);
6901
+ }
6685
6902
  });
6686
6903
 
6687
6904
  wrap.appendChild(btn);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.10.5",
3
+ "version": "0.10.7",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,