@takagaki/cortex-decisions-viewer 0.4.4 → 0.4.6
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 +26 -23
- package/dist/render.js +38 -3
- package/package.json +1 -1
package/dist/build.js
CHANGED
|
@@ -472,7 +472,9 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
|
|
|
472
472
|
for (const sec of sections)
|
|
473
473
|
for (const r of sec.records)
|
|
474
474
|
fileNameToId.set(r.fileName, r.id);
|
|
475
|
-
// 参照先ID
|
|
475
|
+
// 参照先IDから層を推定してノード化する。
|
|
476
|
+
// 外部リンク(http(s))はノード化せず null を返す(外部URLの点はグラフ肥大化=描画負荷の主因。
|
|
477
|
+
// リンク自体は各レコードの詳細・参照欄に残るため情報は失われない)。
|
|
476
478
|
const classifyTarget = (target) => {
|
|
477
479
|
if (nodes.has(target))
|
|
478
480
|
return target;
|
|
@@ -496,9 +498,7 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
|
|
|
496
498
|
return addNode({ id: target, label, group, url });
|
|
497
499
|
}
|
|
498
500
|
else if (/^https?:\/\//.test(target)) {
|
|
499
|
-
|
|
500
|
-
label = target.replace(/^https?:\/\//, "").slice(0, 60);
|
|
501
|
-
return addNode({ id: target, label, group, url: target });
|
|
501
|
+
return null; // 外部リンクはノード化しない
|
|
502
502
|
}
|
|
503
503
|
else if (target.includes("/") || target.toLowerCase().endsWith(".md")) {
|
|
504
504
|
group = "silver"; // リポジトリ内ファイルへのパス参照 → GitHubのコピーへ飛べるようにする
|
|
@@ -508,35 +508,30 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
|
|
|
508
508
|
}
|
|
509
509
|
return addNode({ id: target, label, group });
|
|
510
510
|
};
|
|
511
|
+
// 解決先が null(外部リンク等で非ノード化)の辺は張らない
|
|
512
|
+
const pushEdge = (fromId, target, rel) => {
|
|
513
|
+
if (target)
|
|
514
|
+
edges.push({ from: fromId, to: target, rel });
|
|
515
|
+
};
|
|
511
516
|
const addRelationEdges = (fromId, relations) => {
|
|
512
|
-
for (const r of relations)
|
|
513
|
-
|
|
514
|
-
}
|
|
517
|
+
for (const r of relations)
|
|
518
|
+
pushEdge(fromId, classifyTarget(r.target), r.rel);
|
|
515
519
|
};
|
|
516
520
|
const addSourceEdge = (fromId, source) => {
|
|
517
521
|
if (source && source.trim() !== "")
|
|
518
|
-
|
|
522
|
+
pushEdge(fromId, classifyTarget(source.trim()), "source");
|
|
519
523
|
};
|
|
520
524
|
const addReferenceEdges = (fromId, references) => {
|
|
525
|
+
// ref.url(http(s))は classifyTarget が null を返す=外部はノード化しない。
|
|
526
|
+
// URLが無い参照(課題キー・議事録ID等)は従来どおり該当ノードへ繋ぐ。
|
|
521
527
|
for (const ref of references) {
|
|
522
|
-
|
|
523
|
-
const id = addNode({
|
|
524
|
-
id: ref.url,
|
|
525
|
-
label: ref.label.slice(0, 60),
|
|
526
|
-
group: "external",
|
|
527
|
-
url: ref.url,
|
|
528
|
-
});
|
|
529
|
-
edges.push({ from: fromId, to: id, rel: "reference" });
|
|
530
|
-
}
|
|
531
|
-
else {
|
|
532
|
-
edges.push({ from: fromId, to: classifyTarget(ref.label), rel: "reference" });
|
|
533
|
-
}
|
|
528
|
+
pushEdge(fromId, classifyTarget(ref.url ?? ref.label), "reference");
|
|
534
529
|
}
|
|
535
530
|
};
|
|
536
531
|
const addLinkEdges = (fromId, links) => {
|
|
537
532
|
for (const link of links) {
|
|
538
533
|
const key = backlogViewKey(link);
|
|
539
|
-
|
|
534
|
+
pushEdge(fromId, classifyTarget(key ?? link), "link");
|
|
540
535
|
}
|
|
541
536
|
};
|
|
542
537
|
// Bronze/Silverのノードを先に登録する(Gold・Bronze/Silver双方からの参照が同一ノードに解決されるように)
|
|
@@ -573,7 +568,7 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
|
|
|
573
568
|
}
|
|
574
569
|
for (const c of content) {
|
|
575
570
|
for (const e of c.edges) {
|
|
576
|
-
|
|
571
|
+
pushEdge(c.id, classifyTarget(e.target), e.rel);
|
|
577
572
|
}
|
|
578
573
|
}
|
|
579
574
|
// 自己ループと重複辺を除去する(同じURLが複数回貼られていても辺は1本)
|
|
@@ -587,7 +582,15 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
|
|
|
587
582
|
seen.add(key);
|
|
588
583
|
return true;
|
|
589
584
|
});
|
|
590
|
-
|
|
585
|
+
// 描画対象は「レコード(Gold) or 辺に接続のあるノード」だけ。外部リンク除去で孤立した
|
|
586
|
+
// 非レコードノードは描画もされないため、ペイロードからも落としておく(初期ロードを軽くする)。
|
|
587
|
+
const usedIds = new Set();
|
|
588
|
+
for (const e of deduped) {
|
|
589
|
+
usedIds.add(e.from);
|
|
590
|
+
usedIds.add(e.to);
|
|
591
|
+
}
|
|
592
|
+
const prunedNodes = [...nodes.values()].filter((n) => n.recordId || usedIds.has(n.id));
|
|
593
|
+
return { nodes: prunedNodes, edges: deduped };
|
|
591
594
|
}
|
|
592
595
|
/**
|
|
593
596
|
* 各レコードの bodyHtml を out/bodies/<i>.html に書き出し、bodyRef にパスを設定して
|
package/dist/render.js
CHANGED
|
@@ -285,6 +285,13 @@ a:hover { text-decoration: underline; }
|
|
|
285
285
|
background: #fffbeb; border: 1px solid #fcd34d; border-radius: 8px;
|
|
286
286
|
padding: 10px 14px; margin: 12px 0 4px; font-size: 13.5px; color: #92400e; line-height: 1.7;
|
|
287
287
|
}
|
|
288
|
+
.adoption-note {
|
|
289
|
+
display: flex; gap: 8px; align-items: flex-start;
|
|
290
|
+
background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px;
|
|
291
|
+
padding: 10px 14px; margin: 0 0 14px; font-size: 13.5px; color: #1e40af; line-height: 1.7;
|
|
292
|
+
}
|
|
293
|
+
.chip.adoption-existing, .chip.adoption-migration { background: #eff6ff; color: #1e40af; border-color: #bfdbfe; }
|
|
294
|
+
.chip.adoption-new { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
|
|
288
295
|
.chip {
|
|
289
296
|
display: inline-block; padding: 2px 10px; border-radius: 999px;
|
|
290
297
|
font-size: 12.5px; background: #f1f3f5; color: #41474f; border: 1px solid var(--border);
|
|
@@ -522,12 +529,29 @@ const CLIENT_JS = `
|
|
|
522
529
|
renderGenericList();
|
|
523
530
|
}
|
|
524
531
|
|
|
532
|
+
// 導入経緯(overview.adoption)の表示情報。existing/migration は Decision の薄さを注記する。
|
|
533
|
+
function adoptionInfo(v) {
|
|
534
|
+
// existing/migration は同一文言で「導入前の意思決定が揃わない」旨を注記する
|
|
535
|
+
var note = "この案件はAIS導入前から進行しているため、導入以前の意思決定はDecisionログに残っていない場合があります。";
|
|
536
|
+
if (v === "existing") return { label: "既存案件に導入", note: note };
|
|
537
|
+
if (v === "migration") return { label: "Cortex移行", note: note };
|
|
538
|
+
if (v === "new") return { label: "新規導入", note: "" };
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function homeAdoption() {
|
|
543
|
+
return SITE.home && SITE.home.fm ? adoptionInfo(SITE.home.fm.adoption) : null;
|
|
544
|
+
}
|
|
545
|
+
|
|
525
546
|
// ---------- ホーム(着地画面: Markdownをそのまま表示) ----------
|
|
526
547
|
function renderHome() {
|
|
527
548
|
var h = SITE.home;
|
|
528
549
|
countEl.textContent = "";
|
|
529
550
|
var head = el("div", { class: "detail-head" });
|
|
530
|
-
|
|
551
|
+
var titleWrap = el("div", {}, [ el("h1", { class: "detail-title", text: h.title }) ]);
|
|
552
|
+
var ai = h.fm ? adoptionInfo(h.fm.adoption) : null;
|
|
553
|
+
if (ai) titleWrap.appendChild(el("span", { class: "chip adoption-" + String(h.fm.adoption), text: ai.label }));
|
|
554
|
+
head.appendChild(titleWrap);
|
|
531
555
|
if (h.editUrl) {
|
|
532
556
|
head.appendChild(el("a", { class: "edit-btn", href: h.editUrl, target: "_blank", rel: "noopener", text: "✏️ GitHubで編集" }));
|
|
533
557
|
}
|
|
@@ -539,6 +563,14 @@ const CLIENT_JS = `
|
|
|
539
563
|
|
|
540
564
|
// ---------- Decisions一覧(フィルタ付き) ----------
|
|
541
565
|
function renderDecisionList() {
|
|
566
|
+
// 既存案件・移行案件は導入前/移行前の意思決定が揃わないため、その旨を最初に注記する
|
|
567
|
+
var ai = homeAdoption();
|
|
568
|
+
if (ai && ai.note) {
|
|
569
|
+
app.appendChild(el("div", { class: "adoption-note" }, [
|
|
570
|
+
el("span", { text: "ℹ️" }),
|
|
571
|
+
el("span", { text: ai.note }),
|
|
572
|
+
]));
|
|
573
|
+
}
|
|
542
574
|
var filters = el("div", { class: "filters" });
|
|
543
575
|
var search = el("input", { type: "search", placeholder: "キーワード検索(タイトル・要約・本文)" });
|
|
544
576
|
search.value = listState.q;
|
|
@@ -981,7 +1013,7 @@ const CLIENT_JS = `
|
|
|
981
1013
|
n.vx *= 0.85; n.vy *= 0.85;
|
|
982
1014
|
n.x += n.vx * alpha; n.y += n.vy * alpha;
|
|
983
1015
|
});
|
|
984
|
-
if (alpha > 0.
|
|
1016
|
+
if (alpha > 0.0015) alpha *= 0.97; // 収束まで減衰しきる(下げ止まりさせず、整定後はループ側で物理計算を止める)
|
|
985
1017
|
}
|
|
986
1018
|
|
|
987
1019
|
function nodeRadius(n) {
|
|
@@ -1225,6 +1257,7 @@ const CLIENT_JS = `
|
|
|
1225
1257
|
else if (n.url) window.open(n.url, "_blank", "noopener");
|
|
1226
1258
|
}
|
|
1227
1259
|
}
|
|
1260
|
+
if (draggingNode) alpha = Math.max(alpha, 0.2); // 動かした点の周りを少し整え直してから止まる
|
|
1228
1261
|
draggingNode = null;
|
|
1229
1262
|
panning = null;
|
|
1230
1263
|
canvas.classList.remove("dragging");
|
|
@@ -1250,7 +1283,9 @@ const CLIENT_JS = `
|
|
|
1250
1283
|
var running = true;
|
|
1251
1284
|
function loop() {
|
|
1252
1285
|
if (!running || !document.body.contains(canvas)) { running = false; return; }
|
|
1253
|
-
|
|
1286
|
+
// 収束後(alpha減衰しきり・無操作)は O(n²) の物理計算 tick を止める。これが「固まり続ける」主因。
|
|
1287
|
+
// ドラッグ/パン中は動かす必要があるので回す。描画(draw)はホバー演出・イントロのため毎フレーム続ける。
|
|
1288
|
+
if (alpha > 0.004 || draggingNode || panning) tick();
|
|
1254
1289
|
draw();
|
|
1255
1290
|
requestAnimationFrame(loop);
|
|
1256
1291
|
}
|