@takagaki/cortex-decisions-viewer 0.12.22 → 0.12.23
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 +218 -137
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -756,7 +756,7 @@ function sanitizeHarnessShelf(v) {
|
|
|
756
756
|
* 写し忘れても赤くならなかったので、突き合わせは viewer/test/state-vocab-parity.test.mjs。
|
|
757
757
|
*/
|
|
758
758
|
const STATE_STATUSES = {
|
|
759
|
-
reachable: ["ok", "not_in_channel", "missing_scope", "no_token", "unreachable", "unknown", "not_in_space", "no_credentials"],
|
|
759
|
+
reachable: ["ok", "not_in_channel", "missing_scope", "no_token", "unreachable", "unknown", "not_in_space", "no_credentials", "no_consent", "transcripts_api_disabled", "no_access_policy", "speaker_attribution_off", "folder_not_granted"],
|
|
760
760
|
ingested: ["ok", "failed", "skipped"],
|
|
761
761
|
};
|
|
762
762
|
const STATE_ROW_FIELDS = ["cap", "ref", "workspace", "question", "status", "at", "by", "needed", "detail", "lastOkAt", "lastFailAt"];
|
|
@@ -943,6 +943,13 @@ function gchatRowsToAdd(externals, rows) {
|
|
|
943
943
|
*
|
|
944
944
|
* **種別(issues / discussions)は登録ファイルの宣言をそのまま使う。** 無いときだけ
|
|
945
945
|
* Issues に倒す——ここで決め打ちすると、Discussions だけを登録した案件のラベルが嘘になる。
|
|
946
|
+
*
|
|
947
|
+
* 🔴 **`origin: "explicit"` を付ける(#354)。** 「登録から削除」は `origin === "explicit"` の
|
|
948
|
+
* 行にだけ出る(導出リポに出すと押しても翌日戻る)。ここで足す行は `dev-sources.json` の
|
|
949
|
+
* `sources`(人が登録簿に書いたもの)からしか来ないので、明示登録であることは事実。
|
|
950
|
+
* 付けないと、**登録した直後の行だけ「登録から削除」が無い**(夜間のまとめ表が追いつく
|
|
951
|
+
* 翌朝まで、読めていない主役の行を外す手段が画面に無い——cortex-test で実際に踏んだ)。
|
|
952
|
+
* Slack の同じ穴を #221 で `chatRowsToAdd` が塞いだのと同型。
|
|
946
953
|
*/
|
|
947
954
|
function devRowsToAdd(externals, rows) {
|
|
948
955
|
const have = {};
|
|
@@ -957,7 +964,7 @@ function devRowsToAdd(externals, rows) {
|
|
|
957
964
|
continue;
|
|
958
965
|
if (have[String(r.ref)])
|
|
959
966
|
continue;
|
|
960
|
-
out.push({ type: r.type || "github-issues", name: r.ref, ref: r.ref });
|
|
967
|
+
out.push({ type: r.type || "github-issues", name: r.ref, ref: r.ref, origin: "explicit" });
|
|
961
968
|
}
|
|
962
969
|
return out;
|
|
963
970
|
}
|
|
@@ -1627,7 +1634,7 @@ function keyMissingText(cap) {
|
|
|
1627
1634
|
*/
|
|
1628
1635
|
const BAD_STATE_STATUSES = {
|
|
1629
1636
|
ingested: ["failed", "skipped"],
|
|
1630
|
-
reachable: ["not_in_channel", "missing_scope", "no_token", "unreachable", "not_in_space", "no_credentials"],
|
|
1637
|
+
reachable: ["not_in_channel", "missing_scope", "no_token", "unreachable", "not_in_space", "no_credentials", "no_consent", "transcripts_api_disabled", "no_access_policy", "speaker_attribution_off", "folder_not_granted"],
|
|
1631
1638
|
};
|
|
1632
1639
|
/**
|
|
1633
1640
|
* タイル1行(と接続グラフの1ノード)の状態を、**正本から導出する**(0.12.0)。
|
|
@@ -3326,6 +3333,56 @@ const CLIENT_JS = `
|
|
|
3326
3333
|
var SITE = JSON.parse(document.getElementById("site-data").textContent);
|
|
3327
3334
|
var ADAPTER_ICONS = ${JSON.stringify(ADAPTER_ICONS)};
|
|
3328
3335
|
|
|
3336
|
+
// ---- intake(操作の受け口)への共通の呼び出し(#349)----
|
|
3337
|
+
//
|
|
3338
|
+
// **全 op はここを通す。** 名乗り券(ポータルが出す Cookie の cortex-actor)を body に添えるのは
|
|
3339
|
+
// この1箇所だけ。fetch を直書きすると、その op だけ操作者が記録されない。
|
|
3340
|
+
// 券は document.cookie から**1回だけ**読んでメモリに持つ。site-data にも localStorage にも書かない
|
|
3341
|
+
// (ビルド時の値ではなく、開いた人ごとに違う値なので)。
|
|
3342
|
+
//
|
|
3343
|
+
// **1回だけ読むのは仕様。** ポータルからログアウトしても、開いたままのタブは券の期限まで
|
|
3344
|
+
// 名乗り続ける——署名付き Cookie と同じ性質で、券の寿命がそのまま名乗りの寿命になる。
|
|
3345
|
+
var ACTOR_COOKIE = "cortex-actor";
|
|
3346
|
+
var actorTicketCache;
|
|
3347
|
+
function actorTicket() {
|
|
3348
|
+
if (actorTicketCache !== undefined) return actorTicketCache;
|
|
3349
|
+
actorTicketCache = null;
|
|
3350
|
+
try {
|
|
3351
|
+
var parts = String(document.cookie || "").split(";");
|
|
3352
|
+
for (var i = 0; i < parts.length; i++) {
|
|
3353
|
+
var kv = parts[i].trim();
|
|
3354
|
+
if (kv.indexOf(ACTOR_COOKIE + "=") === 0) { actorTicketCache = kv.slice(ACTOR_COOKIE.length + 1) || null; break; }
|
|
3355
|
+
}
|
|
3356
|
+
} catch (e) { actorTicketCache = null; }
|
|
3357
|
+
return actorTicketCache;
|
|
3358
|
+
}
|
|
3359
|
+
/**
|
|
3360
|
+
* intake の op を1回呼ぶ。POST は JSON の body に名乗り券(あれば)を actor として足す。
|
|
3361
|
+
* GET(opts.method === "GET" のとき)はカスタムヘッダも body も付けない(preflight を増やさないため・#198)。
|
|
3362
|
+
* 戻り値は fetch の Promise そのもの(呼び出し側の .then / await / res.json() はそのまま使える)。
|
|
3363
|
+
*/
|
|
3364
|
+
function callIntake(op, body, opts) {
|
|
3365
|
+
var intake = SITE.intake;
|
|
3366
|
+
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
3367
|
+
var url = pfx + "op=" + encodeURIComponent(op) + "&t=" + encodeURIComponent(intake.token);
|
|
3368
|
+
var o = opts || {};
|
|
3369
|
+
if (o.method === "GET") return fetch(url, { signal: o.signal });
|
|
3370
|
+
var payload = body && typeof body === "object" ? body : {};
|
|
3371
|
+
var ticket = actorTicket();
|
|
3372
|
+
if (ticket) {
|
|
3373
|
+
var withActor = {};
|
|
3374
|
+
for (var k in payload) if (Object.prototype.hasOwnProperty.call(payload, k)) withActor[k] = payload[k];
|
|
3375
|
+
withActor.actor = ticket;
|
|
3376
|
+
payload = withActor;
|
|
3377
|
+
}
|
|
3378
|
+
return fetch(url, {
|
|
3379
|
+
method: "POST",
|
|
3380
|
+
headers: { "content-type": "application/json" },
|
|
3381
|
+
body: JSON.stringify(payload),
|
|
3382
|
+
signal: o.signal,
|
|
3383
|
+
});
|
|
3384
|
+
}
|
|
3385
|
+
|
|
3329
3386
|
// ---- ビルド時TSと共有する判定(唯一の正本は上の関数定義) ----
|
|
3330
3387
|
//
|
|
3331
3388
|
// **写経しない。** 接続マップ(ビルド時にSVGを描く)と画面(ブラウザで一覧を描く)が
|
|
@@ -3688,14 +3745,9 @@ ${deriveCapTile.toString()}
|
|
|
3688
3745
|
var endBusy = beginBusy(btn, "確認中…");
|
|
3689
3746
|
setStatus("", false);
|
|
3690
3747
|
var who = String(name || "").trim();
|
|
3691
|
-
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
3692
3748
|
var res, j;
|
|
3693
3749
|
try {
|
|
3694
|
-
res = await
|
|
3695
|
-
method: "POST",
|
|
3696
|
-
headers: { "content-type": "application/json" },
|
|
3697
|
-
body: JSON.stringify({ projectKey: intake.projectKey, path: path, submitter: who }),
|
|
3698
|
-
});
|
|
3750
|
+
res = await callIntake("promote", { projectKey: intake.projectKey, path: path, submitter: who });
|
|
3699
3751
|
j = await res.json().catch(function () { return {}; });
|
|
3700
3752
|
} catch (e) {
|
|
3701
3753
|
endBusy();
|
|
@@ -4406,6 +4458,44 @@ ${deriveCapTile.toString()}
|
|
|
4406
4458
|
cls: "ds-gate-muted",
|
|
4407
4459
|
help: "管理者の設定が済むと読み取りが始まります。",
|
|
4408
4460
|
},
|
|
4461
|
+
// --- ここから Microsoft 365(#335)。**値の正本は infra 側の語彙表**
|
|
4462
|
+
// (slack-gate.mjs の SLACK_GATE_VALUES と connection-state-keys.mjs の
|
|
4463
|
+
// REACHABLE_STATUSES)で、1対1の一致を infra のテストと
|
|
4464
|
+
// viewer/test/state-vocab-parity.test.mjs が見張る。
|
|
4465
|
+
// **判定を返すのは engine の夜間実測(1-E 以降)**——画面は語彙と文面だけを先に持つ
|
|
4466
|
+
// (判定器そのものは infra/lambda/shared の teams-gate.mjs / sharepoint-gate.mjs /
|
|
4467
|
+
// teams-chat-gate.mjs に既にある)。
|
|
4468
|
+
//
|
|
4469
|
+
// **バッジは短語・次の一手は help に分ける**(DS_GATE_NO_TOKEN と同じ作り。
|
|
4470
|
+
// バッジに長文を入れると行が折り返す)。**内部語を出さない**——証明書・トークン・
|
|
4471
|
+
// テナント・サービスプリンシパルは、読む人が自分の画面で探せない言葉
|
|
4472
|
+
"no_consent": {
|
|
4473
|
+
text: "管理者の承認が必要です",
|
|
4474
|
+
cls: "ds-gate-warn",
|
|
4475
|
+
help: "貴社の Microsoft 365 管理者が承認リンクを開いて許可すると読み取りが始まります。承認を取り消した場合もこの表示になります。",
|
|
4476
|
+
},
|
|
4477
|
+
"transcripts_api_disabled": {
|
|
4478
|
+
text: "文字起こしの外部取得がオフです",
|
|
4479
|
+
cls: "ds-gate-warn",
|
|
4480
|
+
help: "Teams 管理センターの会議設定で「文字起こしへの API アクセス」をオンにしてください。",
|
|
4481
|
+
},
|
|
4482
|
+
"no_access_policy": {
|
|
4483
|
+
text: "会議へのアクセス許可が未設定です",
|
|
4484
|
+
cls: "ds-gate-warn",
|
|
4485
|
+
help: "管理者がこの主催者にアクセス ポリシーを割り当てると読み取りが始まります(反映まで最大30分)。",
|
|
4486
|
+
},
|
|
4487
|
+
// **承認済み・API アクセスもオンなのに、話者名のトグルだけがオフ**という状態が実在する。
|
|
4488
|
+
// transcripts_api_disabled に寄せると、既にオンにしてある設定をもう一度案内することになる
|
|
4489
|
+
"speaker_attribution_off": {
|
|
4490
|
+
text: "話者名付きの文字起こしがオフです",
|
|
4491
|
+
cls: "ds-gate-warn",
|
|
4492
|
+
help: "Teams 管理センターの会議設定で話者名付き文字起こしをオンにしてください。オフのままだと取り込みません。",
|
|
4493
|
+
},
|
|
4494
|
+
"folder_not_granted": {
|
|
4495
|
+
text: "フォルダへのアクセス許可がありません",
|
|
4496
|
+
cls: "ds-gate-warn",
|
|
4497
|
+
help: "SharePoint 管理者がこのフォルダに読み取り許可を付与すると取り込みが始まります。",
|
|
4498
|
+
},
|
|
4409
4499
|
"unknown": { text: "不明", cls: "ds-gate-muted" },
|
|
4410
4500
|
};
|
|
4411
4501
|
/* ---------------------------------------------------------------------------
|
|
@@ -4479,16 +4569,26 @@ ${deriveCapTile.toString()}
|
|
|
4479
4569
|
},
|
|
4480
4570
|
};
|
|
4481
4571
|
/**
|
|
4482
|
-
* 休止状態の行に、状態の語に添えて**押す前から**出す定型の補足(#346
|
|
4483
|
-
*
|
|
4484
|
-
* {
|
|
4572
|
+
* 休止状態の行に、状態の語に添えて**押す前から**出す定型の補足(#346)と、
|
|
4573
|
+
* 「接続を確認」を押した結果に添える定型の1文(#356)。
|
|
4574
|
+
* 鍵は「アダプタ種別(helpTypeOf)× 状態」。値は { resting, probed } で、どちらも文の
|
|
4575
|
+
* パーツの配列。文字列はテキスト、{ link: <リンクの文字列> } は GitHub App の
|
|
4576
|
+
* インストール設定へのリンク(GITHUB_APP_INSTALL_URL)。
|
|
4577
|
+
*
|
|
4578
|
+
* ## 文の長さ(#356・オーナー却下を受けた原則)
|
|
4579
|
+
* **帯は症状だけ・行は具体的な一手だけ・説明を繰り返さない。** 0.12.22 では帯と行と
|
|
4580
|
+
* 押した結果に同じ admin の4文が3回出ており、オーナーが「長すぎ・冗長」と却下した。
|
|
4581
|
+
* - resting … **1文+リンクだけ**(誰が・どこで。「何が起きているか」は帯が言う)
|
|
4582
|
+
* - probed … **状態に応じた1文だけ**(1行目のサーバの needed が言わないことだけ)。
|
|
4583
|
+
* 押した結果に resting を繰り返さない——resting は押した瞬間に隠れ、needed が
|
|
4584
|
+
* 同じ操作(Configure から追加)を宛先つきで言う
|
|
4585
|
+
* 「admin」の語は画面に1回だけ(github-state-reason.test.mjs が押す前・押した後で数える)。
|
|
4485
4586
|
*
|
|
4486
4587
|
* ## なぜ画面の表で持つのか
|
|
4487
4588
|
* サーバの needed / detail は「何が起きているか」と「どこを開くか」までを持つが、
|
|
4488
|
-
* **誰がその操作をできるか**(リポジトリの admin
|
|
4489
|
-
*
|
|
4490
|
-
*
|
|
4491
|
-
* ここ、という役割分担にする。
|
|
4589
|
+
* **誰がその操作をできるか**(リポジトリの admin)と **request の意味**(組織オーナーの
|
|
4590
|
+
* 承認待ち)は、夜間(engine)とボタン(Lambda)の2つの書き手が別々に文を作るので、
|
|
4591
|
+
* サーバ側で足すと片方だけ古くなる。判定と URL はサーバ、定型の補足はここ、という役割分担。
|
|
4492
4592
|
*
|
|
4493
4593
|
* 🔴 **DS_GATE には入れない**(実測が返す語彙の表で、突き合わせテストの対象)。
|
|
4494
4594
|
* DS_GATE_NO_TOKEN と同じく、仕組みはアダプタ非依存・データだけがアダプタ固有。
|
|
@@ -4500,21 +4600,29 @@ ${deriveCapTile.toString()}
|
|
|
4500
4600
|
* 片方だけ古くなる)。
|
|
4501
4601
|
*
|
|
4502
4602
|
* エントリがある状態では**この文だけ**を出し、サーバの needed / detail は出さない
|
|
4503
|
-
*
|
|
4504
|
-
*
|
|
4603
|
+
* ——理由文と補足が issues / discussions の2行 × N リポに並ぶと、一覧が案内で埋まる
|
|
4604
|
+
* (DS_GATE_NO_TOKEN.github の項と同じ判断)。needed は押した結果が持つ。
|
|
4605
|
+
*
|
|
4606
|
+
* ⚠ **「移動・改名・削除の可能性 → 登録から外してください」は出さない。** App のトークン
|
|
4607
|
+
* では「未選択」と「消えた・改名」がどちらも 404 で**区別できない**(github-gate.mjs)。
|
|
4608
|
+
* 状態で出し分ける材料が無いので書かない。消えたリポジトリの逃げ道は、行に常に出る
|
|
4609
|
+
* 「登録から削除」(#354)が担う。区別する信号ができたら probed に足す
|
|
4505
4610
|
*/
|
|
4506
|
-
var GITHUB_ADMIN_HELP = "このリポジトリの admin(管理者権限を持つ人)であれば、Configure から自分で追加できます(承認は不要です)。"
|
|
4507
|
-
+ "admin でない場合は、そのリポジトリの admin の人に「Cortex の GitHub App の対象にこのリポジトリを追加してください」と依頼してください。"
|
|
4508
|
-
+ "GitHub 側で request と表示された場合は、組織オーナーの承認待ちです。"
|
|
4509
|
-
+ "追加したあと「接続を確認」を押して、読めるようになったことを確かめてください。";
|
|
4510
4611
|
var DS_GATE_RESTING_HELP = {
|
|
4511
4612
|
github: {
|
|
4512
|
-
unreachable:
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4613
|
+
unreachable: {
|
|
4614
|
+
// 誰が(admin)・どこで(Configure の Repository access)だけ。理由は帯、宛先はリンクが持つ。
|
|
4615
|
+
// 着地点(Repository access)を名指しするのは、押す前の画面からこの語が消えないため
|
|
4616
|
+
//(設計レビュー②)。「admin が…してください」はオーナーの原文の形
|
|
4617
|
+
resting: [
|
|
4618
|
+
"このリポジトリの admin(管理者権限を持つ人)が、Configure の Repository access に追加してください。",
|
|
4619
|
+
{ link: "インストール設定を開く" },
|
|
4620
|
+
],
|
|
4621
|
+
// 2026-09-02 の実測: admin でないリポジトリを Configure で選ぶと「request」タグが付き、
|
|
4622
|
+
// 組織オーナーの承認待ちになる("Okay, updated" と出るのに対象に入らない)。
|
|
4623
|
+
// 1行目(サーバの needed)はこれを言わないので、ここだけが持つ
|
|
4624
|
+
probed: ["GitHub 側で request と表示された場合は、組織オーナーの承認待ちです。"],
|
|
4625
|
+
},
|
|
4518
4626
|
},
|
|
4519
4627
|
};
|
|
4520
4628
|
/**
|
|
@@ -4526,11 +4634,20 @@ ${deriveCapTile.toString()}
|
|
|
4526
4634
|
var t = String(type || "");
|
|
4527
4635
|
return t.indexOf("github") === 0 ? "github" : t;
|
|
4528
4636
|
}
|
|
4529
|
-
|
|
4530
|
-
function restingHelpPartsOf(type, gate) {
|
|
4637
|
+
function restingHelpEntryOf(type, gate) {
|
|
4531
4638
|
var byType = DS_GATE_RESTING_HELP[helpTypeOf(type)];
|
|
4532
4639
|
return (byType && byType[gate]) || null;
|
|
4533
4640
|
}
|
|
4641
|
+
/** 休止状態の行に出すパーツ(無ければ null) */
|
|
4642
|
+
function restingHelpPartsOf(type, gate) {
|
|
4643
|
+
var e = restingHelpEntryOf(type, gate);
|
|
4644
|
+
return (e && e.resting) || null;
|
|
4645
|
+
}
|
|
4646
|
+
/** 押した結果に添えるパーツ(無ければ null)。行と同じ表から引く(写経しない) */
|
|
4647
|
+
function probedHelpPartsOf(type, gate) {
|
|
4648
|
+
var e = restingHelpEntryOf(type, gate);
|
|
4649
|
+
return (e && e.probed) || null;
|
|
4650
|
+
}
|
|
4534
4651
|
/** パーツを1段落にする。包む要素の class は置き場所で違う(行は ds-gate-help・押した結果は ds-probe-help) */
|
|
4535
4652
|
function restingHelpNode(parts, cls) {
|
|
4536
4653
|
var p = el("p", { class: cls });
|
|
@@ -4895,12 +5012,7 @@ ${deriveCapTile.toString()}
|
|
|
4895
5012
|
msg.className = "ds-toggle-msg";
|
|
4896
5013
|
msg.textContent = "承認画面を準備しています…";
|
|
4897
5014
|
try {
|
|
4898
|
-
var
|
|
4899
|
-
var res = await fetch(pfx + "op=slack-oauth-start&t=" + encodeURIComponent(intake.token), {
|
|
4900
|
-
method: "POST",
|
|
4901
|
-
headers: { "content-type": "application/json" },
|
|
4902
|
-
body: "{}",
|
|
4903
|
-
});
|
|
5015
|
+
var res = await callIntake("slack-oauth-start", {});
|
|
4904
5016
|
var j = await res.json().catch(function () { return {}; });
|
|
4905
5017
|
if (!res.ok || !j.url) {
|
|
4906
5018
|
// サーバの文言をそのまま出す(未設定のときは「準備中です」が返る)
|
|
@@ -4959,7 +5071,6 @@ ${deriveCapTile.toString()}
|
|
|
4959
5071
|
orgResolveDone = true;
|
|
4960
5072
|
var intake = SITE.intake;
|
|
4961
5073
|
if (!intake) return;
|
|
4962
|
-
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
4963
5074
|
// **描画の途中で投げない。** ここは行を組み立てている最中に呼ばれるので、
|
|
4964
5075
|
// 例外が出ると**画面そのものが描かれない**(fetch が無い環境で実際にそうなった)。
|
|
4965
5076
|
// 判定し直しは「できたら直る」性質のもので、失敗しても行は
|
|
@@ -4971,11 +5082,7 @@ ${deriveCapTile.toString()}
|
|
|
4971
5082
|
// fetch が存在しない(ReferenceError)と、呼び出しが投げる
|
|
4972
5083
|
if (typeof fetch !== "function") return;
|
|
4973
5084
|
try {
|
|
4974
|
-
|
|
4975
|
-
method: "POST",
|
|
4976
|
-
headers: { "content-type": "application/json" },
|
|
4977
|
-
body: "{}",
|
|
4978
|
-
})
|
|
5085
|
+
callIntake("slack-resolve", {})
|
|
4979
5086
|
.then(function (res) { return res.ok ? res.json() : null; })
|
|
4980
5087
|
.then(function (j) {
|
|
4981
5088
|
if (!j || !j.resolved) return;
|
|
@@ -5192,35 +5299,46 @@ ${deriveCapTile.toString()}
|
|
|
5192
5299
|
// App 導入済みの組織にも「まだ接続されていません」と出て、**同じ帯の本文と矛盾**した
|
|
5193
5300
|
// (実機でオーナーが踏み、利用者が「組織の接続からやり直し」と誤解した)
|
|
5194
5301
|
if (installed === true) {
|
|
5195
|
-
//
|
|
5196
|
-
//
|
|
5302
|
+
// 🔴 **帯は症状だけ(#356・オーナー却下を受けた原則)。** 0.12.22 ではここに9文
|
|
5303
|
+
// (App の説明・Configure の手順・admin の4文・移動改名削除・お客様の組織)を入れ、
|
|
5304
|
+
// 同じ説明が行と押した結果にも出て3回繰り返された。見出しは件数だけ・本文は2文だけ。
|
|
5305
|
+
// **組織名は見出しに入れない**——各行のバッジ「{組織}(GitHub App)」が持っている。
|
|
5306
|
+
// 組織が複数ある画面でも、組織ごとの帯のまま・見出しは同じ形。
|
|
5307
|
+
//
|
|
5308
|
+
// **見出しでは「読み取り対象に選ばれていません」と言い切らない。** 「appInstalled」 が
|
|
5309
|
+
// 分けられるのは「①未インストール」と「②未選択/③消えた・改名」までで、**②と③は
|
|
5310
|
+
// 分かれない**(App のトークンではどちらも 404)。見出しは事実だけを言う
|
|
5197
5311
|
out.push(el("div", {
|
|
5198
5312
|
class: "ds-orgnote-title",
|
|
5199
|
-
text: "⚠️ " +
|
|
5313
|
+
text: "⚠️ " + unread + "件のリポジトリを読み取れていません",
|
|
5200
5314
|
}));
|
|
5201
5315
|
// App は入っている。**インストールをもう一度促さないこと**——済んでいる操作を促すのは
|
|
5202
|
-
//
|
|
5316
|
+
// 「設定する必要が無いものに設定を促す」偽の警告と同じで、しかも直らない。
|
|
5317
|
+
//
|
|
5318
|
+
// 「誰が・どこで」は各行の1文(DS_GATE_RESTING_HELP)が持つ。ここで繰り返さない。
|
|
5319
|
+
// 「移動・改名・削除の可能性 → 登録から外して」も言わない——②と③を区別する材料が
|
|
5320
|
+
// 無く、外す手段は行の「登録から削除」(#354)が常に持つ。
|
|
5321
|
+
// 「お客様の組織では、組織のオーナーに承認を依頼」も外した——request(承認待ち)の
|
|
5322
|
+
// 1文は押した結果が持つ(同じ表の probed)。
|
|
5203
5323
|
//
|
|
5204
|
-
//
|
|
5205
|
-
//
|
|
5206
|
-
//
|
|
5207
|
-
//
|
|
5324
|
+
// ⚠ **件数の文 「head」(「{N}リポジトリ中 {M}件が読めていません。」)もこの枝では
|
|
5325
|
+
// 出さない(#356)。** #101 で3度直した「読める件数を出す」を意図して覆した——見出しが
|
|
5326
|
+
// 件数を持つので、本文で二重に言うと帯が3文になる。分母(登録数)は画面から消えるが、
|
|
5327
|
+
// 箱の中に行が全部並んでいるので数えられる。false / null の枝は従来どおり head を出す。
|
|
5208
5328
|
//
|
|
5209
|
-
//
|
|
5210
|
-
//
|
|
5211
|
-
//
|
|
5212
|
-
// いまの宛先と、そこに着ける人の条件は 「appSettingsLink」 の項にある。
|
|
5329
|
+
// **「各行の案内」ではなく「アクセス不可の行の案内」と言う。** 帯の箱には読めている行も
|
|
5330
|
+
// 一緒に入る(unread が1件でもあれば組織ごと warn)。案内を持つのは「アクセス不可」の
|
|
5331
|
+
// 行だけなので、行に出ている状態の語そのもので指す(設計レビュー②の指摘)。
|
|
5213
5332
|
//
|
|
5214
|
-
//
|
|
5215
|
-
//
|
|
5216
|
-
//
|
|
5333
|
+
// **「読み取り対象に入っていません」はオーナーの文(#356)。** 2026-08-21 の
|
|
5334
|
+
// 「②未選択と③消えた・改名を区別できないので断定しない」は、帯の本文については
|
|
5335
|
+
// この文で覆した(見出しは引き続き断定しない)。③の逃げ道は「登録から削除」。
|
|
5336
|
+
//
|
|
5337
|
+
// **設定画面の宛先は App 個別ページ(#346)。** いまの宛先と、そこに着ける人の条件は
|
|
5338
|
+
// 「appSettingsLink」 の項にある
|
|
5217
5339
|
out.push(el("p", {
|
|
5218
5340
|
class: "ds-group-note",
|
|
5219
|
-
text:
|
|
5220
|
-
+ "「インストール設定を開く」から " + g.title + " の Configure を開き、Repository access に対象のリポジトリを追加してください。"
|
|
5221
|
-
+ GITHUB_ADMIN_HELP
|
|
5222
|
-
+ "リポジトリ自体が一覧に見当たらない場合は、移動・改名・削除されている可能性があるので、登録から外してください。"
|
|
5223
|
-
+ "お客様の組織では、組織のオーナーに承認を依頼してください。",
|
|
5341
|
+
text: "GitHub App の読み取り対象に入っていません。アクセス不可の行の案内に従って追加してください。",
|
|
5224
5342
|
}));
|
|
5225
5343
|
out.push(appSettingsLink("インストール設定を開く →"));
|
|
5226
5344
|
return out;
|
|
@@ -5414,14 +5532,8 @@ ${deriveCapTile.toString()}
|
|
|
5414
5532
|
btn.disabled = true;
|
|
5415
5533
|
msg.className = "ds-toggle-msg";
|
|
5416
5534
|
msg.textContent = "実行中…";
|
|
5417
|
-
var intake = SITE.intake;
|
|
5418
|
-
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
5419
5535
|
try {
|
|
5420
|
-
var res = await
|
|
5421
|
-
method: "POST",
|
|
5422
|
-
headers: { "content-type": "application/json" },
|
|
5423
|
-
body: JSON.stringify({ kind: kind }),
|
|
5424
|
-
});
|
|
5536
|
+
var res = await callIntake("sync", { kind: kind });
|
|
5425
5537
|
var j = await res.json().catch(function () { return {}; });
|
|
5426
5538
|
// **起こせなかったときも「失敗」と言わない。** 定期実行が拾うので、
|
|
5427
5539
|
// 押した人にできることは無い。何が起きるかだけを伝える
|
|
@@ -7106,11 +7218,9 @@ ${deriveCapTile.toString()}
|
|
|
7106
7218
|
var giveUp = ctrl ? setTimeout(function () { ctrl.abort(); }, LIVE_CONFIRM_TIMEOUT_MS) : null;
|
|
7107
7219
|
// **成功・失敗の両方で外す。** 残すと、window を閉じないテストで node --test が終わらない
|
|
7108
7220
|
var clearGiveUp = function () { if (giveUp != null) { clearTimeout(giveUp); giveUp = null; } };
|
|
7109
|
-
|
|
7110
|
-
// GET
|
|
7111
|
-
|
|
7112
|
-
signal: ctrl ? ctrl.signal : undefined,
|
|
7113
|
-
})
|
|
7221
|
+
// GET で取る。**カスタムヘッダは付けない**(preflight を1往復増やさないため)。
|
|
7222
|
+
// 名乗り券は body に載せる仕組みなので、GET のこの op には付かない(#349)
|
|
7223
|
+
callIntake("harness-catalog", null, { method: "GET", signal: ctrl ? ctrl.signal : undefined })
|
|
7114
7224
|
.then(function (res) {
|
|
7115
7225
|
clearGiveUp();
|
|
7116
7226
|
if (!res.ok) throw new Error("http " + res.status);
|
|
@@ -8368,18 +8478,21 @@ ${deriveCapTile.toString()}
|
|
|
8368
8478
|
* 「App が入っていない」と「App は入っているがこのリポジトリが選ばれていない」の
|
|
8369
8479
|
* 言い分けも、設定ページの URL もあちらが決める——**画面で分岐を書き足さない**
|
|
8370
8480
|
* (書いた瞬間に判定が2箇所になり、夜間の実測とボタンでずれる)。
|
|
8371
|
-
*
|
|
8372
|
-
*
|
|
8481
|
+
* **ただし状態に応じた定型の1文だけは画面の表(DS_GATE_RESTING_HELP の probed)から引く**
|
|
8482
|
+
* (#346 → #356)——「request は組織オーナーの承認待ち」のような GitHub 側の意味は、
|
|
8483
|
+
* サーバの2つの書き手が別々に文を作るので、片方だけ古くなる。
|
|
8484
|
+
*
|
|
8485
|
+
* 🔴 **行の常時表示(resting)を押した結果に繰り返さない(#356)。** 0.12.22 では admin の
|
|
8486
|
+
* 4文が行と押した結果の両方に出ていた。行の1文は押した瞬間に隠れ、needed が同じ操作
|
|
8487
|
+
* (Configure から追加)を宛先つきで言うので、ここは needed が言わない1文だけ
|
|
8373
8488
|
*/
|
|
8374
8489
|
function githubProbeHelpNodes(r) {
|
|
8375
8490
|
if (r.gate === "ok") return [];
|
|
8376
8491
|
if (r.needed) {
|
|
8377
8492
|
var nodes = [neededNode(r.needed)];
|
|
8378
|
-
//
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
// 表のパーツ全部ではなく admin の4文(GITHUB_ADMIN_HELP)だけを添える
|
|
8382
|
-
if (restingHelpPartsOf("github", r.gate)) nodes.push(restingHelpNode([GITHUB_ADMIN_HELP], "ds-probe-help"));
|
|
8493
|
+
// 状態に応じた1文は**行と同じ表から引く**(ここに文を直書きすると表と割れる)
|
|
8494
|
+
var probed = probedHelpPartsOf("github", r.gate);
|
|
8495
|
+
if (probed) nodes.push(restingHelpNode(probed, "ds-probe-help"));
|
|
8383
8496
|
return nodes;
|
|
8384
8497
|
}
|
|
8385
8498
|
// needed が無いのは gate に落とし込めなかったとき。**生のエラーは隠さない**
|
|
@@ -8525,12 +8638,7 @@ ${deriveCapTile.toString()}
|
|
|
8525
8638
|
if (!intake) return;
|
|
8526
8639
|
var payload = { op: "refresh-channel-name", ref: s.ref };
|
|
8527
8640
|
if (s.workspace) payload.workspace = s.workspace;
|
|
8528
|
-
|
|
8529
|
-
fetch(pfx + "op=config&t=" + encodeURIComponent(intake.token), {
|
|
8530
|
-
method: "POST",
|
|
8531
|
-
headers: { "content-type": "application/json" },
|
|
8532
|
-
body: JSON.stringify(payload),
|
|
8533
|
-
}).then(function (res) {
|
|
8641
|
+
callIntake("config", payload).then(function (res) {
|
|
8534
8642
|
if (!res.ok) return;
|
|
8535
8643
|
// 一覧は夜間のスナップショットなので、その場では変わらない。行だけ追いつかせる
|
|
8536
8644
|
var nameEl = card.querySelector(".ds-name");
|
|
@@ -8591,13 +8699,8 @@ ${deriveCapTile.toString()}
|
|
|
8591
8699
|
// ワークスペースは Slack にしか無い概念なので、他アダプタでは載せない
|
|
8592
8700
|
var payload = { type: probeTypeOf(s.type), ref: s.ref };
|
|
8593
8701
|
if (s.workspace) payload.workspace = s.workspace;
|
|
8594
|
-
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
8595
8702
|
try {
|
|
8596
|
-
var res = await
|
|
8597
|
-
method: "POST",
|
|
8598
|
-
headers: { "content-type": "application/json" },
|
|
8599
|
-
body: JSON.stringify(payload),
|
|
8600
|
-
});
|
|
8703
|
+
var res = await callIntake("probe", payload);
|
|
8601
8704
|
var j = await res.json().catch(function () { return {}; });
|
|
8602
8705
|
if (!res.ok) {
|
|
8603
8706
|
// サーバの文言をそのまま出す(回数制限の案内・未対応のアダプタの説明を含んでいる)
|
|
@@ -9932,17 +10035,12 @@ ${deriveCapTile.toString()}
|
|
|
9932
10035
|
async function sendConfig(payload, msg, btn, onDone, hooks) {
|
|
9933
10036
|
var intake = SITE.intake;
|
|
9934
10037
|
if (!intake) return;
|
|
9935
|
-
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
9936
10038
|
// 押している間はボタンごと「処理中…」にする(#222・beginBusy の項)
|
|
9937
10039
|
var endBusy = beginBusy(btn);
|
|
9938
10040
|
msg.className = "ds-toggle-msg";
|
|
9939
10041
|
msg.textContent = "保存中…";
|
|
9940
10042
|
try {
|
|
9941
|
-
var res = await
|
|
9942
|
-
method: "POST",
|
|
9943
|
-
headers: { "content-type": "application/json" },
|
|
9944
|
-
body: JSON.stringify(payload),
|
|
9945
|
-
});
|
|
10043
|
+
var res = await callIntake("config", payload);
|
|
9946
10044
|
var j = await res.json().catch(function () { return {}; });
|
|
9947
10045
|
// 一覧が添えられていれば、断られていても先に画面を追いつかせる(#127)
|
|
9948
10046
|
var raced = hooks && hooks.onTargets && Array.isArray(j.targets) ? hooks.onTargets(j.targets) : false;
|
|
@@ -10962,17 +11060,15 @@ ${deriveCapTile.toString()}
|
|
|
10962
11060
|
var giveUp = ctrl ? setTimeout(function () { ctrl.abort(); }, LIVE_CONFIRM_TIMEOUT_MS) : null;
|
|
10963
11061
|
/** 見切りのタイマを外す。**応答が来たら必ず呼ぶ**(残すと次の取得を巻き込んで中断する) */
|
|
10964
11062
|
var clearGiveUp = function () { if (giveUp != null) { clearTimeout(giveUp); giveUp = null; } };
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
|
|
10973
|
-
|
|
10974
|
-
body: JSON.stringify(useFresh ? { caps: ALL_STATE_CAPS, fresh: true } : { caps: ALL_STATE_CAPS }),
|
|
10975
|
-
})
|
|
11063
|
+
// **常に全能力を要求する(ALL_STATE_CAPS の項)。** 知らない値は Lambda 側が黙って
|
|
11064
|
+
// 捨てる(断らない)ので、画面と Lambda の版が食い違っても接続状況の表示は消えない
|
|
11065
|
+
// **保存直後だけ据え置きを迂回させる。** これが無いと、サーバが保存前の答えを返し、
|
|
11066
|
+
// 足りない行が0件になって取り直しも張られない=手で再読み込みするまで追いつかない
|
|
11067
|
+
callIntake(
|
|
11068
|
+
"state",
|
|
11069
|
+
useFresh ? { caps: ALL_STATE_CAPS, fresh: true } : { caps: ALL_STATE_CAPS },
|
|
11070
|
+
{ signal: ctrl ? ctrl.signal : undefined },
|
|
11071
|
+
)
|
|
10976
11072
|
// **非2xxも失敗として扱う。** ビューアとLambdaの版は独立に進むので、
|
|
10977
11073
|
// op=state 未対応のLambdaは 400 を返す。通信エラーだけを見ていると空表示になる。
|
|
10978
11074
|
.then(function (res) {
|
|
@@ -11479,18 +11575,13 @@ ${deriveCapTile.toString()}
|
|
|
11479
11575
|
msg.className = "ds-toggle-msg";
|
|
11480
11576
|
msg.textContent = "保存中…";
|
|
11481
11577
|
var intake = SITE.intake;
|
|
11482
|
-
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
11483
11578
|
try {
|
|
11484
|
-
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
// **押した時点で読む。** 組み立て時に固めると、接続先を登録した直後に
|
|
11491
|
-
// 貼った鍵が「スペースを特定できません」で断られる
|
|
11492
|
-
body: JSON.stringify(secretPayload(intake, kind, value, cardSpace)),
|
|
11493
|
-
});
|
|
11579
|
+
// **シークレット名は送らない。** どの連携かだけを送り、書き込み先はサーバが案件から決める。
|
|
11580
|
+
// **Backlog はスペースだけ名乗る(#138)。** 名前を組み立てるのはサーバで、
|
|
11581
|
+
// こちらが渡すのは「どのスペースの鍵か」という材料だけ。
|
|
11582
|
+
// **押した時点で読む。** 組み立て時に固めると、接続先を登録した直後に
|
|
11583
|
+
// 貼った鍵が「スペースを特定できません」で断られる
|
|
11584
|
+
var res = await callIntake("secret", secretPayload(intake, kind, value, cardSpace));
|
|
11494
11585
|
var j = await res.json().catch(function () { return {}; });
|
|
11495
11586
|
if (!res.ok) {
|
|
11496
11587
|
msg.className = "ds-toggle-msg is-error";
|
|
@@ -12239,7 +12330,6 @@ ${deriveCapTile.toString()}
|
|
|
12239
12330
|
if (!entries || !entries.length) { setStatus("⚠ ファイルを選択してください。", true); return; }
|
|
12240
12331
|
if (isT && !meeting) { setStatus("⚠ 会議名を選んでください。", true); return; }
|
|
12241
12332
|
submitBtn.disabled = true;
|
|
12242
|
-
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
12243
12333
|
function fail(msg) { setStatus("✗ " + msg, true); submitBtn.disabled = false; }
|
|
12244
12334
|
try {
|
|
12245
12335
|
var uploaded = [];
|
|
@@ -12248,10 +12338,8 @@ ${deriveCapTile.toString()}
|
|
|
12248
12338
|
setStatus("アップロード中… (" + (i + 1) + "/" + entries.length + ") " + f.name, false);
|
|
12249
12339
|
var pres;
|
|
12250
12340
|
try {
|
|
12251
|
-
pres = await
|
|
12252
|
-
|
|
12253
|
-
body: JSON.stringify({ projectKey: intake.projectKey, filename: f.name, contentType: f.type || "application/octet-stream" }),
|
|
12254
|
-
}).then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); });
|
|
12341
|
+
pres = await callIntake("presign", { projectKey: intake.projectKey, filename: f.name, contentType: f.type || "application/octet-stream" })
|
|
12342
|
+
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); });
|
|
12255
12343
|
} catch (net) { return fail("サーバーに接続できませんでした。通信環境を確認して、もう一度お試しください。"); }
|
|
12256
12344
|
if (!pres.ok || !pres.j.url) return fail((pres.j && pres.j.message) || "アップロードURLの取得に失敗しました。対応していないファイル形式かもしれません。");
|
|
12257
12345
|
var put;
|
|
@@ -12269,10 +12357,8 @@ ${deriveCapTile.toString()}
|
|
|
12269
12357
|
try {
|
|
12270
12358
|
var payload = { projectKey: intake.projectKey, kind: kind, files: uploaded, submitter: submitter.trim() };
|
|
12271
12359
|
if (isT) payload.meeting = meeting;
|
|
12272
|
-
sub = await
|
|
12273
|
-
|
|
12274
|
-
body: JSON.stringify(payload),
|
|
12275
|
-
}).then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); });
|
|
12360
|
+
sub = await callIntake("submit", payload)
|
|
12361
|
+
.then(function (r) { return r.json().then(function (j) { return { ok: r.ok, j: j }; }); });
|
|
12276
12362
|
} catch (net3) { return fail("サーバーに接続できませんでした。もう一度お試しください。"); }
|
|
12277
12363
|
if (!sub.ok) return fail((sub.j && sub.j.message) || "取り込みに失敗しました。時間をおいて再度お試しください。");
|
|
12278
12364
|
status.className = "modal-status";
|
|
@@ -12630,15 +12716,10 @@ ${deriveCapTile.toString()}
|
|
|
12630
12716
|
var endBusy = beginBusy(btn, "削除中…");
|
|
12631
12717
|
msg.className = "record-delete-msg";
|
|
12632
12718
|
msg.textContent = "";
|
|
12633
|
-
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
12634
12719
|
var res, j;
|
|
12635
12720
|
try {
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
headers: { "content-type": "application/json" },
|
|
12639
|
-
// 名乗りは確認済み昇格で覚えたものを流用する(削除のためだけに名前を聞かない)
|
|
12640
|
-
body: JSON.stringify({ projectKey: intake.projectKey, path: path, submitter: rememberedVerifier() }),
|
|
12641
|
-
});
|
|
12721
|
+
// 名乗りは確認済み昇格で覚えたものを流用する(削除のためだけに名前を聞かない)
|
|
12722
|
+
res = await callIntake("delete-record", { projectKey: intake.projectKey, path: path, submitter: rememberedVerifier() });
|
|
12642
12723
|
j = await res.json().catch(function () { return {}; });
|
|
12643
12724
|
} catch (e) {
|
|
12644
12725
|
endBusy();
|
package/package.json
CHANGED