@takagaki/cortex-decisions-viewer 0.12.82 → 0.12.83
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 +292 -33
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -4952,7 +4952,13 @@ button.site-icon[aria-busy="true"] .site-icon-plus { opacity: 0; }
|
|
|
4952
4952
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11.5px;
|
|
4953
4953
|
color: var(--muted); margin-top: 8px; overflow-wrap: anywhere;
|
|
4954
4954
|
}
|
|
4955
|
+
.ip-reason { font-size: 13px; color: var(--muted); line-height: 1.7; margin: -4px 0 8px; }
|
|
4955
4956
|
.ip-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
|
|
4957
|
+
/* ボタンの下に、押すと何が起きるかを小さく添える(#712) */
|
|
4958
|
+
.ip-choice { display: flex; flex-direction: column; gap: 4px; flex: 1 1 180px; max-width: 280px; }
|
|
4959
|
+
.ip-choice > a { align-self: flex-start; }
|
|
4960
|
+
.ip-choice-note { font-size: 11.5px; color: var(--muted); line-height: 1.5; }
|
|
4961
|
+
.proposal-more { font-size: 12.5px; color: var(--muted); }
|
|
4956
4962
|
.ip-why { margin-top: 10px; }
|
|
4957
4963
|
.ip-why-summary { cursor: pointer; font-size: 12.5px; color: var(--muted); }
|
|
4958
4964
|
.ip-why-text { font-size: 13px; color: var(--muted); line-height: 1.7; margin-top: 6px; }
|
|
@@ -7371,16 +7377,90 @@ ${calendarAddUrl.toString()}
|
|
|
7371
7377
|
}
|
|
7372
7378
|
return ids.length === 1 ? ids[0] : null;
|
|
7373
7379
|
}
|
|
7380
|
+
// 見出しの道具の言い方(#712)。🔴 **liKindLabel は使わない**——あちらは語彙外を綴りのまま
|
|
7381
|
+
// 返す(表の「道具」の列ではそれが正しい)が、見出しに backlog_user のような綴りを出さない。
|
|
7382
|
+
// 語彙外は「外のツール」に寄せる。email / git_author は ipAskText が別の文で組む
|
|
7383
|
+
var IP_ASK_TOOL = {
|
|
7384
|
+
backlog_user: "Backlog", slack_user: "Slack", github_login: "GitHub",
|
|
7385
|
+
google_chat_user: "Google Chat", figma_user: "Figma", portal_user: "ポータル",
|
|
7386
|
+
};
|
|
7387
|
+
var IP_NAME_MAX = 40;
|
|
7374
7388
|
/**
|
|
7375
|
-
*
|
|
7389
|
+
* 見出しに使ってよい表示名(使えなければ空文字)。
|
|
7376
7390
|
*
|
|
7377
7391
|
* 🔴 **名乗り(display_name)は engine が出したときだけ使う。推測で名前を作らない。**
|
|
7378
|
-
*
|
|
7392
|
+
* 🔴 **名前に見えないものは無い扱い**: 種類つき ID の形・urn: を含む・数字だけ・メールの形・
|
|
7393
|
+
* ID の値と同じ(名乗りの無い夜に engine が値を名前の欄へ入れることがある)
|
|
7394
|
+
*/
|
|
7395
|
+
function ipDisplayName(one, typed) {
|
|
7396
|
+
var n = ipText(one.display_name);
|
|
7397
|
+
if (!n) return "";
|
|
7398
|
+
if (/^[A-Za-z][A-Za-z0-9_]*:/.test(n)) return "";
|
|
7399
|
+
if (n.toLowerCase().indexOf("urn:") >= 0) return "";
|
|
7400
|
+
if (/^[0-9]+$/.test(n)) return "";
|
|
7401
|
+
if (LI_EMAIL.test(n)) return "";
|
|
7402
|
+
if (n === typed.value) return "";
|
|
7403
|
+
var chars = Array.from(n);
|
|
7404
|
+
return chars.length > IP_NAME_MAX ? chars.slice(0, IP_NAME_MAX).join("") + "…" : n;
|
|
7405
|
+
}
|
|
7406
|
+
/**
|
|
7407
|
+
* カードの見出しの問い。🔴 **常に画面で組む(#712 で #704 の「question を優先」を覆した)。**
|
|
7408
|
+
* 名乗りの無い夜の engine の question は「backlog_user:…」のような機械の綴りを含むため。
|
|
7409
|
+
*/
|
|
7410
|
+
function ipAskText(one, typed) {
|
|
7411
|
+
var name = ipDisplayName(one, typed);
|
|
7412
|
+
var k = typed.kind;
|
|
7413
|
+
if (k === "email") {
|
|
7414
|
+
return name ? "メールで「" + name + "」と名乗っている人は、この人ですか?" : "このメールアドレスの持ち主は、この人ですか?";
|
|
7415
|
+
}
|
|
7416
|
+
if (k === "git_author") {
|
|
7417
|
+
return name ? "git のコミットで「" + name + "」と名乗っている人は、この人ですか?" : "この git のコミットの作者は、この人ですか?";
|
|
7418
|
+
}
|
|
7419
|
+
var tool = Object.prototype.hasOwnProperty.call(IP_ASK_TOOL, k) ? IP_ASK_TOOL[k] : "";
|
|
7420
|
+
if (name) return (tool ? tool + " の" : "外のツールの") + "「" + name + "」は、この人ですか?";
|
|
7421
|
+
return tool ? tool + " のアカウントは、この人ですか?" : "外のツールのアカウントは、この人ですか?";
|
|
7422
|
+
}
|
|
7423
|
+
/** 見出しの直下の 1 行(機械の事情を人の言葉で 1 つに言い分ける。機械の綴りは出さない) */
|
|
7424
|
+
function ipReasonLine(why) {
|
|
7425
|
+
if (/[0-90-9二三四五六七八九十]+ *人/.test(why)) return "名簿に当てはまる人が何人かいて、どの人か決められません";
|
|
7426
|
+
if (why.indexOf("読み") >= 0) return "読みは同じですが、同じ人か確かめる材料が足りません";
|
|
7427
|
+
if (why.indexOf("呼び名") >= 0) return "呼び名は同じですが、同じ人か確かめる材料が足りません";
|
|
7428
|
+
if (why.indexOf("何人か") >= 0 || why.indexOf("複数") >= 0) return "名簿に当てはまる人が何人かいて、どの人か決められません";
|
|
7429
|
+
return "名前は同じですが、同じ人か確かめる材料が足りません";
|
|
7430
|
+
}
|
|
7431
|
+
/**
|
|
7432
|
+
* 種類つき ID の綴り(backlog_user: など)に当たる正規表現。語彙の中の種類に加えて、
|
|
7433
|
+
* **語彙外の snake_case の種類**(zoom_user: 等)も当てる。https: や 12:30 は当てない
|
|
7379
7434
|
*/
|
|
7380
|
-
function
|
|
7381
|
-
return
|
|
7382
|
-
|
|
7383
|
-
|
|
7435
|
+
function ipMachineRe() {
|
|
7436
|
+
return new RegExp("(?:(?:" + Object.keys(LI_KIND_LABEL).join("|") + ")|[A-Za-z][A-Za-z0-9]*_[A-Za-z0-9_]*) *[::]");
|
|
7437
|
+
}
|
|
7438
|
+
/** 画面に出してはいけない機械の綴りを含むか(URN・欄名・パス・種類つき ID) */
|
|
7439
|
+
function ipHasMachineWords(t) {
|
|
7440
|
+
if (/(?:^|[^A-Za-z])urn *:/i.test(t)) return true;
|
|
7441
|
+
for (var i = 0; i < IP_MACHINE_WORDS.length; i++) if (t.indexOf(IP_MACHINE_WORDS[i]) >= 0) return true;
|
|
7442
|
+
return ipMachineRe().test(t);
|
|
7443
|
+
}
|
|
7444
|
+
// 「くわしく」から落とす文の目印(記録のパス・欄名・URN。人が読んでも判断に使えない)
|
|
7445
|
+
var IP_MACHINE_WORDS = ["urn:", "not_aliases", "aliases", "identities", ".md", "Cortex/", "/records/"];
|
|
7446
|
+
/**
|
|
7447
|
+
* 「くわしく」に残す文。why||reason を文に割り、機械の事情の文・問いの文(見出しと重複)・
|
|
7448
|
+
* 1 行の理由と同じ文を落とす。🔴 **種類つき ID(backlog_user: 等)を含む文も落とす**
|
|
7449
|
+
*(位置で縛らない。文の途中に出ても落とす)
|
|
7450
|
+
*/
|
|
7451
|
+
function ipWhyDetail(why, line) {
|
|
7452
|
+
var kindRe = ipMachineRe();
|
|
7453
|
+
var parts = why.match(/[^。.??!!]*[。.??!!]+|[^。.??!!]+$/g) || [];
|
|
7454
|
+
var keep = [];
|
|
7455
|
+
parts.forEach(function (raw) {
|
|
7456
|
+
var t = raw.trim();
|
|
7457
|
+
if (!t || t === line) return;
|
|
7458
|
+
for (var i = 0; i < IP_MACHINE_WORDS.length; i++) if (t.indexOf(IP_MACHINE_WORDS[i]) >= 0) return;
|
|
7459
|
+
if (kindRe.test(t)) return;
|
|
7460
|
+
if (/[??]$/.test(t)) return;
|
|
7461
|
+
keep.push(t);
|
|
7462
|
+
});
|
|
7463
|
+
return keep.join("");
|
|
7384
7464
|
}
|
|
7385
7465
|
/** 名寄せのボタンが読ませる先(対象の記録 と 関係者の規約 README) */
|
|
7386
7466
|
function ipTarget(rec, sectionName) {
|
|
@@ -7393,13 +7473,6 @@ ${calendarAddUrl.toString()}
|
|
|
7393
7473
|
function ipText(v) {
|
|
7394
7474
|
return typeof v === "string" && v.trim() !== "" ? v.trim() : "";
|
|
7395
7475
|
}
|
|
7396
|
-
/**
|
|
7397
|
-
* カードの見出しの問い。🔴 **engine の question を優先する**(便 A・#534 で「人への問い」と
|
|
7398
|
-
* 「機械の事情」を別の欄にした)。無い提案(便 A より前の形)は画面で組み立てる
|
|
7399
|
-
*/
|
|
7400
|
-
function ipAskText(one, typed) {
|
|
7401
|
-
return ipText(one.question) || ipQuestion(liKindLabel(typed.kind), typed.value, ipText(one.display_name));
|
|
7402
|
-
}
|
|
7403
7476
|
/** 折りたたみに入れる機械の事情。why があればそれ、無ければ reason(前の形) */
|
|
7404
7477
|
function ipWhyText(one) {
|
|
7405
7478
|
return ipText(one.why) || ipText(one.reason);
|
|
@@ -7458,46 +7531,232 @@ ${calendarAddUrl.toString()}
|
|
|
7458
7531
|
].concat(aiFenced(ipDataLines(one, typed))).concat([""]).concat(ipTail(rec));
|
|
7459
7532
|
return aiLink("ai-diff-btn", lines.join("\\n") + AI_COMMON, "別人です");
|
|
7460
7533
|
}
|
|
7461
|
-
|
|
7534
|
+
// 根拠の行は最初の 3 行まで。残りは「ほか N 件」の 1 行に畳む(#712)
|
|
7535
|
+
var EV_MAX_ROWS = 3;
|
|
7536
|
+
var EV_URN_HEAD = "urn:cortex:obs:";
|
|
7537
|
+
var EV_ISSUE_KEY = /^[A-Z][A-Z0-9_]*-[0-9]+$/;
|
|
7538
|
+
var EV_PROJ = /^[A-Z][A-Z0-9_]*$/;
|
|
7539
|
+
var EV_REPO = /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/;
|
|
7540
|
+
// Slack / Google Chat の名前が引けなかった形(チャンネル ID のまま)
|
|
7541
|
+
var EV_CHANNEL_ID = /^[CGD][A-Z0-9]{6,}$/;
|
|
7542
|
+
/**
|
|
7543
|
+
* 観測の URN(urn:cortex:obs:<cap>:<workspace>:<ref>:<item>:<rev>)を読む。読めなければ null。
|
|
7544
|
+
* 🔴 **ちょうど 8 段でなければ読めない**(段の中の : は %3A で来る)。% の崩れも読めない扱い
|
|
7545
|
+
*/
|
|
7546
|
+
function evParseUrn(raw) {
|
|
7547
|
+
var seg = raw.split(":");
|
|
7548
|
+
if (seg.length !== 8) return null;
|
|
7549
|
+
var out = [];
|
|
7550
|
+
for (var i = 0; i < seg.length; i++) {
|
|
7551
|
+
try { out.push(decodeURIComponent(seg[i])); } catch (err) { return null; }
|
|
7552
|
+
}
|
|
7553
|
+
return { cap: out[3], ws: out[4], ref: out[5], item: out[6] };
|
|
7554
|
+
}
|
|
7555
|
+
/** fleet の外部ソース(type ごと)から、チャンネル・スペースの読める名前を引く(引けなければ空文字) */
|
|
7556
|
+
function evSourceName(type, ws, ref) {
|
|
7557
|
+
var rows = fleetVal("externalSources") || [];
|
|
7558
|
+
var wsOk = ws && ws !== "-";
|
|
7559
|
+
for (var i = 0; i < rows.length; i++) {
|
|
7560
|
+
var row = rows[i];
|
|
7561
|
+
if (!row || row.type !== type || String(row.ref || "") !== ref) continue;
|
|
7562
|
+
if (wsOk && row.workspace && String(row.workspace) !== ws) continue;
|
|
7563
|
+
var nm = typeof row.name === "string" ? row.name.trim() : "";
|
|
7564
|
+
// 🔴 **名前に見えない値は引けなかった扱い**(ID のまま・コロンや / や山括弧を含む・spaces/… のまま)
|
|
7565
|
+
if (!nm || nm === ref || EV_CHANNEL_ID.test(nm) || /[:\/<>]/.test(nm)) return "";
|
|
7566
|
+
return nm;
|
|
7567
|
+
}
|
|
7568
|
+
return "";
|
|
7569
|
+
}
|
|
7570
|
+
/** 行の文(span.proposal-source)。parts は文字列か {text, href} の並び。href は呼び出し側で検査済み */
|
|
7571
|
+
function evSpan(parts) {
|
|
7572
|
+
var span = el("span", { class: "proposal-source" });
|
|
7573
|
+
parts.forEach(function (x) {
|
|
7574
|
+
if (typeof x === "string") span.appendChild(document.createTextNode(x));
|
|
7575
|
+
else if (x.href) span.appendChild(el("a", { href: x.href, target: "_blank", rel: "noopener", text: x.text }));
|
|
7576
|
+
else span.appendChild(document.createTextNode(x.text));
|
|
7577
|
+
});
|
|
7578
|
+
return span;
|
|
7579
|
+
}
|
|
7580
|
+
/** Backlog の束(ref = <domain>/<PROJ>)→ 文の並び */
|
|
7581
|
+
function evBacklogRows(g) {
|
|
7582
|
+
var cut = g.ref.indexOf("/");
|
|
7583
|
+
var domain = cut >= 0 ? g.ref.slice(0, cut) : "";
|
|
7584
|
+
var proj = cut >= 0 ? g.ref.slice(cut + 1) : g.ref;
|
|
7585
|
+
var projOk = EV_PROJ.test(proj);
|
|
7586
|
+
var projLabel = projOk ? proj : "Backlog";
|
|
7587
|
+
// 🔴 **課題のリンクは、接続先のスペースと同じドメインのときだけ**(別のスペースの課題を
|
|
7588
|
+
// 接続先のスペースの URL で組まない)。el() は href を無害化しないので、ここで決める
|
|
7589
|
+
var bd = domain ? liBacklogDomain(domain) : "";
|
|
7590
|
+
var linkDomain = bd && bd === domain.toLowerCase() ? bd : "";
|
|
7591
|
+
var keys = [], bad = 0, comments = 0, wiki = 0, other = 0;
|
|
7592
|
+
g.items.forEach(function (it) {
|
|
7593
|
+
if (it.indexOf("issue:") === 0) {
|
|
7594
|
+
var key = it.slice(6);
|
|
7595
|
+
if (projOk && EV_ISSUE_KEY.test(key) && key.slice(0, key.lastIndexOf("-")) === proj) keys.push(key);
|
|
7596
|
+
else bad++;
|
|
7597
|
+
} else if (it.indexOf("issue-comment:") === 0) comments++;
|
|
7598
|
+
else if (it.indexOf("wiki:") === 0) wiki++;
|
|
7599
|
+
else other++;
|
|
7600
|
+
});
|
|
7601
|
+
var out = [];
|
|
7602
|
+
if (keys.length) {
|
|
7603
|
+
var parts = [];
|
|
7604
|
+
keys.slice(0, 3).forEach(function (key, i) {
|
|
7605
|
+
if (i > 0) parts.push("・");
|
|
7606
|
+
var shown = i === 0 ? key : key.slice(key.lastIndexOf("-") + 1);
|
|
7607
|
+
parts.push({ text: shown, href: linkDomain ? "https://" + linkDomain + "/view/" + key : "" });
|
|
7608
|
+
});
|
|
7609
|
+
var rest = Math.max(0, keys.length - 3) + bad;
|
|
7610
|
+
parts.push(rest ? " ほか " + rest + " 件の課題を書いています" : " の課題を書いています");
|
|
7611
|
+
out.push(parts);
|
|
7612
|
+
} else if (bad) {
|
|
7613
|
+
out.push([projLabel + " の課題を " + bad + " 件書いています"]);
|
|
7614
|
+
}
|
|
7615
|
+
if (comments) out.push([projLabel + " の課題に " + comments + " 回コメントしています"]);
|
|
7616
|
+
if (wiki) out.push([projLabel + " の Wiki を " + wiki + " 回更新しています"]);
|
|
7617
|
+
if (other) out.push(["ほかの記録 " + other + " 件"]);
|
|
7618
|
+
return out;
|
|
7619
|
+
}
|
|
7620
|
+
/** GitHub の束(ref = owner/repo)→ 文の並び */
|
|
7621
|
+
function evDevRows(g) {
|
|
7622
|
+
var ok = EV_REPO.test(g.ref) && g.ref.split("/").every(function (x) { return x !== "." && x !== ".."; });
|
|
7623
|
+
var repo = ok ? { text: g.ref, href: "https://github.com/" + g.ref } : { text: "GitHub のリポジトリ" };
|
|
7624
|
+
// 🔴 **PR は開いた・マージした・閉じたで別の item(pr:<n>@opened 等)になる**ので、@ より前で 1 件に数える。
|
|
7625
|
+
// コミットは commit:<sha> か素の sha(記録の確定)。それ以外の語はコミットに数えない
|
|
7626
|
+
var talk = [], commits = 0, rest = 0;
|
|
7627
|
+
g.items.forEach(function (it) {
|
|
7628
|
+
if (/^(?:issue|discussion|issue-comment|discussion-comment|pr|review|pr-comment):/.test(it)) {
|
|
7629
|
+
var k = it.indexOf("pr:") === 0 ? it.split("@")[0] : it;
|
|
7630
|
+
if (talk.indexOf(k) < 0) talk.push(k);
|
|
7631
|
+
} else if (it.indexOf("commit:") === 0 || /^[0-9a-f]{7,64}$/i.test(it)) commits++;
|
|
7632
|
+
else rest++;
|
|
7633
|
+
});
|
|
7634
|
+
// 名前のときだけ空白で区切る(「GitHub のリポジトリに」と続けて読む)
|
|
7635
|
+
var sep = ok ? " " : "";
|
|
7636
|
+
var out = [];
|
|
7637
|
+
if (talk.length) out.push([repo, sep + "の Issue・PR で " + talk.length + " 件書いています"]);
|
|
7638
|
+
if (commits) out.push([repo, sep + "に " + commits + " 件コミットしています"]);
|
|
7639
|
+
if (rest) out.push(["ほかの記録 " + rest + " 件"]);
|
|
7640
|
+
return out;
|
|
7641
|
+
}
|
|
7642
|
+
/** URN の束 1 つ → 文の並び(1 束から 2 行出ることがある) */
|
|
7643
|
+
function evGroupRows(g) {
|
|
7644
|
+
var n = g.items.length;
|
|
7645
|
+
if (g.cap === "issues") return evBacklogRows(g);
|
|
7646
|
+
if (g.cap === "dev") return evDevRows(g);
|
|
7647
|
+
if (g.cap === "chat") {
|
|
7648
|
+
var ch = evSourceName("slack", g.ws, g.ref);
|
|
7649
|
+
return [[ch ? (ch.charAt(0) === "#" ? ch : "#" + ch) + " で " + n + " 回発言しています" : "Slack のチャンネルで " + n + " 回発言しています"]];
|
|
7650
|
+
}
|
|
7651
|
+
if (g.cap === "google-chat") {
|
|
7652
|
+
var sp = evSourceName("google-chat", g.ws, g.ref);
|
|
7653
|
+
return [[sp ? sp + " で " + n + " 回発言しています" : "Google Chat のスペースで " + n + " 回発言しています"]];
|
|
7654
|
+
}
|
|
7655
|
+
if (g.cap === "design") return [["Figma で " + n + " 件コメントしています"]];
|
|
7656
|
+
if (g.cap === "meetings") return [["会議の記録に " + n + " 回出ています"]];
|
|
7657
|
+
return [["ほかの記録 " + n + " 件"]];
|
|
7658
|
+
}
|
|
7659
|
+
/**
|
|
7660
|
+
* 根拠の並び(従来のカードと名寄せのカードで**同じ出し方**。引用が無い行は出典だけ)。
|
|
7661
|
+
*
|
|
7662
|
+
* 🔴 **観測の URN(urn:cortex:obs:…)は生のまま出さない**(#712)。場ごと(cap・workspace・ref)に
|
|
7663
|
+
* 束ね、item で重複を除き(rev 違いは同じ)、「DEMO-10・11 の課題を書いています」のような人の文にする。
|
|
7664
|
+
* 読めない URN も生で出さず「ほかの記録 N 件」に畳む。URN でない行(engine の「場・日付」の文)は今までどおり
|
|
7665
|
+
*/
|
|
7462
7666
|
function proposalEvidenceList(one) {
|
|
7463
7667
|
if (!one.evidence || !one.evidence.length) return null;
|
|
7464
7668
|
var ul = el("ul", { class: "proposal-evidence" });
|
|
7669
|
+
// 行の並び(最初に出てきた順)。{ parts, quote } か { group } か { other }
|
|
7670
|
+
var order = [];
|
|
7671
|
+
var groups = {};
|
|
7672
|
+
var other = null;
|
|
7465
7673
|
one.evidence.forEach(function (e) {
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7674
|
+
if (!e || typeof e.source !== "string" || e.source.trim() === "") return;
|
|
7675
|
+
var raw = e.source.trim();
|
|
7676
|
+
// 🔴 **引用にも機械の綴りを出さない**(ID やパスを含む引用は落とし、出典だけ出す)
|
|
7677
|
+
var quote = typeof e.quote === "string" && !ipHasMachineWords(e.quote) ? e.quote : "";
|
|
7678
|
+
e = { source: raw, quote: quote };
|
|
7679
|
+
if (raw.toLowerCase().indexOf(EV_URN_HEAD) !== 0) {
|
|
7680
|
+
// 🔴 **URN でなくても機械の綴り(パス・種類つき ID 等)を含む出典は生で出さない**(「ほかの記録」に畳む)
|
|
7681
|
+
if (ipHasMachineWords(raw)) {
|
|
7682
|
+
if (!other) { other = { keys: [], quote: "" }; order.push({ other: other }); }
|
|
7683
|
+
if (other.keys.indexOf(raw) < 0) other.keys.push(raw);
|
|
7684
|
+
return;
|
|
7685
|
+
}
|
|
7686
|
+
// **引用が無くても出典は出す。** 引用は公開範囲フィルタで落ちることがあり、
|
|
7687
|
+
// そこで根拠ごと畳むと「根拠の無い提案」に見える
|
|
7688
|
+
order.push({ parts: [raw], quote: quote });
|
|
7689
|
+
return;
|
|
7690
|
+
}
|
|
7691
|
+
var u = evParseUrn(raw);
|
|
7692
|
+
var known = u && { issues: 1, chat: 1, "google-chat": 1, dev: 1, design: 1, meetings: 1 }[u.cap];
|
|
7693
|
+
if (!known) {
|
|
7694
|
+
// 読めない URN と語彙外の場は 1 行に畳む(生の綴りは出さない)
|
|
7695
|
+
var okey = u ? JSON.stringify([u.cap, u.ws, u.ref, u.item]) : raw;
|
|
7696
|
+
if (!other) { other = { keys: [], quote: "" }; order.push({ other: other }); }
|
|
7697
|
+
if (other.keys.indexOf(okey) < 0) other.keys.push(okey);
|
|
7698
|
+
if (!other.quote && e.quote) other.quote = e.quote;
|
|
7699
|
+
return;
|
|
7700
|
+
}
|
|
7701
|
+
var gkey = JSON.stringify([u.cap, u.ws, u.ref]);
|
|
7702
|
+
var g = groups[gkey];
|
|
7703
|
+
if (!g) { g = groups[gkey] = { cap: u.cap, ws: u.ws, ref: u.ref, items: [], quote: "" }; order.push({ group: g }); }
|
|
7704
|
+
if (g.items.indexOf(u.item) < 0) g.items.push(u.item);
|
|
7705
|
+
if (!g.quote && e.quote) g.quote = e.quote;
|
|
7706
|
+
});
|
|
7707
|
+
var rows = [];
|
|
7708
|
+
order.forEach(function (o) {
|
|
7709
|
+
if (o.parts) { rows.push(o); return; }
|
|
7710
|
+
if (o.other) { rows.push({ parts: ["ほかの記録 " + o.other.keys.length + " 件"], quote: o.other.quote }); return; }
|
|
7711
|
+
evGroupRows(o.group).forEach(function (parts, i) {
|
|
7712
|
+
rows.push({ parts: parts, quote: i === 0 ? o.group.quote : "" });
|
|
7713
|
+
});
|
|
7714
|
+
});
|
|
7715
|
+
rows.slice(0, EV_MAX_ROWS).forEach(function (r) {
|
|
7716
|
+
var li = el("li", {}, [evSpan(r.parts)]);
|
|
7717
|
+
if (r.quote) li.appendChild(el("blockquote", { class: "proposal-quote", text: r.quote }));
|
|
7470
7718
|
ul.appendChild(li);
|
|
7471
7719
|
});
|
|
7720
|
+
if (rows.length > EV_MAX_ROWS) {
|
|
7721
|
+
ul.appendChild(el("li", { class: "proposal-more", text: "ほか " + (rows.length - EV_MAX_ROWS) + " 件" }));
|
|
7722
|
+
}
|
|
7472
7723
|
return ul;
|
|
7473
7724
|
}
|
|
7474
7725
|
/** 「同じ人ですか」のカード 1 枚。**ボタンはカードごと**(束ねる側からは外してある) */
|
|
7475
7726
|
function ipCard(rec, sectionName, one, typed) {
|
|
7727
|
+
// 見出し(常に画面で組む)→ 理由の 1 行 → 根拠 → 2 つの選択 → くわしく(残りの文と問い合わせ用の ID)
|
|
7728
|
+
var why = ipWhyText(one);
|
|
7729
|
+
var reasonLine = ipReasonLine(why);
|
|
7476
7730
|
var item = el("div", { class: "proposal proposal-identity" }, [
|
|
7477
7731
|
el("div", { class: "ip-ask", text: ipAskText(one, typed) }),
|
|
7732
|
+
el("div", { class: "ip-reason", text: reasonLine }),
|
|
7478
7733
|
]);
|
|
7479
7734
|
var ev = proposalEvidenceList(one);
|
|
7480
7735
|
if (ev) item.appendChild(ev);
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7736
|
+
item.appendChild(el("div", { class: "ip-actions" }, [
|
|
7737
|
+
el("div", { class: "ip-choice" }, [
|
|
7738
|
+
ipSameBtn(rec, sectionName, rec.title, one, typed),
|
|
7739
|
+
el("div", { class: "ip-choice-note", text: "承認すると、翌晩からこの人の活動としてまとめて数えます" }),
|
|
7740
|
+
]),
|
|
7741
|
+
el("div", { class: "ip-choice" }, [
|
|
7742
|
+
ipDiffBtn(rec, sectionName, rec.title, one, typed),
|
|
7743
|
+
el("div", { class: "ip-choice-note", text: "承認すると、翌晩からこの人に結び付けません" }),
|
|
7744
|
+
]),
|
|
7745
|
+
]));
|
|
7746
|
+
// 🔴 **ID の値は「くわしく」の中にだけ置く**(問い合わせ用。判断は見出しと根拠でする)。
|
|
7747
|
+
// リンクにしてよい形(許可リストで検査・Slack と Backlog は行き先のドメインが 1 つに
|
|
7748
|
+
// 決まるときだけ)は「つながっている ID」と同じ規則で決める
|
|
7749
|
+
var idCell = el("div", { class: "ip-id" }, [el("span", { text: "問い合わせ用の ID: " })]);
|
|
7484
7750
|
var whole = typed.kind + ":" + typed.value;
|
|
7485
7751
|
var href = liHref(typed.kind, typed.value);
|
|
7486
7752
|
idCell.appendChild(href
|
|
7487
7753
|
? el("a", { href: href, target: "_blank", rel: "noopener", text: whole })
|
|
7488
7754
|
: el("span", { text: whole }));
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
var why = ipWhyText(one);
|
|
7495
|
-
if (why) {
|
|
7496
|
-
item.appendChild(el("details", { class: "ip-why" }, [
|
|
7497
|
-
el("summary", { class: "ip-why-summary", text: "機械が決めきれなかった理由" }),
|
|
7498
|
-
el("div", { class: "ip-why-text", text: why }),
|
|
7499
|
-
]));
|
|
7500
|
-
}
|
|
7755
|
+
var det = el("details", { class: "ip-why" }, [el("summary", { class: "ip-why-summary", text: "くわしく" })]);
|
|
7756
|
+
var detail = why ? ipWhyDetail(why, reasonLine) : "";
|
|
7757
|
+
if (detail) det.appendChild(el("div", { class: "ip-why-text", text: detail }));
|
|
7758
|
+
det.appendChild(idCell);
|
|
7759
|
+
item.appendChild(det);
|
|
7501
7760
|
if (one.createdAt) {
|
|
7502
7761
|
item.appendChild(el("div", { class: "proposal-at", text: (rtAgo(one.createdAt) || one.createdAt) + "の提案" }));
|
|
7503
7762
|
}
|
package/package.json
CHANGED