@takagaki/cortex-decisions-viewer 0.12.215 → 0.12.219

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.
@@ -229,7 +229,7 @@ function googleConfirmPageJs() {
229
229
  document.head.appendChild(s);
230
230
  });
231
231
  }
232
- /** Picker でフォルダを選ぶ。選ばずに閉じたら null */
232
+ /** Picker でフォルダを選ぶ。選ばずに閉じたら null。確認(confirm)は、確かめる行のフォルダだけを出す(setFileIds は setEnableDrives・setParent と併用できないので 1 つの画面にする) */
233
233
  function pickFolder(info, accessToken) {
234
234
  return loadScript("https://apis.google.com/js/api.js")
235
235
  .then(function () { return new Promise(function (resolve) { window.gapi.load("picker", { callback: resolve }); }); })
@@ -238,13 +238,18 @@ function googleConfirmPageJs() {
238
238
  var g = window.google.picker;
239
239
  var mine = new g.DocsView(g.ViewId.FOLDERS).setIncludeFolders(true).setSelectFolderEnabled(true).setMimeTypes("application/vnd.google-apps.folder");
240
240
  var shared = new g.DocsView(g.ViewId.FOLDERS).setIncludeFolders(true).setSelectFolderEnabled(true).setEnableDrives(true).setMimeTypes("application/vnd.google-apps.folder");
241
- var picker = new g.PickerBuilder()
241
+ var builder = new g.PickerBuilder()
242
242
  .setAppId(info.projectNumber)
243
243
  .setDeveloperKey(info.apiKey)
244
244
  .setOAuthToken(accessToken)
245
- .enableFeature(g.Feature.SUPPORT_DRIVES)
246
- .addView(mine)
247
- .addView(shared)
245
+ .enableFeature(g.Feature.SUPPORT_DRIVES);
246
+ if (ctx.mode === "confirm" && ctx.id) {
247
+ var only = new g.DocsView(g.ViewId.FOLDERS).setIncludeFolders(true).setSelectFolderEnabled(true).setMimeTypes("application/vnd.google-apps.folder").setFileIds(ctx.id);
248
+ builder = builder.addView(only);
249
+ } else {
250
+ builder = builder.addView(mine).addView(shared);
251
+ }
252
+ var picker = builder
248
253
  .setCallback(function (data) {
249
254
  if (data.action === g.Action.PICKED && data.docs && data.docs[0]) resolve(data.docs[0]);
250
255
  else if (data.action === g.Action.CANCEL) resolve(null);
@@ -372,7 +377,7 @@ function googleConfirmPageJs() {
372
377
  var what = isDrive ? "Drive のフォルダ" : "Google Chat のスペース";
373
378
  titleEl.textContent = (ctx.mode === "confirm" ? what + "を確認する" : what + "を追加する");
374
379
  leadEl.textContent = isDrive
375
- ? "あなたの Google アカウントで、追加するフォルダを選びます。選んだフォルダだけを Cortex が確認に使います。「このアプリは Google で確認されていません」と出たら、「詳細」から進めます。"
380
+ ? (ctx.mode === "confirm" && ctx.id ? "登録済みのフォルダを、あなたの Google アカウントで開けるか確かめます。出てきたフォルダを選んで[Select]を押してください。" : "あなたの Google アカウントで、追加するフォルダを選びます。") + "選んだフォルダだけを Cortex が確認に使います。「このアプリは Google で確認されていません」と出たら、「詳細」から進めます。"
376
381
  : "あなたの Google アカウントで、このスペースを開けるかを確認します。メッセージは読みません。";
377
382
  openChannel();
378
383
  // 作業中(Picker の選択など)は本体へ生存の合図を送る。本体は、窓が閉じたように見えても、合図が続いている間は失敗にしない
package/dist/render.js CHANGED
@@ -10503,6 +10503,9 @@ ${story_1.splitByNameLinks.toString()}
10503
10503
  * 知らない値は 「DS_GATE」 と同じく「不明」(engine が新しい語を足したのに画面が知らない、
10504
10504
  * という事実を黙って消さない)。
10505
10505
  */
10506
+ /** 接続の状態と[接続を確認]を鍵の部品が持つ能力か(Backlog=issues・Figma=design)。行はこの 2 つを持たない(便 KU) */
10507
+ function keyCardOwnsStatus(capId) { return capId === "issues" || capId === "design"; }
10508
+
10506
10509
  function dsGateForCap(capId, status) {
10507
10510
  var byCap = DS_GATE_CAP[capId];
10508
10511
  if (byCap && byCap[status]) return byCap[status];
@@ -15973,6 +15976,8 @@ ${story_1.splitByNameLinks.toString()}
15973
15976
  * 行の組み立ての最後に 「appendReachableReason」 を呼ぶ。
15974
15977
  */
15975
15978
  function appendReachableChip(row, capId, ref, workspace) {
15979
+ // 🔴 鍵で読む能力(Backlog・Figma)の接続の状態は、鍵の部品(secretCard)の札 1 か所だけ(便 KU)。行にも出すと同じ材料の札が窓の中で 2 か所に見える
15980
+ if (keyCardOwnsStatus(capId)) return row;
15976
15981
  var r = reachableStateOf(capId, ref, workspace);
15977
15982
  if (!r) return row;
15978
15983
  var gate = dsGateForCap(capId, r.status);
@@ -16167,7 +16172,8 @@ ${story_1.splitByNameLinks.toString()}
16167
16172
  // 🔴 表の案件(組み直した案件)には起こす同期が無い(押すと「確認を開始できませんでした」になる)。2 つとも出さない。
16168
16173
  // 見分けは設定の画面と同じ 1 か所(viewMode)。今までの案件(file)はここを素通り=画面は 1 バイトも変わらない
16169
16174
  if (viewMode() === "table") return row;
16170
- var checkBtn = el("button", { class: "ds-toggle-btn", type: "button", text: "接続を確認" });
16175
+ // 鍵で読む能力の[接続を確認]は鍵の部品の[保存して接続を確認]だけ(便 KU)。行には[今すぐ同期]だけ残す
16176
+ var checkBtn = keyCardOwnsStatus(capId) ? null : el("button", { class: "ds-toggle-btn", type: "button", text: "接続を確認" });
16171
16177
  var syncBtn = el("button", { class: "ds-toggle-btn", type: "button", text: "今すぐ同期" });
16172
16178
  var note = el("p", { class: "ds-probe-wait" });
16173
16179
  var phase = probeWaitPhaseOf(capId, ref);
@@ -16176,7 +16182,7 @@ ${story_1.splitByNameLinks.toString()}
16176
16182
  else if (phase === "timeout") note.textContent = PROBE_WAIT_TIMEOUT_TEXT;
16177
16183
  else note.hidden = true;
16178
16184
 
16179
- checkBtn.addEventListener("click", async function () {
16185
+ if (checkBtn) checkBtn.addEventListener("click", async function () {
16180
16186
  // 押している間は**ボタンだけ**が「確認中…」になる。行の中身は変えない(#1328)。
16181
16187
  // 前回の返事(「同期を開始しました」等)は押した時点で消す
16182
16188
  var endBusy = beginBusy(checkBtn, "確認中…");
@@ -16243,7 +16249,7 @@ ${story_1.splitByNameLinks.toString()}
16243
16249
  endBusy();
16244
16250
  });
16245
16251
 
16246
- row.appendChild(checkBtn);
16252
+ if (checkBtn) row.appendChild(checkBtn);
16247
16253
  row.appendChild(syncBtn);
16248
16254
  row.appendChild(note);
16249
16255
  return row;
@@ -19463,6 +19469,8 @@ ${story_1.splitByNameLinks.toString()}
19463
19469
  "figma": {
19464
19470
  icon: "🎨",
19465
19471
  title: "Figma のトークン",
19472
+ // 欄の案内(placeholder)。窓の他の文言・発行のしかたと同じ語(便 KU)
19473
+ paste: "アクセストークンを貼り付け",
19466
19474
  // **必要なスコープは実装が叩くAPIから決まる。** sync-designs は
19467
19475
  // GET /v1/files/{key} → file_content:read(画面インベントリ)
19468
19476
  // GET /v1/files/{key}/comments → file_comments:read(指摘の同期)
@@ -19552,6 +19560,8 @@ ${story_1.splitByNameLinks.toString()}
19552
19560
  "backlog": {
19553
19561
  icon: "📋",
19554
19562
  title: "Backlog のAPIキー",
19563
+ // 欄の案内(placeholder)。窓の他の文言・発行のしかたと同じ語(便 KU)
19564
+ paste: "API キーを貼り付け",
19555
19565
  how: "Backlog → 個人設定 → API で発行(同期先の Backlog プロジェクトが見えるアカウントで)",
19556
19566
  // ⚠ **desc は足さない。** 「毎晩同期するために使います」の 1 行は「カードが長すぎる」で
19557
19567
  // 外した経緯があり、secret-card-guidance.test.mjs が空の段落ごと見張っている。
@@ -19786,10 +19796,13 @@ ${story_1.splitByNameLinks.toString()}
19786
19796
  // 同じ鍵の[入れる]が行の一手・「その他」・畳みの 3 か所にあった。いまは 状態の札 → 伏せ字の欄(空のまま)→ [保存して接続を確認]。
19787
19797
  // 保存した値は読み戻さない(書き込み専用)。登録済みでも欄は空で、入れ直すときだけ貼る(伏せ字を欄に入れて伏せ字ごと保存する事故を避ける)
19788
19798
  var cap = kind === "backlog" ? "issues" : "design";
19789
- var input = el("input", { class: "sec-input", type: "password", placeholder: "トークンを貼り付け", autocomplete: "off", spellcheck: "false" });
19799
+ var input = el("input", { class: "sec-input", type: "password", placeholder: meta.paste || "トークンを貼り付け", autocomplete: "off", spellcheck: "false" });
19790
19800
  var btn = el("button", { class: "ds-toggle-btn", type: "button", text: "保存" });
19791
19801
  var msg = el("div", { class: "ds-toggle-msg" });
19792
19802
  var savedNote = el("p", { class: "sec-note sec-saved" });
19803
+ // 登録済みの鍵は欄を畳む(GitHub の Secrets・Vercel の環境変数と同じ)。[入れ直す]を押すまで欄とボタンは出さない(便 KU-3)
19804
+ var reopen = el("button", { class: "ds-toggle-btn sec-reopen", type: "button", text: "入れ直す" });
19805
+ var reopened = false;
19793
19806
  // 札が読む材料の控え。checking=保存〜確認の最中、savedHere=この画面で保存した(正本 secretsNow は最大 10 秒古い答えを返すので、registered を返すまで「登録済み」以上に固定する)
19794
19807
  var ent = { kind: kind, el: null, compact: compact, space: stateSpace, input: input, msg: msg, checking: false, savedHere: false };
19795
19808
 
@@ -19862,7 +19875,13 @@ ${story_1.splitByNameLinks.toString()}
19862
19875
  var reg = st.known === "yes";
19863
19876
  var d = savedDate(st);
19864
19877
  savedNote.hidden = !reg;
19865
- savedNote.textContent = reg ? "登録済み" + (d ? "(" + d + " に保存)" : "") + "。入れ直すときだけ貼ってください" : "";
19878
+ // 畳んだ形=登録済み(この画面で保存した直後も)で、[入れ直す]をまだ押していない。保存に失敗したときは reg が変わらないので畳まない
19879
+ var folded = reg && !reopened;
19880
+ savedNote.textContent = reg ? "登録済み" + (d ? "(" + d + " に保存)" : "") + (folded ? "" : "。入れ直すときだけ貼ってください") : "";
19881
+ input.style.display = folded ? "none" : "";
19882
+ btn.style.display = folded ? "none" : "";
19883
+ // 接続の確認中は出さない(押すと成功の文が消える)
19884
+ reopen.style.display = folded && !ent.checking ? "" : "none";
19866
19885
  if (!btn.disabled) btn.textContent = probeOk() ? "保存して接続を確認" : "保存";
19867
19886
  if (preferred) {
19868
19887
  var want = st.known === "no";
@@ -19871,7 +19890,9 @@ ${story_1.splitByNameLinks.toString()}
19871
19890
  }
19872
19891
  }
19873
19892
  /** 保存のあとの接続の確認。結果は行と同じ形で置く(applyProbeResult)。返すのは添える 1 文(無ければ空) */
19893
+ var ipReason = false;
19874
19894
  async function checkAfterSave() {
19895
+ ipReason = false;
19875
19896
  var type = dispatchProbeTypeOf(cap);
19876
19897
  // Figma は回数制限(1 分あたりの枠)に収まるよう先頭の 2 ファイルだけ。残りは各行の[接続を確認]
19877
19898
  var refs = refsNow().slice(0, kind === "figma" ? 2 : 20);
@@ -19887,6 +19908,10 @@ ${story_1.splitByNameLinks.toString()}
19887
19908
  applyProbeResult(cap, refs[i], "", { gate: j.gate, checkedAt: j.checkedAt, needed: "", detail: j.detail || "" });
19888
19909
  } else if (!res.ok) {
19889
19910
  return "接続の確認はできませんでした:" + ((j && j.message) || "少し待ってからもう一度お試しください。");
19911
+ } else if (j.reason === "ip-restricted") {
19912
+ // 原因が分かる応答は、固定文ではなく原因の文を出す。[切り替える]は呼び出し側が添える
19913
+ ipReason = true;
19914
+ return j.message || "この場では確認できませんでした(IP 制限の可能性)。";
19890
19915
  } else {
19891
19916
  return "接続の確認は少し後に札へ出ます。";
19892
19917
  }
@@ -19898,12 +19923,21 @@ ${story_1.splitByNameLinks.toString()}
19898
19923
  return "";
19899
19924
  }
19900
19925
 
19926
+ reopen.addEventListener("click", function () {
19927
+ reopened = true;
19928
+ input.value = ""; // 畳まれる前に貼りかけた値を持ち越さない
19929
+ msg.className = "ds-toggle-msg";
19930
+ msg.textContent = "";
19931
+ paint();
19932
+ input.focus();
19933
+ });
19934
+
19901
19935
  btn.addEventListener("click", async function () {
19902
19936
  var value = input.value;
19903
19937
  if (!value.trim()) {
19904
19938
  msg.className = "ds-toggle-msg";
19905
19939
  // 登録済みで空のまま押しても何も変えない(置き換えるのは、貼ったときだけ)
19906
- msg.textContent = secretNow().known === "yes" ? "何も変えていません。入れ直すときだけ値を貼ってください。" : "";
19940
+ msg.textContent = secretNow().known === "yes" && reopened ? "何も変えていません。入れ直すときだけ値を貼ってください。" : "";
19907
19941
  if (secretNow().known !== "yes") { msg.className = "ds-toggle-msg is-error"; msg.textContent = "⚠ トークンを入力してください。"; }
19908
19942
  return;
19909
19943
  }
@@ -19935,14 +19969,18 @@ ${story_1.splitByNameLinks.toString()}
19935
19969
  // 入れた値は画面に残さない(肩越しに見えるのを防ぐ)
19936
19970
  input.value = "";
19937
19971
  ent.savedHere = true;
19972
+ reopened = false; // 保存できたら欄を畳む(成功の文と札だけ残す)
19973
+ var hadFocus = typeof document !== "undefined" && document.activeElement === btn;
19938
19974
  var willCheck = probeOk() && refsNow().length > 0;
19939
19975
  ent.checking = willCheck;
19940
19976
  paint();
19977
+ if (hadFocus) msg.setAttribute("tabindex", "-1"), msg.focus(); // 畳んだボタンからフォーカスを落とさない(成功の文へ)
19941
19978
  // 🔴 Backlog の行の一手は登録状況の正本に合わせて当て直す。正本(secretsNow)は取り直しで届く
19942
19979
  if (compact && typeof BACKLOG_UI.repaintRows === "function") BACKLOG_UI.repaintRows();
19943
19980
  if (willCheck) {
19944
19981
  var note = await checkAfterSave();
19945
19982
  if (note) msg.appendChild(document.createTextNode(" " + note));
19983
+ if (ipReason) appendBacklogProbeSwitch(msg, cap, { reason: "ip-restricted" });
19946
19984
  }
19947
19985
  ent.checking = false;
19948
19986
  endBusy();
@@ -20002,6 +20040,7 @@ ${story_1.splitByNameLinks.toString()}
20002
20040
  input,
20003
20041
  el("div", { class: "ds-toggle" }, [btn, msg]),
20004
20042
  savedNote,
20043
+ reopen,
20005
20044
  // 🔴 **値の扱いの 1 文は常に出す**(顧客に鍵の貼り付けを求める画面でいちばん落としてはいけない説明・#101)
20006
20045
  el("p", { class: "sec-note", text: compact
20007
20046
  ? "入れた値は保存だけでき、あとから表示されません。"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.12.215",
3
+ "version": "0.12.219",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,