@takagaki/cortex-decisions-viewer 0.4.80 → 0.4.81
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/build.js +5 -4
- package/dist/render.js +106 -230
- package/package.json +1 -1
package/dist/build.js
CHANGED
|
@@ -137,9 +137,10 @@ async function readFleetSources(repoRoot) {
|
|
|
137
137
|
name: String(s.name ?? ""),
|
|
138
138
|
ref: s.ref != null ? String(s.ref) : undefined,
|
|
139
139
|
url: s.url != null ? String(s.url) : undefined,
|
|
140
|
-
|
|
141
|
-
//
|
|
142
|
-
//
|
|
140
|
+
// **通すのは goldState だけ(`gold` の真偽値は落とす)。** slack は常に対象なので
|
|
141
|
+
// 真偽値は情報を持たず、github の除外は `excluded` の方が「正常な除外」だと
|
|
142
|
+
// 分かる(真偽値で見ていた頃は exclude 済みのリポにまで警告が付いた)。
|
|
143
|
+
// 画面はこの値で github の読み取り ON/OFF トグルの向きを決める。
|
|
143
144
|
goldState: s.goldState != null ? String(s.goldState) : undefined,
|
|
144
145
|
notify: typeof s.notify === "boolean" ? s.notify : undefined,
|
|
145
146
|
gate: s.gate != null ? String(s.gate) : undefined,
|
|
@@ -149,7 +150,7 @@ async function readFleetSources(repoRoot) {
|
|
|
149
150
|
origin: s.origin != null ? String(s.origin) : undefined,
|
|
150
151
|
// どの Slack ワークスペースのチャンネルか(#104)。**列挙し忘れると静かに消える**
|
|
151
152
|
// (このマッピングは素通しではなく明示の許可リスト)。落とすと、同じIDの
|
|
152
|
-
// チャンネルを2
|
|
153
|
+
// チャンネルを2つのワークスペースに持つ案件で「登録を解除」が別の行を消す
|
|
153
154
|
workspace: s.workspace != null ? String(s.workspace) : undefined,
|
|
154
155
|
}))
|
|
155
156
|
: undefined;
|
package/dist/render.js
CHANGED
|
@@ -160,15 +160,26 @@ const CM_TOOL_LABEL = {
|
|
|
160
160
|
* **同じ判定を使う**ためにここに置く。片方だけ直すと、同じ画面でマップが⚠️・直下が「接続OK」になる。
|
|
161
161
|
*
|
|
162
162
|
* 判定の考え方:
|
|
163
|
-
* -
|
|
164
|
-
*
|
|
165
|
-
* -
|
|
166
|
-
*
|
|
163
|
+
* - 明示的に読み取りから外したもの(`goldState === "excluded"`)は、読めなくて当たり前なので
|
|
164
|
+
* 警告しない。ただし通知先(`notify`)に使っているなら、届いていないこと自体が問題なので拾う。
|
|
165
|
+
* - それ以外は**警告する側に倒す**。「不明」を「対象外」と扱うと、本当に壊れているものが
|
|
166
|
+
* 黙って隠れる(フェイルオープン)。
|
|
167
|
+
*
|
|
168
|
+
* **`excluded` は github だけの状態。** `dev-sources.json` の `exclude` による除外で、
|
|
169
|
+
* slack 側の状態ではない——`channels.json` に載っているチャンネルは例外なく全て Gold 昇格の
|
|
170
|
+
* 対象になったので、slack は常に「読めるべきもの」。判定を `gold === false` に置いたままだと、
|
|
171
|
+
* engine が github の除外リポに付ける `gold: false` を slack と同じ意味で読むことになり、
|
|
172
|
+
* **exclude 済みの github リポに警告が付く**(除外は正常な状態)。
|
|
173
|
+
*
|
|
174
|
+
* **`notify` は見ない。** 以前は「除外されていても通知先なら繋がっている必要がある」として
|
|
175
|
+
* 例外にしていたが、`excluded` が github 専用になった今、engine が `notify` を付けるのは
|
|
176
|
+
* slack だけ(resolve-external-sources)なので**この節は決して成立しない**。残しておくと、
|
|
177
|
+
* 読み手には現役の分岐に見えて「github の通知先」という存在しない状態を想定させる。
|
|
167
178
|
*/
|
|
168
179
|
function sourceNeedsAttention(s) {
|
|
169
180
|
if (s.gate === "ok")
|
|
170
181
|
return false;
|
|
171
|
-
if (s.
|
|
182
|
+
if (s.goldState === "excluded")
|
|
172
183
|
return false;
|
|
173
184
|
return true;
|
|
174
185
|
}
|
|
@@ -1192,13 +1203,6 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1192
1203
|
.ds-inactive .ds-type, .ds-inactive .ds-name, .ds-inactive a.ds-name, .ds-inactive .ds-pipe-label { color: #9ca3af; }
|
|
1193
1204
|
.ds-inactive-note { font-size: 12px; color: #9ca3af; line-height: 1.6; flex: 0 0 auto; }
|
|
1194
1205
|
.ds-badges { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; flex: 0 0 auto; }
|
|
1195
|
-
.badge.ds-gold { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
|
|
1196
|
-
.badge.ds-excluded { background: #eceef1; color: #6b7280; }
|
|
1197
|
-
/* 保存は済んでいるが、接続状況の再計算(1〜2分)がまだのもの。**確定と同じ見た目にしない**
|
|
1198
|
-
——リロードで消えたときに「戻された」と読まれるため、点線で区別して (反映中) を添える。
|
|
1199
|
-
**幅と色まで指定する。** border-style だけだと、border を持たない .ds-excluded 側は
|
|
1200
|
-
初期値の medium(≈3px)/currentColor に解決され、押した向きによって太さ3倍・色が別物になる */
|
|
1201
|
-
.badge.is-pending { border: 1px dashed currentColor; opacity: 0.85; }
|
|
1202
1206
|
/* 能力モーダルは一覧(17チャンネル・19リポジトリ)を入れるので広く取る。
|
|
1203
1207
|
既定の480pxでは、チャンネル名+バッジ2つ+トグルが1行に収まらず折り返す。
|
|
1204
1208
|
画面の広さいっぱいまで使う——この画面は一覧を読むためのもので、
|
|
@@ -1252,7 +1256,6 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1252
1256
|
.ds-drive-note, .ds-inactive-note, .ds-legacy-chip, .ds-keys-code {
|
|
1253
1257
|
min-width: 0; white-space: normal; overflow-wrap: anywhere;
|
|
1254
1258
|
}
|
|
1255
|
-
.badge.ds-undeclared { background: #fff4e5; color: #9a6700; }
|
|
1256
1259
|
.ds-toggle { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 6px; }
|
|
1257
1260
|
.ds-toggle-btn { font-size: 12px; padding: 3px 10px; border-radius: 999px; border: 1px solid var(--border); background: #fff; color: var(--text); cursor: pointer; }
|
|
1258
1261
|
.ds-toggle-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
|
|
@@ -2169,9 +2172,12 @@ ${capabilityState.toString()}
|
|
|
2169
2172
|
*/
|
|
2170
2173
|
function openCapabilityModal(cap, items, note) {
|
|
2171
2174
|
var m = makeModal(cap, true);
|
|
2172
|
-
//
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
+
// **何が読み取られるのかを必ず書く。** 一覧に並ぶものと読み取られるものの関係は、
|
|
2176
|
+
// 書いていないと分からない(チャットは「載っていれば全部」、開発はリポジトリ単位でOFFできる)
|
|
2177
|
+
if (cap === "チャット") {
|
|
2178
|
+
m.modal.appendChild(el("p", { class: "modal-desc", text: "ここに並んでいるチャンネルは、例外なく全て毎晩の Gold 昇格が読み取り、顧客も見る Decision・用語集の材料になります。読み取りを止めるには「登録を解除」してください。" }));
|
|
2179
|
+
} else if (cap === "開発") {
|
|
2180
|
+
m.modal.appendChild(el("p", { class: "modal-desc", text: "ここに並んでいるリポジトリの Issues を毎晩の Gold 昇格が読み取ります。リポジトリ単位で読み取りを止められます(止めたものは読み取られません)。" }));
|
|
2175
2181
|
}
|
|
2176
2182
|
// **なぜこの状態なのかを、押した先でも読めるようにする(#125②)。** タイルは常時出す
|
|
2177
2183
|
// ようになったので、未接続の能力を押したときに中身が空になる場面が増えた。
|
|
@@ -2697,7 +2703,7 @@ ${capabilityState.toString()}
|
|
|
2697
2703
|
}
|
|
2698
2704
|
// 読み取り範囲。**この画面は顧客も見る。何をGoldに読んでいるかの開示が主眼**
|
|
2699
2705
|
//
|
|
2700
|
-
// **繋がっているときだけ出す。**
|
|
2706
|
+
// **繋がっているときだけ出す。** 「未使用」と読み取り範囲の内訳が
|
|
2701
2707
|
// 同じ行に並ぶと読めない。tools を none に倒しても externalSources は翌朝の
|
|
2702
2708
|
// 再生成まで残るので、使うのをやめた宣言の直後に必ず通る。
|
|
2703
2709
|
// 「⦿ 未接続 Driveフォルダ 0件」も同様(最終同期を出さないのと同じ理由)
|
|
@@ -2705,10 +2711,11 @@ ${capabilityState.toString()}
|
|
|
2705
2711
|
if (!connected) {
|
|
2706
2712
|
// 状態だけ出す
|
|
2707
2713
|
} else if (live.length) {
|
|
2708
|
-
//
|
|
2714
|
+
// 単位は分かるものだけ。知らない種別に勝手な単位を付けない。
|
|
2715
|
+
// **「N件をGoldに使用」の内訳は出さない。** チャンネルは載っていれば全部が対象で、
|
|
2716
|
+
// github の除外は行のトグルが持つ(件数の内訳は Gold トグルがあった頃の名残)
|
|
2709
2717
|
var unit = cap === "チャット" ? "チャンネル" : cap === "開発" ? "リポジトリ" : "件";
|
|
2710
|
-
|
|
2711
|
-
parts.push(live.length + unit + "/" + gold + "件をGoldに使用");
|
|
2718
|
+
parts.push(live.length + unit);
|
|
2712
2719
|
} else if (cap === "共有資料" && adapter === "google-drive" && internal && internal.driveFolderIds) {
|
|
2713
2720
|
// **そのタイルのアダプタを見る。** 宣言(tools)を見ていた頃は、local の案件
|
|
2714
2721
|
//(gdo・三菱)で「ローカル」と名乗ったタイルが「Driveフォルダ 0件」と語っていた。
|
|
@@ -2871,9 +2878,9 @@ ${capabilityState.toString()}
|
|
|
2871
2878
|
}
|
|
2872
2879
|
}
|
|
2873
2880
|
|
|
2874
|
-
// 注記は全能力の後ろに1
|
|
2881
|
+
// 注記は全能力の後ろに1つ。**何が Gold の材料になるのかを1文で言う。**
|
|
2875
2882
|
if (anyCap) {
|
|
2876
|
-
sec.appendChild(el("p", { class: "ds-note", text: "
|
|
2883
|
+
sec.appendChild(el("p", { class: "ds-note", text: "登録されている Slack チャンネルと GitHub リポジトリは、毎晩の Gold 昇格が読み取り、顧客も見る Decision・用語集の材料になります。チャンネルは登録を解除すると、リポジトリは読み取りを止めると、以後は読み取られません。" }));
|
|
2877
2884
|
}
|
|
2878
2885
|
|
|
2879
2886
|
if (pipes.length) {
|
|
@@ -2948,65 +2955,46 @@ ${capabilityState.toString()}
|
|
|
2948
2955
|
// 宣言を撤去したいま出す条件が無い。未接続の能力は能力タイル(常時表示)が状態と入口を持つ。
|
|
2949
2956
|
// 外部ソース1件のカード(グループ化表示・展開表示の両方から使う)
|
|
2950
2957
|
/**
|
|
2951
|
-
*
|
|
2958
|
+
* チャンネルの登録を解除するボタン(remove-channel)。押すと channels.json から行が消える。
|
|
2959
|
+
*
|
|
2960
|
+
* 注: ここは埋め込みJSのテンプレートリテラル内。**コメントでもバッククォートを使わない**
|
|
2961
|
+
*(リテラルが閉じて構文エラーになる。実際にそれで壊した)。
|
|
2962
|
+
*
|
|
2963
|
+
* **これが画面から読み取りを止める唯一の手段。** チャンネル単位の Gold トグルは撤去した
|
|
2964
|
+
* (載っているチャンネルは例外なく全て Gold 昇格の対象)。事故(社内限定の会話が顧客可視の
|
|
2965
|
+
* Gold へ流れ始めた)に画面から手を打てないと、git で channels.json を直接編集するしかない。
|
|
2952
2966
|
*
|
|
2953
|
-
*
|
|
2954
|
-
*
|
|
2955
|
-
*
|
|
2967
|
+
* **確認文に不可逆性を必ず書く。** 止まるのは今後の読み取りだけで、**既に Gold 層へ
|
|
2968
|
+
* 入った内容は消えない**(案件リポの git 履歴に残る)。「読み取りを止めます」だけだと
|
|
2969
|
+
* 「入ってしまった内容も消える」と読まれ、事故対応の判断を誤らせる。
|
|
2956
2970
|
*
|
|
2957
|
-
*
|
|
2958
|
-
*
|
|
2971
|
+
* 削除の作法は既存の removeButton(Figma・GitHub の削除)に揃える——確認は向きに
|
|
2972
|
+
* 関わらず必ず出し、成功しても一覧からは消さずに行へ取り消し線を引く(一覧は夜間
|
|
2973
|
+
* スナップショットなので、翌朝まで残るのが正しい状態)。
|
|
2959
2974
|
*/
|
|
2960
|
-
function
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
"「" + (s.name || s.ref) + "」の内容を、顧客も見る Decision・用語集に蒸留するようになります。",
|
|
2976
|
-
"",
|
|
2977
|
-
"社内限定の会話が含まれるチャンネルでは、顧客に見せられない内容が出てしまう可能性があります。",
|
|
2978
|
-
"顧客がこのチャンネルにいる(=すでに会話を見ている)場合にだけ有効にしてください。",
|
|
2979
|
-
"",
|
|
2980
|
-
"※ 今夜の蒸留(22時ごろ)までに止めれば取り込まれません。一度生成された記録は自動では消えません。",
|
|
2981
|
-
"",
|
|
2982
|
-
"有効にしますか?",
|
|
2983
|
-
],
|
|
2984
|
-
build: function (next) {
|
|
2975
|
+
function removeChannelButton(s, card) {
|
|
2976
|
+
return removeButton({
|
|
2977
|
+
label: "登録を解除",
|
|
2978
|
+
confirmLines: function () {
|
|
2979
|
+
return [
|
|
2980
|
+
"「" + (s.name || s.ref) + "」を、Gold 昇格の読み取り対象から外します。",
|
|
2981
|
+
"",
|
|
2982
|
+
"次回の Gold 昇格(毎晩22時ごろ)から、このチャンネルは読み取られなくなります。",
|
|
2983
|
+
"",
|
|
2984
|
+
"※ 既に Gold 層に入った内容は消えません(Decision・用語集はそのまま残ります)。",
|
|
2985
|
+
"",
|
|
2986
|
+
"解除しますか?",
|
|
2987
|
+
];
|
|
2988
|
+
},
|
|
2989
|
+
build: function () {
|
|
2985
2990
|
// **どのワークスペースのチャンネルかを必ず送る(#104)。** 落とすと、サーバ側は
|
|
2986
2991
|
// 既定ワークスペースの同じIDのエントリを探しに行き、「対象チャンネルが
|
|
2987
|
-
//
|
|
2988
|
-
var payload = { op: "
|
|
2992
|
+
// 見つかりません」か、最悪**別のワークスペースの同じIDのチャンネルを消す**
|
|
2993
|
+
var payload = { op: "remove-channel", ref: s.ref };
|
|
2989
2994
|
if (s.workspace) payload.workspace = s.workspace;
|
|
2990
2995
|
return payload;
|
|
2991
2996
|
},
|
|
2992
|
-
|
|
2993
|
-
// 一覧そのものは触らない(結果メッセージや他行の状態を巻き込まないため)。
|
|
2994
|
-
pending: function (next, toggleEl) {
|
|
2995
|
-
// **表示済みの値に戻したなら「反映中」ではない。** ON→OFF と押し直した場合、
|
|
2996
|
-
// 画面が出している値と一致するので待つものが無い。ここで消さないと、
|
|
2997
|
-
// 何も保留していないのに (反映中) が残り、リロードで消えて不可解に見える。
|
|
2998
|
-
var back = next === (s.gold === true);
|
|
2999
|
-
// 控えの鍵もワークスペース込み(#104。pendingKeyOf の doc)
|
|
3000
|
-
if (back) clearPendingGold(pendingKeyOf(s));
|
|
3001
|
-
else markPendingGold(pendingKeyOf(s), next);
|
|
3002
|
-
var card = toggleEl && toggleEl.parentNode;
|
|
3003
|
-
var badges = card && card.querySelector(".ds-badges");
|
|
3004
|
-
if (!badges) return;
|
|
3005
|
-
var b = badges.querySelector(".badge.ds-gold, .badge.ds-excluded, .badge.ds-undeclared");
|
|
3006
|
-
var spec = pendingBadgeSpec(next, back);
|
|
3007
|
-
if (b) { b.className = spec.cls; b.textContent = spec.text; }
|
|
3008
|
-
else badges.insertBefore(el("span", { class: spec.cls, text: spec.text }), badges.firstChild);
|
|
3009
|
-
},
|
|
2997
|
+
onDone: function () { card.classList.add("ds-removed"); },
|
|
3010
2998
|
});
|
|
3011
2999
|
}
|
|
3012
3000
|
|
|
@@ -3631,10 +3619,10 @@ ${capabilityState.toString()}
|
|
|
3631
3619
|
// 「会議はTeams・連絡はSlack」という普通の構成を表せない。teams を宣言した案件では
|
|
3632
3620
|
// フォームごと消え、**Slackを渡されているのに追加できない**状態になっていた。
|
|
3633
3621
|
//
|
|
3634
|
-
//
|
|
3635
|
-
//
|
|
3636
|
-
//
|
|
3637
|
-
//
|
|
3622
|
+
// **追加そのものが Gold 昇格の意思決定になった。** チャンネル単位の gold: true という
|
|
3623
|
+
// 二段目のゲートは撤去され、channels.json に載っているチャンネルは例外なく全て
|
|
3624
|
+
// 毎晩の Gold 昇格が読む。だから**確認はここに要る**——重い話(顧客可視の層へ出る)を
|
|
3625
|
+
// 伝える場所が他に無くなった。撤去した Gold トグルの確認文の趣旨をここへ移している。
|
|
3638
3626
|
//
|
|
3639
3627
|
// 注: ここは埋め込みJSのテンプレートリテラル内。**コメントでもバッククォートを使わない**
|
|
3640
3628
|
//(リテラルが閉じて構文エラーになる。実際にそれで壊した)。
|
|
@@ -3648,22 +3636,27 @@ ${capabilityState.toString()}
|
|
|
3648
3636
|
requiredNote: "チャンネルのURLを入力してください。",
|
|
3649
3637
|
// **招待の話を先頭に置く。** Slack の仕様で、ボットは**公開チャンネルでも**招待されるまで
|
|
3650
3638
|
// 中身を1件も読めない(conversations.history が not_in_channel を返す・2026-08-16 実測+公式ドキュメント)。
|
|
3651
|
-
//
|
|
3652
|
-
hint: "先に Slack でそのチャンネルを開き、下のコマンドを貼って Cortex を招待してください。公開チャンネルでも招待が必要で、招待していないと中身を読めません。そのあと、チャンネル名を右クリック →「リンクをコピー」で出るURL
|
|
3639
|
+
// そのあとに「追加=Gold 昇格の対象」を置く(手順と、その手順の重さ)。
|
|
3640
|
+
hint: "先に Slack でそのチャンネルを開き、下のコマンドを貼って Cortex を招待してください。公開チャンネルでも招待が必要で、招待していないと中身を読めません。そのあと、チャンネル名を右クリック →「リンクをコピー」で出るURLを下に貼ります。追加したチャンネルは毎晩の Gold 昇格の対象になり、顧客も見る Decision・用語集の材料になります(読み取りを止めるには、追加した行の「登録を解除」を押します)。招待前に登録すると名前は「名前未取得」になるので、招待してから追加するのがおすすめです。",
|
|
3653
3641
|
copyText: "/invite @Cortex",
|
|
3654
|
-
//
|
|
3655
|
-
//
|
|
3642
|
+
// 撤去した Gold トグルの確認文の趣旨をここへ移した。**追加が昇格の意思決定そのもの**
|
|
3643
|
+
// なので、社内限定の会話が顧客可視の層に出てしまう話はここで伝えるしかない
|
|
3644
|
+
// (実際にその事故が起きている)。あわせて他案件の取り違えも確認させる。
|
|
3656
3645
|
confirmLines: function (v) {
|
|
3657
3646
|
return [
|
|
3658
|
-
"
|
|
3659
|
-
"",
|
|
3660
|
-
"貼ったURLがこの案件のものか、もう一度確認してください。",
|
|
3647
|
+
"このチャンネルの内容を、顧客も見る Decision・用語集に蒸留するようになります。",
|
|
3661
3648
|
"",
|
|
3662
3649
|
v,
|
|
3663
3650
|
"",
|
|
3651
|
+
"社内限定の会話が含まれるチャンネルでは、顧客に見せられない内容が出てしまう可能性があります。",
|
|
3652
|
+
"顧客がこのチャンネルにいる(=すでに会話を見ている)場合にだけ追加してください。",
|
|
3653
|
+
"",
|
|
3654
|
+
"貼ったURLがこの案件のものか、もう一度確認してください。",
|
|
3655
|
+
"",
|
|
3664
3656
|
// Slack の仕様(公開チャンネルでも招待が要る)を、最後にもう一度置く。
|
|
3665
3657
|
// 「追加したのに何も取り込まれない」の原因のほとんどがこれ。
|
|
3666
3658
|
"※ Slack でこのチャンネルに Cortex を招待していないと、中身は読めません。",
|
|
3659
|
+
"※ 今夜の蒸留(22時ごろ)までに登録を解除すれば取り込まれません。一度生成された記録は自動では消えません。",
|
|
3667
3660
|
"",
|
|
3668
3661
|
"追加しますか?",
|
|
3669
3662
|
];
|
|
@@ -3707,20 +3700,15 @@ ${capabilityState.toString()}
|
|
|
3707
3700
|
|
|
3708
3701
|
// ---------- 設定の変更(?op=config)の共通部品 ----------
|
|
3709
3702
|
//
|
|
3710
|
-
// 確認 → 送信 → 結果表示、までを1
|
|
3711
|
-
//
|
|
3703
|
+
// 確認 → 送信 → 結果表示、までを1箇所に置く。操作ごとに書き写すと、
|
|
3704
|
+
// 片方だけ直したときにずれる(トグル・削除・追加のどれも同じ経路を通す)。
|
|
3712
3705
|
|
|
3713
3706
|
/**
|
|
3714
3707
|
* サーバへ設定変更を送る。**一覧は書き換えない**
|
|
3715
3708
|
* (接続状況は夜間バッチのスナップショットなので、「もう効いている」と誤解させないため)。
|
|
3716
3709
|
* 呼び出し側は onDone で自分のボタンの向きを反転させる。
|
|
3717
3710
|
*
|
|
3718
|
-
*
|
|
3719
|
-
* 押した内容を「(反映中)」として先に出す。出してよいのは (1) 保存の成否がサーバで
|
|
3720
|
-
* 確定していて推測が入らない (2) **確定した表示と見た目で区別できる**、の両方を満たす
|
|
3721
|
-
* ときだけ。区別しないと、リロードで消えたときに「戻された」と読まれる。
|
|
3722
|
-
*
|
|
3723
|
-
* **もう1つの例外が接続先の一覧(#127)。** 追加・削除の応答にはいまの一覧が必ず
|
|
3711
|
+
* **例外が接続先の一覧(#127)。** 追加・削除の応答にはいまの一覧が必ず
|
|
3724
3712
|
* 添えられていて(成功も、重複で断られたときも、世代がずれていたときも)、これは
|
|
3725
3713
|
* スナップショットではなく**サーバが書いた直後の確定値**なので、その場で描き直してよい。
|
|
3726
3714
|
* @param hooks { onTargets(list) → 画面が見ていた集合と違ったか, staleNote }
|
|
@@ -3796,9 +3784,7 @@ ${capabilityState.toString()}
|
|
|
3796
3784
|
|
|
3797
3785
|
/**
|
|
3798
3786
|
* ON/OFF のトグル。**戻す操作を必ず残す**(誤って有効にしたとき翌朝まで止められないのは許容できない)。
|
|
3799
|
-
* @param opts { on, labelOn, labelOff, confirmOn, build(next)
|
|
3800
|
-
* pending … 保存できた直後に、その行のバッジだけを「(反映中)」へ差し替える任意のフック。
|
|
3801
|
-
* 持たない操作は従来どおりボタンの向きだけを反転する(バッジは触らない)。
|
|
3787
|
+
* @param opts { on, labelOn, labelOff, confirmOn, build(next) }
|
|
3802
3788
|
*/
|
|
3803
3789
|
function stateToggle(opts) {
|
|
3804
3790
|
var wrap = el("div", { class: "ds-toggle" });
|
|
@@ -3817,11 +3803,9 @@ ${capabilityState.toString()}
|
|
|
3817
3803
|
if (next && opts.confirmOn && !confirmDanger(opts.confirmOn)) { msg.textContent = ""; return; }
|
|
3818
3804
|
sendConfig(opts.build(next), msg, btn, function () {
|
|
3819
3805
|
// **押した内容をボタンに反映し、逆向きの操作を残す。**
|
|
3806
|
+
// **カードごと作り直さない。** 上の msg に出した結果表示が消えてしまう
|
|
3820
3807
|
on = next;
|
|
3821
3808
|
paint();
|
|
3822
|
-
// バッジは「反映中」として先出しする(opts.pending がある操作だけ)。
|
|
3823
|
-
// **カードごと作り直さない。** 上の msg に出した結果表示が消えてしまう
|
|
3824
|
-
if (opts.pending) opts.pending(next, wrap);
|
|
3825
3809
|
});
|
|
3826
3810
|
});
|
|
3827
3811
|
wrap.appendChild(btn);
|
|
@@ -3949,123 +3933,14 @@ ${capabilityState.toString()}
|
|
|
3949
3933
|
}
|
|
3950
3934
|
|
|
3951
3935
|
/* ---------------------------------------------------------------------------
|
|
3952
|
-
* Gold
|
|
3953
|
-
*
|
|
3954
|
-
* 押しても一覧のバッジが変わるのは fleet-status.yml が完走したあと(1〜2分)。
|
|
3955
|
-
* その間バッジが古いままだと「押したのに何も起きない」に見える。
|
|
3936
|
+
* Gold 切り替えの「(画面反映待ち)」バッジ(pendingGold 一式)は**撤去した**。
|
|
3956
3937
|
*
|
|
3957
|
-
*
|
|
3958
|
-
*
|
|
3959
|
-
* 「確定した事実の先出し」であって楽観的な当て推量ではない。
|
|
3938
|
+
* チャンネル単位の Gold トグルが無くなったので、先出しする値が無い。残っている
|
|
3939
|
+
* sessionStorage(cortex.pendingGold:案件キー)は読み手が消えるだけなので無害。
|
|
3960
3940
|
*
|
|
3961
|
-
*
|
|
3962
|
-
*
|
|
3963
|
-
* 繰り返し警告してきた誤読そのものになる。だから (反映中) を付けて区別し、
|
|
3964
|
-
* さらに sessionStorage に持たせてリロードしても残す。
|
|
3965
|
-
*
|
|
3966
|
-
* 消えるのは「fleet-status が追いついたとき」か「TTL 切れ」。TTL が無いと、
|
|
3967
|
-
* ワークフローが落ちている案件で永久に「反映中」が残り、嘘の表示になる。
|
|
3941
|
+
* **削除の結果は行の取り消し線で示す**(removeButton の作法)。一覧は夜間
|
|
3942
|
+
* スナップショットから描かれるので、消したはずの行が翌朝まで残るのが正しい状態。
|
|
3968
3943
|
* ------------------------------------------------------------------------- */
|
|
3969
|
-
// **キーは案件別にする。** Slackの共有チャンネルは複数案件のCortexに同時に載りうるので、
|
|
3970
|
-
// 案件をまたぐキーにすると、案件Aで押した「反映中」が案件Bの同じ行に出る
|
|
3971
|
-
// (チュートリアルの既読キーが同じ理由で案件別になっている)。
|
|
3972
|
-
var PENDING_KEY = "cortex.pendingGold:" + ((SITE.intake && SITE.intake.projectKey) || "");
|
|
3973
|
-
var PENDING_TTL_MS = 15 * 60 * 1000;
|
|
3974
|
-
/**
|
|
3975
|
-
* 保存する形: { "<チャンネルID>": { value: boolean, at: number } }
|
|
3976
|
-
* at が無い/0 のエントリは期限切れとして落とす。
|
|
3977
|
-
* **型では守れない**(このコードは render.ts のテンプレートリテラル内で、tsc が見ない)。
|
|
3978
|
-
* 守るのはテストの仕事。
|
|
3979
|
-
*/
|
|
3980
|
-
|
|
3981
|
-
/**
|
|
3982
|
-
* 先出しバッジの見た目。**1箇所に集約する**——文言とクラスを2箇所に書くと片方だけ直る。
|
|
3983
|
-
*
|
|
3984
|
-
* **「反映中」とは書かない。** この画面の既存語彙では「反映」が2つの意味で使われていて、
|
|
3985
|
-
* 短いほう(数分)には必ず「一覧への」が付いている(サーバ文言「次回の Gold 昇格
|
|
3986
|
-
* (毎晩22時ごろ)から反映されます。一覧への反映には数分かかります」)。修飾なしの
|
|
3987
|
-
* 「反映中」だと、22時の蒸留の話と読めてしまう。
|
|
3988
|
-
*
|
|
3989
|
-
* とくに OFF 方向で害が大きい。**止めた時点で蒸留に対しては完全に効いている**
|
|
3990
|
-
* (Slack はミラーせず Gold 昇格が直接読むため)。待っているのは画面だけなので、
|
|
3991
|
-
* 「除外(反映中)」は「まだ除外されていない」と逆に読める。
|
|
3992
|
-
*/
|
|
3993
|
-
function pendingBadgeSpec(value, settled) {
|
|
3994
|
-
return {
|
|
3995
|
-
cls: "badge " + (value ? "ds-gold" : "ds-excluded") + (settled ? "" : " is-pending"),
|
|
3996
|
-
text: (value ? "Gold昇格の読み取り対象" : "除外") + (settled ? "" : "(画面反映待ち)"),
|
|
3997
|
-
};
|
|
3998
|
-
}
|
|
3999
|
-
|
|
4000
|
-
function readPending() {
|
|
4001
|
-
try {
|
|
4002
|
-
var raw = sessionStorage.getItem(PENDING_KEY);
|
|
4003
|
-
if (!raw) return {};
|
|
4004
|
-
var obj = JSON.parse(raw);
|
|
4005
|
-
if (!obj || typeof obj !== "object") return {};
|
|
4006
|
-
var now = Date.now();
|
|
4007
|
-
var out = {};
|
|
4008
|
-
for (var k in obj) {
|
|
4009
|
-
if (!Object.prototype.hasOwnProperty.call(obj, k)) continue;
|
|
4010
|
-
var e = obj[k];
|
|
4011
|
-
if (e && typeof e === "object" && now - (e.at || 0) < PENDING_TTL_MS) out[k] = e;
|
|
4012
|
-
}
|
|
4013
|
-
return out;
|
|
4014
|
-
} catch (_) {
|
|
4015
|
-
// sessionStorage が使えない環境(プライベートモード等)でも画面は出す
|
|
4016
|
-
return {};
|
|
4017
|
-
}
|
|
4018
|
-
}
|
|
4019
|
-
function writePending(map) {
|
|
4020
|
-
try { sessionStorage.setItem(PENDING_KEY, JSON.stringify(map)); } catch (_) {}
|
|
4021
|
-
}
|
|
4022
|
-
function clearPendingGold(key) {
|
|
4023
|
-
if (!key) return;
|
|
4024
|
-
var map = readPending();
|
|
4025
|
-
if (!(key in map)) return;
|
|
4026
|
-
delete map[key];
|
|
4027
|
-
writePending(map);
|
|
4028
|
-
}
|
|
4029
|
-
/**
|
|
4030
|
-
* 控えの鍵。**チャンネルIDだけでは足りない(#104)。**
|
|
4031
|
-
* IDはワークスペースの中でしか一意でないので、同じIDのチャンネルを2つのワークスペースに
|
|
4032
|
-
* 持つ案件では、片方で押した「反映中」が**もう片方の行にも出る**。
|
|
4033
|
-
*/
|
|
4034
|
-
function pendingKeyOf(s) {
|
|
4035
|
-
if (!s || !s.ref) return "";
|
|
4036
|
-
return s.workspace ? s.workspace + "\t" + s.ref : s.ref;
|
|
4037
|
-
}
|
|
4038
|
-
/** 押した内容を控える。fleet-status が追いつくまでの間だけ効く */
|
|
4039
|
-
function markPendingGold(key, value) {
|
|
4040
|
-
if (!key) return;
|
|
4041
|
-
var map = readPending();
|
|
4042
|
-
map[key] = { value: value === true, at: Date.now() };
|
|
4043
|
-
writePending(map);
|
|
4044
|
-
}
|
|
4045
|
-
/**
|
|
4046
|
-
* その行の「反映中」を引く。**実データが追いついていたら控えを捨てる。**
|
|
4047
|
-
* 捨てないと、正しくなった後も (反映中) が残り続ける。
|
|
4048
|
-
*/
|
|
4049
|
-
function pendingGoldFor(s) {
|
|
4050
|
-
var key = pendingKeyOf(s);
|
|
4051
|
-
if (!key) return null;
|
|
4052
|
-
var map = readPending();
|
|
4053
|
-
var e = map[key];
|
|
4054
|
-
if (!e) return null;
|
|
4055
|
-
// **「値が一致したら捨てる」だけでは足りない。** 別の人が直後に逆を押して、
|
|
4056
|
-
// その結果で追いついた場合、値が一致しないので控えが残り、TTL切れまで
|
|
4057
|
-
// 実際とは違う値を出し続ける。**押した時点より新しいスナップショットが来たら、
|
|
4058
|
-
// 値が何であれ控えは用済み**——サーバの答えのほうが新しいので、そちらを信じる。
|
|
4059
|
-
var snapshot = fleetVal("generatedAt");
|
|
4060
|
-
var snapAt = snapshot ? Date.parse(snapshot) : NaN;
|
|
4061
|
-
var stale = !isNaN(snapAt) && snapAt >= (e.at || 0);
|
|
4062
|
-
if (s.gold === e.value || stale) {
|
|
4063
|
-
delete map[s.ref];
|
|
4064
|
-
writePending(map);
|
|
4065
|
-
return null;
|
|
4066
|
-
}
|
|
4067
|
-
return e;
|
|
4068
|
-
}
|
|
4069
3944
|
|
|
4070
3945
|
/**
|
|
4071
3946
|
* 登録の由来の表示(#118)。値は fleet-status.json の origin
|
|
@@ -4112,16 +3987,9 @@ ${capabilityState.toString()}
|
|
|
4112
3987
|
|
|
4113
3988
|
function extSourceCard(s, meta) {
|
|
4114
3989
|
var badges = el("div", { class: "ds-badges" });
|
|
4115
|
-
|
|
4116
|
-
//
|
|
4117
|
-
//
|
|
4118
|
-
if (pending) {
|
|
4119
|
-
var spec = pendingBadgeSpec(pending.value, false);
|
|
4120
|
-
badges.appendChild(el("span", { class: spec.cls, text: spec.text }));
|
|
4121
|
-
}
|
|
4122
|
-
else if (s.gold === true) badges.appendChild(el("span", { class: "badge ds-gold", text: "Gold昇格の読み取り対象" }));
|
|
4123
|
-
else if (s.goldState === "undeclared") badges.appendChild(el("span", { class: "badge ds-undeclared", text: "未宣言(対象外)" }));
|
|
4124
|
-
else if (s.gold === false) badges.appendChild(el("span", { class: "badge ds-excluded", text: "除外" }));
|
|
3990
|
+
// **Gold 対象かのバッジは持たない。** 一覧に並ぶ Slack チャンネルは例外なく全て対象で、
|
|
3991
|
+
// 行ごとに「対象です」と書いても情報が増えない。github の除外は行のトグル
|
|
3992
|
+
// (「読み取りを始める/止める」)が向きで示す。
|
|
4125
3993
|
if (s.notify === true) badges.appendChild(el("span", { class: "badge ds-notify", text: "通知先" }));
|
|
4126
3994
|
// **どのワークスペースのチャンネルかを出す(#104)。** 同じチャンネル名が
|
|
4127
3995
|
// 2つのワークスペースに並びうるので、これが無いと「どっちの #general か」が読めない。
|
|
@@ -4136,8 +4004,10 @@ ${capabilityState.toString()}
|
|
|
4136
4004
|
// 登録の由来(#118)。**「登録から削除」が出る/出ないの理由がこれ。** 導出されたリポは
|
|
4137
4005
|
// 登録ファイルから消しても翌日また現れるので削除を出していないが、画面には
|
|
4138
4006
|
// 「同じ見た目の行なのに、片方にだけ削除がある」としか映らず、毎回考え直すことになる。
|
|
4139
|
-
// **GitHub の行だけに出す。**
|
|
4140
|
-
//
|
|
4007
|
+
// **GitHub の行だけに出す。** ORIGIN_HELP の文面がリポジトリと .gitmodules に
|
|
4008
|
+
// 特化していて、Slack に出すと嘘になる。Slack も由来で「登録を解除」を出し分ける
|
|
4009
|
+
// ようになった(explicit には出さない)が、Slack で explicit なのは登録ファイルに
|
|
4010
|
+
// 直接書いた例外的な行だけで、バッジのために文面をもう一組増やすには釣り合わない。
|
|
4141
4011
|
// #119 以降、新しいデータの github は必ず explicit(詳細は ORIGIN_LABEL)
|
|
4142
4012
|
if (String(s.type).indexOf("github") === 0 && ORIGIN_LABEL[s.origin]) {
|
|
4143
4013
|
badges.appendChild(el("span", {
|
|
@@ -4156,10 +4026,16 @@ ${capabilityState.toString()}
|
|
|
4156
4026
|
badges,
|
|
4157
4027
|
el("span", { class: "ds-gate " + gate.cls, text: gate.text }),
|
|
4158
4028
|
]);
|
|
4159
|
-
//
|
|
4160
|
-
// Slack
|
|
4161
|
-
|
|
4162
|
-
|
|
4029
|
+
// チャンネルの登録解除。書き込み経路(intake Lambda)がある案件でだけ出す。
|
|
4030
|
+
// **Slack だけ。** github は登録ファイルが別(dev-sources.json)で、下のトグルと
|
|
4031
|
+
// 「登録から削除」が担う。
|
|
4032
|
+
//
|
|
4033
|
+
// **explicit(=dev-sources.json だけに登録された行)には出さない。** 解除が書き換える
|
|
4034
|
+
// のは channels.json なので、そこに無い行は押しても必ず 404 になる。GitHub 側が
|
|
4035
|
+
// 同じ事故(押しても戻ってくる削除)を origin で避けているのと同じ理由で、向きが逆
|
|
4036
|
+
// ——Slack は channels.json 由来が derived なので、出すのは derived と both。
|
|
4037
|
+
if (SITE.intake && s.type === "slack" && s.ref && s.origin !== "explicit") {
|
|
4038
|
+
card.appendChild(removeChannelButton(s, card));
|
|
4163
4039
|
}
|
|
4164
4040
|
// GitHubリポの読み取り ON/OFF。OFF は exclude で表現される(導出されたリポも確実に落ちる)。
|
|
4165
4041
|
if (SITE.intake && s.type.indexOf("github") === 0 && s.ref) {
|
|
@@ -4803,8 +4679,8 @@ ${capabilityState.toString()}
|
|
|
4803
4679
|
* モーダルを app に載せて、中へフォーカスを移す。
|
|
4804
4680
|
*
|
|
4805
4681
|
* **「最初の focusable」に載せてはいけない。** 一覧の先頭に来るのは
|
|
4806
|
-
*
|
|
4807
|
-
*
|
|
4682
|
+
* 「読み取りを止める」「このファイルを外す」といった設定を書き換えるボタンで、
|
|
4683
|
+
* しかも**狭める向きは意図的に確認を出さない**
|
|
4808
4684
|
* (stateToggle の confirmOn は広げる向きだけ)。タイルを Enter で開いて
|
|
4809
4685
|
* もう一度 Enter を押しただけで、確認なしに設定ファイルが書き換わる。
|
|
4810
4686
|
* 移す先は閉じるボタン——押しても何も壊れないものにする。
|
package/package.json
CHANGED