@takagaki/cortex-decisions-viewer 0.12.165 → 0.12.167
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 +68 -30
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -5140,7 +5140,7 @@ a.pager-btn:hover { text-decoration: none; }
|
|
|
5140
5140
|
使っていない)ので、暗色側の指定は置かない。押したあとの見た目は「取り消し線+無効化」 */
|
|
5141
5141
|
.record-delete-btn {
|
|
5142
5142
|
flex: 0 0 auto; cursor: pointer; white-space: nowrap;
|
|
5143
|
-
padding: 8px
|
|
5143
|
+
padding: 8px 18px; border-radius: 999px;
|
|
5144
5144
|
border: 1px solid #fca5a5; background: #fff; color: #b91c1c;
|
|
5145
5145
|
font-size: 13.5px; font-weight: 600;
|
|
5146
5146
|
}
|
|
@@ -5153,7 +5153,8 @@ a.pager-btn:hover { text-decoration: none; }
|
|
|
5153
5153
|
.record-delete-msg.is-error { color: #b91c1c; }
|
|
5154
5154
|
/* 帯の中では1行を占める(ボタンの並びの下へ回り込ませる)。操作列では右寄せのまま畳む */
|
|
5155
5155
|
.draft-note > .record-delete-msg { flex: 1 0 100%; }
|
|
5156
|
-
|
|
5156
|
+
/* ページ最下部の削除の口(レコード情報の下)。結果の行はボタンの下 */
|
|
5157
|
+
.record-delete-foot { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; margin: 24px 0 8px; }
|
|
5157
5158
|
.deleted-note {
|
|
5158
5159
|
display: flex; gap: 8px; align-items: flex-start; margin: 4px 0 16px;
|
|
5159
5160
|
background: #fff; border: 1px solid var(--border); border-radius: 8px;
|
|
@@ -6762,7 +6763,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
6762
6763
|
// **削除もここに並べる(2026-08-28 のオーナー裁定)。** AIが起票した記録に対して
|
|
6763
6764
|
// 人がやることは「引き取る(確認済みにする)」か「要らないと言う(削除)」の二択で、
|
|
6764
6765
|
// 同じ場面の同じ判断なので、口を離さない。**この帯は draft にしか出ない**ので、
|
|
6765
|
-
// draft
|
|
6766
|
+
// draft でない記録の削除の口はページの最下部(appendDeleteFoot)に置く。
|
|
6766
6767
|
function draftNote(rec) {
|
|
6767
6768
|
if (!rec || !unconfirmed(rec)) return null;
|
|
6768
6769
|
var path = promotableRecordPath(rec);
|
|
@@ -7075,7 +7076,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
7075
7076
|
}
|
|
7076
7077
|
/** 筋の札(一覧の行)。札が無ければ null */
|
|
7077
7078
|
function strandBadge(rec) {
|
|
7078
|
-
return hasStrand(rec) ? el("span", { class: "badge strand", title: "
|
|
7079
|
+
return hasStrand(rec) ? el("span", { class: "badge strand", title: "論点", text: rec.strand }) : null;
|
|
7079
7080
|
}
|
|
7080
7081
|
var FIRMNESS_CLASS = { "確定": "fixed", "仮": "tentative", "検討中": "open" };
|
|
7081
7082
|
/** 固さの小札。語彙外は出さない(ビルド側でも捨てている・二重の網) */
|
|
@@ -18900,7 +18901,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
18900
18901
|
// 筋の札(#1094)。札を持つ決定が 1 件も無い案件では出さない
|
|
18901
18902
|
var strandOpts = strandOptions(visibleRecords(SITE.decisions));
|
|
18902
18903
|
if (strandOpts.length) {
|
|
18903
|
-
var strandSel = buildSelect("
|
|
18904
|
+
var strandSel = buildSelect("すべての論点", strandOpts, listState.strand, function (v) { listState.strand = v; listState.page = 1; drawCards(); });
|
|
18904
18905
|
strandSel.classList.add("strand-filter");
|
|
18905
18906
|
filters.appendChild(strandSel);
|
|
18906
18907
|
}
|
|
@@ -19218,6 +19219,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19218
19219
|
//(acme.slack.com の acme の部分。fleet-status.json の slackWorkspaces[].domain)
|
|
19219
19220
|
var LI_SLACK_USER = /^[UW][A-Z0-9]{2,20}$/;
|
|
19220
19221
|
var LI_SLACK_DOMAIN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;
|
|
19222
|
+
// エンタープライズの組織は classmethod.enterprise.slack.com のように「<組織>.enterprise」の形(台帳の domain には入らない)
|
|
19223
|
+
var LI_SLACK_ENT_DOMAIN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.enterprise$/i;
|
|
19224
|
+
var LI_SLACK_CHANNEL_HOST = /^https:\\/\\/([a-z0-9.-]{1,200})\\.slack\\.com\\//i;
|
|
19221
19225
|
var LI_SLACK_TEAM = /^[TE][A-Z0-9]{2,20}$/;
|
|
19222
19226
|
// Backlog のユーザー(engine は userId=ログイン名、無い相手は数値 id を入れる)と、
|
|
19223
19227
|
// スペースのドメイン(fleet の backlogTarget。正本は 課題管理/issues-config.json)。
|
|
@@ -19273,8 +19277,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19273
19277
|
* 場が team_id の形なのにどれとも一致しなければ**リンク無し**
|
|
19274
19278
|
* 2. そうでなく、接続済みワークスペースが**ちょうど 1 つ**ならそれ
|
|
19275
19279
|
* 3. それ以外(0 個・2 個以上)は**リンク無し**
|
|
19276
|
-
* 🔴 **チャンネルの URL
|
|
19277
|
-
*
|
|
19280
|
+
* 🔴 **チャンネルの URL のホストは、台帳にドメインが無いときの最後の手だけ**(liSlackChannelHost。
|
|
19281
|
+
* 登録されたチャンネルの全部が同じホストのときだけ採る。共有チャンネルでは貼った人のホストに
|
|
19282
|
+
* なりうるので、食い違えばリンク無し)。**間違ったリンクは値だけより悪い**
|
|
19278
19283
|
*/
|
|
19279
19284
|
function liSlackDomain(scope) {
|
|
19280
19285
|
var list = slackWorkspaces() || [];
|
|
@@ -19290,7 +19295,33 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19290
19295
|
}
|
|
19291
19296
|
if (!pick && list.length === 1) pick = list[0];
|
|
19292
19297
|
var d = pick && typeof pick.domain === "string" ? pick.domain.trim() : "";
|
|
19293
|
-
|
|
19298
|
+
if (LI_SLACK_DOMAIN.test(d) || LI_SLACK_ENT_DOMAIN.test(d)) return d;
|
|
19299
|
+
// 台帳にドメインが無い(auth.test の url が点を含む組織のアドレスのとき等)ときは、
|
|
19300
|
+
// 案件に登録されたチャンネルの URL のホストから補う(liSlackChannelHost)
|
|
19301
|
+
return liSlackChannelHost(pick ? pick.teamId : "", !pick && list.length > 0);
|
|
19302
|
+
}
|
|
19303
|
+
/**
|
|
19304
|
+
* 登録済みの Slack チャンネル(fleet の externalSources)の URL から、ワークスペースのドメインを引く。
|
|
19305
|
+
*
|
|
19306
|
+
* 🔴 **登録されたチャンネルの URL が全部同じホストを指すときだけ**採る(共有チャンネルの
|
|
19307
|
+
* 貼り付け元のホストが混ざる案件では決められない=リンク無し)。ワークスペースが決まっているなら、
|
|
19308
|
+
* そのワークスペースのチャンネル(workspace が一致するもの)に絞る。**ワークスペースが複数あるのに
|
|
19309
|
+
* 決まっていない行(skipAll)は引かない**。ホストは slack.com の配下の https だけ
|
|
19310
|
+
*/
|
|
19311
|
+
function liSlackChannelHost(teamId, skipAll) {
|
|
19312
|
+
if (skipAll) return "";
|
|
19313
|
+
var srcs = (fleetVal("externalSources") || []).filter(function (x) {
|
|
19314
|
+
return x && x.type === "slack" && typeof x.url === "string" && (!teamId || x.workspace === teamId);
|
|
19315
|
+
});
|
|
19316
|
+
var host = "";
|
|
19317
|
+
for (var i = 0; i < srcs.length; i++) {
|
|
19318
|
+
var m = LI_SLACK_CHANNEL_HOST.exec(srcs[i].url);
|
|
19319
|
+
var h = m ? m[1].toLowerCase() : "";
|
|
19320
|
+
if (!LI_SLACK_DOMAIN.test(h) && !LI_SLACK_ENT_DOMAIN.test(h)) return "";
|
|
19321
|
+
if (host && host !== h) return "";
|
|
19322
|
+
host = h;
|
|
19323
|
+
}
|
|
19324
|
+
return host;
|
|
19294
19325
|
}
|
|
19295
19326
|
/**
|
|
19296
19327
|
* Backlog のユーザーのページを組むスペースのドメイン(決められなければ空文字)。
|
|
@@ -19528,7 +19559,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19528
19559
|
rec.deleted = true;
|
|
19529
19560
|
var title = app.querySelector(".detail-title");
|
|
19530
19561
|
if (title) title.classList.add("is-deleted");
|
|
19531
|
-
// **置き場は2つある**(draft
|
|
19562
|
+
// **置き場は2つある**(draft の警告帯の中/ページの最下部)。どちらに出ていても止める
|
|
19532
19563
|
var btns = app.querySelectorAll(".record-delete-btn");
|
|
19533
19564
|
for (var b = 0; b < btns.length; b++) { btns[b].disabled = true; btns[b].textContent = "削除しました"; }
|
|
19534
19565
|
// もう無い記録を直す口は押させない(AIで編集・GitHubで編集・確認済みにする)
|
|
@@ -19603,7 +19634,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19603
19634
|
*
|
|
19604
19635
|
* 呼び出し側は2つ:
|
|
19605
19636
|
* - draftNote …… 未確認の記録。「確認済みにする」と並べて警告帯の中に置く
|
|
19606
|
-
* -
|
|
19637
|
+
* - 詳細ページの最下部(appendDeleteFoot) …… 警告帯が出ない記録
|
|
19607
19638
|
*/
|
|
19608
19639
|
function buildDeleteControls(rec) {
|
|
19609
19640
|
var path = deletableRecordPath(rec);
|
|
@@ -19623,19 +19654,18 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19623
19654
|
return { btn: btn, msg: msg };
|
|
19624
19655
|
}
|
|
19625
19656
|
/**
|
|
19626
|
-
*
|
|
19657
|
+
* 警告帯が出ない記録の削除の口を、ページの一番下(「レコード情報(frontmatter)」の下・
|
|
19658
|
+
* 生成の行の上)へ置く。取り消せない操作を、高頻度の操作(AIで編集・GitHubで編集)の
|
|
19659
|
+
* 隣に置かない(2026-10-18 のオーナー指摘)。4 区画の詳細で同じ。
|
|
19627
19660
|
*
|
|
19628
19661
|
* **draft には出さない**——そちらは警告帯の中で「確認済みにする」と対になっている
|
|
19629
|
-
* (2つ出すと、同じ操作の口がページに2
|
|
19630
|
-
* 操作の隣に置くことにはなるが、**警告帯の無い記録には他に置き場が無い**。
|
|
19631
|
-
* 見た目は控えめな文字のボタンのままにして、隣の実体のあるボタンと重さを分ける。
|
|
19662
|
+
* (2つ出すと、同じ操作の口がページに2か所できる)。
|
|
19632
19663
|
*/
|
|
19633
|
-
function
|
|
19634
|
-
if (!rec || unconfirmed(rec)) return
|
|
19664
|
+
function appendDeleteFoot(rec) {
|
|
19665
|
+
if (!rec || unconfirmed(rec)) return;
|
|
19635
19666
|
var del = buildDeleteControls(rec);
|
|
19636
|
-
if (!del) return
|
|
19637
|
-
|
|
19638
|
-
return del.msg; // 結果を出す行は操作列の下(呼び出し側が最後に並べる)
|
|
19667
|
+
if (!del) return;
|
|
19668
|
+
app.appendChild(el("div", { class: "record-delete-foot" }, [del.btn, del.msg]));
|
|
19639
19669
|
}
|
|
19640
19670
|
/** 詳細ページの末尾(本文・参照の後)に、つながっている ID・AIの変更履歴・frontmatter を並べる */
|
|
19641
19671
|
function appendRecordFooter(rec) {
|
|
@@ -19646,6 +19676,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19646
19676
|
if (history) app.appendChild(history);
|
|
19647
19677
|
var fmp = renderFmPanel(rec.fm);
|
|
19648
19678
|
if (fmp) app.appendChild(fmp);
|
|
19679
|
+
appendDeleteFoot(rec);
|
|
19649
19680
|
// 開き直しても削除済みのまま見せる(印は rec が持っている)
|
|
19650
19681
|
if (rec.deleted) markRecordDeleted(rec);
|
|
19651
19682
|
}
|
|
@@ -19882,12 +19913,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19882
19913
|
if (r.editUrl) {
|
|
19883
19914
|
editRowR.appendChild(el("a", { class: "edit-btn", href: r.editUrl, target: "_blank", rel: "noopener", text: "GitHubで編集" }));
|
|
19884
19915
|
}
|
|
19885
|
-
// 警告帯が出ない記録の削除の口はここ(編集の行の末尾)。draft には出さない
|
|
19886
|
-
var delMsgR = attachDeleteToEditRow(r, editRowR);
|
|
19887
19916
|
head.appendChild(el("div", { class: "detail-actions" }, [
|
|
19888
19917
|
el("div", { class: "detail-actions-row" }, [ traceBtn2 ]),
|
|
19889
19918
|
editRowR.children.length ? editRowR : null,
|
|
19890
|
-
delMsgR,
|
|
19891
19919
|
]));
|
|
19892
19920
|
app.appendChild(head);
|
|
19893
19921
|
|
|
@@ -20774,12 +20802,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
20774
20802
|
if (d.editUrl) {
|
|
20775
20803
|
editRowD.appendChild(el("a", { class: "edit-btn", href: d.editUrl, target: "_blank", rel: "noopener", text: "GitHubで編集" }));
|
|
20776
20804
|
}
|
|
20777
|
-
// 警告帯が出ない記録の削除の口はここ(編集の行の末尾)。draft には出さない
|
|
20778
|
-
var delMsgD = attachDeleteToEditRow(d, editRowD);
|
|
20779
20805
|
head.appendChild(el("div", { class: "detail-actions" }, [
|
|
20780
20806
|
el("div", { class: "detail-actions-row" }, [ traceBtn ]),
|
|
20781
20807
|
editRowD.children.length ? editRowD : null,
|
|
20782
|
-
delMsgD,
|
|
20783
20808
|
]));
|
|
20784
20809
|
app.appendChild(head);
|
|
20785
20810
|
|
|
@@ -20805,7 +20830,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
20805
20830
|
|
|
20806
20831
|
// 筋(#1094)。札の無い決定では何も作らない
|
|
20807
20832
|
if (hasStrand(d)) {
|
|
20808
|
-
app.appendChild(el("div", { class: "section-label", text: "
|
|
20833
|
+
app.appendChild(el("div", { class: "section-label", text: "論点" }));
|
|
20809
20834
|
app.appendChild(el("div", { class: "decision-strand" }, [el("span", { class: "chip", text: d.strand })]));
|
|
20810
20835
|
}
|
|
20811
20836
|
|
|
@@ -21156,6 +21181,12 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
21156
21181
|
if (isHttp(target)) return el("a", { href: target, target: "_blank", rel: "noopener", text: target });
|
|
21157
21182
|
return el("span", { text: target });
|
|
21158
21183
|
}
|
|
21184
|
+
/** 値が http/https の URL 1 つだけ(前後の空白は落とす・空白を含むものは URL としない)なら、その URL。それ以外は空文字 */
|
|
21185
|
+
function fmHttpUrl(x) {
|
|
21186
|
+
if (typeof x !== "string") return "";
|
|
21187
|
+
var t = x.trim();
|
|
21188
|
+
return isHttp(t) && !/\\s/.test(t) ? t : "";
|
|
21189
|
+
}
|
|
21159
21190
|
var FM_EMPTY_TEXT = "(未記入)";
|
|
21160
21191
|
/** パネルの 1 値を文字にする。オブジェクト・配列は JSON([object Object] を出さない) */
|
|
21161
21192
|
function fmScalarText(x) {
|
|
@@ -21211,14 +21242,21 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
21211
21242
|
cell.appendChild(line);
|
|
21212
21243
|
});
|
|
21213
21244
|
} else if (Array.isArray(v)) {
|
|
21214
|
-
// 🔴 要素がオブジェクトなら JSON で出す(join に落とすと [object Object]
|
|
21215
|
-
|
|
21245
|
+
// 🔴 要素がオブジェクトなら JSON で出す(join に落とすと [object Object] になる)。
|
|
21246
|
+
// http/https の URL だけの要素はリンクにする(新しいタブ・それ以外の綴りは文字のまま)
|
|
21247
|
+
v.forEach(function (x, i) {
|
|
21248
|
+
if (i > 0) cell.appendChild(document.createTextNode(" / "));
|
|
21249
|
+
var u = fmHttpUrl(x);
|
|
21250
|
+
cell.appendChild(u
|
|
21251
|
+
? el("a", { href: u, target: "_blank", rel: "noopener", text: u })
|
|
21252
|
+
: el("span", { text: fmScalarText(x) }));
|
|
21253
|
+
});
|
|
21216
21254
|
} else if (v && typeof v === "object") {
|
|
21217
21255
|
cell.textContent = fmScalarText(v);
|
|
21218
21256
|
} else if (k === "source") {
|
|
21219
21257
|
cell.appendChild(fmTargetLink(String(v)));
|
|
21220
|
-
} else if (
|
|
21221
|
-
cell.appendChild(el("a", { href: v, target: "_blank", rel: "noopener", text: v }));
|
|
21258
|
+
} else if (fmHttpUrl(v)) {
|
|
21259
|
+
cell.appendChild(el("a", { href: fmHttpUrl(v), target: "_blank", rel: "noopener", text: fmHttpUrl(v) }));
|
|
21222
21260
|
} else {
|
|
21223
21261
|
cell.textContent = String(v);
|
|
21224
21262
|
}
|
package/package.json
CHANGED