@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 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
- group = "external";
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
- edges.push({ from: fromId, to: classifyTarget(r.target), rel: r.rel });
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
- edges.push({ from: fromId, to: classifyTarget(source.trim()), rel: "source" });
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
- if (ref.url) {
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
- edges.push({ from: fromId, to: classifyTarget(key ?? link), rel: "link" });
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
- edges.push({ from: c.id, to: classifyTarget(e.target), rel: e.rel });
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
- return { nodes: [...nodes.values()], edges: deduped };
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
- head.appendChild(el("div", {}, [ el("h1", { class: "detail-title", text: h.title }) ]));
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.05) alpha *= 0.995;
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
- tick();
1286
+ // 収束後(alpha減衰しきり・無操作)は O() の物理計算 tick を止める。これが「固まり続ける」主因。
1287
+ // ドラッグ/パン中は動かす必要があるので回す。描画(draw)はホバー演出・イントロのため毎フレーム続ける。
1288
+ if (alpha > 0.004 || draggingNode || panning) tick();
1254
1289
  draw();
1255
1290
  requestAnimationFrame(loop);
1256
1291
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,