@youtyan/code-viewer 0.4.1 → 0.5.1
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/README.md +7 -0
- package/dist/code-viewer.js +4769 -3868
- package/package.json +1 -1
- package/web/app.js +373 -22
- package/web/index.html +3 -0
- package/web/style.css +197 -0
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -658,6 +658,13 @@
|
|
|
658
658
|
lang: params.get("lang") || "en",
|
|
659
659
|
section: params.get("section") || "overview"
|
|
660
660
|
};
|
|
661
|
+
case "/doctor":
|
|
662
|
+
return {
|
|
663
|
+
screen: "repo",
|
|
664
|
+
ref: params.get("ref") || params.get("target") || "worktree",
|
|
665
|
+
path: params.get("path") || "",
|
|
666
|
+
range
|
|
667
|
+
};
|
|
661
668
|
case "/history": {
|
|
662
669
|
const commit = params.get("commit") || "";
|
|
663
670
|
return {
|
|
@@ -757,6 +764,24 @@
|
|
|
757
764
|
function buildRawFileUrl(target) {
|
|
758
765
|
return "/_file?path=" + encodeURIComponent(target.path) + "&ref=" + encodeURIComponent(target.ref || "worktree");
|
|
759
766
|
}
|
|
767
|
+
function parseDoctorOverlay(pathname, search) {
|
|
768
|
+
if (pathname === "/doctor")
|
|
769
|
+
return true;
|
|
770
|
+
const params = new URLSearchParams(search);
|
|
771
|
+
return params.get("doctor") === "open";
|
|
772
|
+
}
|
|
773
|
+
function withDoctorOverlay(url, open) {
|
|
774
|
+
const queryIdx = url.indexOf("?");
|
|
775
|
+
const base = queryIdx >= 0 ? url.slice(0, queryIdx) : url;
|
|
776
|
+
const query = queryIdx >= 0 ? url.slice(queryIdx + 1) : "";
|
|
777
|
+
const params = new URLSearchParams(query);
|
|
778
|
+
if (open)
|
|
779
|
+
params.set("doctor", "open");
|
|
780
|
+
else
|
|
781
|
+
params.delete("doctor");
|
|
782
|
+
const qs = params.toString();
|
|
783
|
+
return qs ? `${base}?${qs}` : base;
|
|
784
|
+
}
|
|
760
785
|
|
|
761
786
|
// web-src/core/annotation-player-core.ts
|
|
762
787
|
function createAnnotationPlayerCore(deps) {
|
|
@@ -846,7 +871,9 @@
|
|
|
846
871
|
emit();
|
|
847
872
|
const item = deps.items()[clamped];
|
|
848
873
|
if (item)
|
|
849
|
-
deps.jump(item.entryId).catch(() => {
|
|
874
|
+
deps.jump(item.entryId).catch(() => {
|
|
875
|
+
return;
|
|
876
|
+
});
|
|
850
877
|
}
|
|
851
878
|
}
|
|
852
879
|
function jumpTo(at) {
|
|
@@ -10897,7 +10924,9 @@ ${frontmatter.yaml}
|
|
|
10897
10924
|
setTimeout(() => {
|
|
10898
10925
|
copyBtn.textContent = text2().er.copyMermaid;
|
|
10899
10926
|
}, 1500);
|
|
10900
|
-
}, () => {
|
|
10927
|
+
}, () => {
|
|
10928
|
+
return;
|
|
10929
|
+
});
|
|
10901
10930
|
}
|
|
10902
10931
|
});
|
|
10903
10932
|
let dragState = null;
|
|
@@ -11749,7 +11778,9 @@ ${frontmatter.yaml}
|
|
|
11749
11778
|
setTimeout(() => {
|
|
11750
11779
|
copyBtn.textContent = text2().history.copySql;
|
|
11751
11780
|
}, 1500);
|
|
11752
|
-
}, () => {
|
|
11781
|
+
}, () => {
|
|
11782
|
+
return;
|
|
11783
|
+
});
|
|
11753
11784
|
});
|
|
11754
11785
|
const deleteBtn = document.createElement("button");
|
|
11755
11786
|
deleteBtn.className = "db-btn db-query-history-danger";
|
|
@@ -12599,7 +12630,9 @@ ${frontmatter.yaml}
|
|
|
12599
12630
|
keyList.innerHTML = "";
|
|
12600
12631
|
keyRowsByName.clear();
|
|
12601
12632
|
setPaneEmpty(mainPane, text2().redis.selectKey);
|
|
12602
|
-
const valuePromise = initial.key ? selectKey(initial.key).catch(() => {
|
|
12633
|
+
const valuePromise = initial.key ? selectKey(initial.key).catch(() => {
|
|
12634
|
+
return;
|
|
12635
|
+
}) : null;
|
|
12603
12636
|
await loadKeys(false);
|
|
12604
12637
|
if (currentDbId !== dbId)
|
|
12605
12638
|
return;
|
|
@@ -14405,7 +14438,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
14405
14438
|
setTimeout(() => {
|
|
14406
14439
|
copyBtn.textContent = text2().sessionLog.copy;
|
|
14407
14440
|
}, 1200);
|
|
14408
|
-
}, () => {
|
|
14441
|
+
}, () => {
|
|
14442
|
+
return;
|
|
14443
|
+
});
|
|
14409
14444
|
});
|
|
14410
14445
|
actions.append(useBtn, copyBtn);
|
|
14411
14446
|
detailCol.appendChild(actions);
|
|
@@ -18551,7 +18586,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18551
18586
|
if (!res.ok)
|
|
18552
18587
|
return;
|
|
18553
18588
|
applyDbUiState(await res.json());
|
|
18554
|
-
}).catch(() => {
|
|
18589
|
+
}).catch(() => {
|
|
18590
|
+
return;
|
|
18591
|
+
});
|
|
18555
18592
|
return dbUiLoadPromise;
|
|
18556
18593
|
}
|
|
18557
18594
|
function getColumnWidths(dbId, table2) {
|
|
@@ -18569,7 +18606,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18569
18606
|
method: "PATCH",
|
|
18570
18607
|
headers: actionHeaders(),
|
|
18571
18608
|
body: JSON.stringify({ columnWidths: { [dbId]: { [table2]: widths } } })
|
|
18572
|
-
}).catch(() => {
|
|
18609
|
+
}).catch(() => {
|
|
18610
|
+
return;
|
|
18611
|
+
});
|
|
18573
18612
|
}
|
|
18574
18613
|
function getExpandedTables(scopeKey) {
|
|
18575
18614
|
return [...dbUiState.expandedTables?.[scopeKey] || []];
|
|
@@ -18601,7 +18640,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18601
18640
|
[scopeKey]: nextTables.length > 0 ? nextTables : null
|
|
18602
18641
|
}
|
|
18603
18642
|
})
|
|
18604
|
-
}).catch(() => {
|
|
18643
|
+
}).catch(() => {
|
|
18644
|
+
return;
|
|
18645
|
+
});
|
|
18605
18646
|
}
|
|
18606
18647
|
const dbUiPrefListeners = new Set;
|
|
18607
18648
|
function applyDbUiState(next) {
|
|
@@ -18620,7 +18661,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18620
18661
|
method: "PATCH",
|
|
18621
18662
|
headers: actionHeaders(),
|
|
18622
18663
|
body: JSON.stringify({ prefs: { [key]: value } })
|
|
18623
|
-
}).catch(() => {
|
|
18664
|
+
}).catch(() => {
|
|
18665
|
+
return;
|
|
18666
|
+
});
|
|
18624
18667
|
}
|
|
18625
18668
|
function onDbUiPrefChange(listener) {
|
|
18626
18669
|
dbUiPrefListeners.add(listener);
|
|
@@ -18733,7 +18776,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18733
18776
|
}
|
|
18734
18777
|
return;
|
|
18735
18778
|
}
|
|
18736
|
-
saveChain = saveChain.catch(() => {
|
|
18779
|
+
saveChain = saveChain.catch(() => {
|
|
18780
|
+
return;
|
|
18781
|
+
}).then(async () => {
|
|
18737
18782
|
const controller = new AbortController;
|
|
18738
18783
|
saveController = controller;
|
|
18739
18784
|
try {
|
|
@@ -18808,7 +18853,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18808
18853
|
syncActiveRoute();
|
|
18809
18854
|
scheduleSave();
|
|
18810
18855
|
if (mounted && !isRestoring()) {
|
|
18811
|
-
ensureInitialEnter(id)?.catch(() => {
|
|
18856
|
+
ensureInitialEnter(id)?.catch(() => {
|
|
18857
|
+
return;
|
|
18858
|
+
});
|
|
18812
18859
|
}
|
|
18813
18860
|
}
|
|
18814
18861
|
function syncActiveRoute() {
|
|
@@ -18871,7 +18918,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18871
18918
|
"Content-Type": "application/json",
|
|
18872
18919
|
"X-Code-Viewer-Action": "1"
|
|
18873
18920
|
};
|
|
18874
|
-
fetch("/_db/close", { method: "POST", headers, body }).catch(() => {
|
|
18921
|
+
fetch("/_db/close", { method: "POST", headers, body }).catch(() => {
|
|
18922
|
+
return;
|
|
18923
|
+
});
|
|
18875
18924
|
}
|
|
18876
18925
|
function clearDropTarget() {
|
|
18877
18926
|
if (!dropTargetId)
|
|
@@ -19381,7 +19430,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19381
19430
|
}
|
|
19382
19431
|
async function enter(db, schema, table2, view, options = {}) {
|
|
19383
19432
|
const seq = lifecycleSeq;
|
|
19384
|
-
enterQueue = enterQueue.catch(() => {
|
|
19433
|
+
enterQueue = enterQueue.catch(() => {
|
|
19434
|
+
return;
|
|
19435
|
+
}).then(() => doEnter(seq, db, schema, table2, view, options));
|
|
19385
19436
|
await enterQueue;
|
|
19386
19437
|
}
|
|
19387
19438
|
function leave() {
|
|
@@ -20855,6 +20906,196 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20855
20906
|
};
|
|
20856
20907
|
}
|
|
20857
20908
|
|
|
20909
|
+
// web-src/views/doctor-view.ts
|
|
20910
|
+
var TEXT = {
|
|
20911
|
+
en: {
|
|
20912
|
+
title: "Environment doctor",
|
|
20913
|
+
refresh: "Re-run checks",
|
|
20914
|
+
refreshing: "Running checks…",
|
|
20915
|
+
loadFailed: "Failed to load doctor report",
|
|
20916
|
+
worstOk: "All checks passed.",
|
|
20917
|
+
worstWarn: "Some checks reported warnings.",
|
|
20918
|
+
worstError: "Some checks failed. See the items marked ERROR below.",
|
|
20919
|
+
empty: "No checks ran.",
|
|
20920
|
+
close: "Close",
|
|
20921
|
+
statusLabels: { ok: "OK", warn: "WARN", error: "ERROR" }
|
|
20922
|
+
},
|
|
20923
|
+
ja: {
|
|
20924
|
+
title: "環境ドクター",
|
|
20925
|
+
refresh: "再診断",
|
|
20926
|
+
refreshing: "診断中…",
|
|
20927
|
+
loadFailed: "doctor の結果を取得できませんでした",
|
|
20928
|
+
worstOk: "すべての診断項目が OK です。",
|
|
20929
|
+
worstWarn: "一部の項目に注意があります (WARN)。",
|
|
20930
|
+
worstError: "失敗している項目があります。下の ERROR を確認してください。",
|
|
20931
|
+
empty: "診断項目がありません。",
|
|
20932
|
+
close: "閉じる",
|
|
20933
|
+
statusLabels: { ok: "OK", warn: "警告", error: "エラー" }
|
|
20934
|
+
}
|
|
20935
|
+
};
|
|
20936
|
+
var viewGeneration = 0;
|
|
20937
|
+
function doctorText(lang) {
|
|
20938
|
+
return TEXT[lang];
|
|
20939
|
+
}
|
|
20940
|
+
function statusLabel(text2, status) {
|
|
20941
|
+
return text2.statusLabels[status];
|
|
20942
|
+
}
|
|
20943
|
+
function renderRow(text2, esc, row) {
|
|
20944
|
+
const pill = `<span class="doctor-row-pill doctor-row-pill-${row.status}">` + `${esc(statusLabel(text2, row.status))}</span>`;
|
|
20945
|
+
const body = `<div class="doctor-row-body">` + `<div class="doctor-row-title">${esc(row.title)}</div>` + (row.detail ? `<div class="doctor-row-detail">${esc(row.detail)}</div>` : "") + (row.hint ? `<div class="doctor-row-hint">${esc(row.hint)}</div>` : "") + `</div>`;
|
|
20946
|
+
return `<div class="doctor-row" data-status="${esc(row.status)}">${pill}${body}</div>`;
|
|
20947
|
+
}
|
|
20948
|
+
function renderGroup(text2, esc, group) {
|
|
20949
|
+
if (group.rows.length === 0)
|
|
20950
|
+
return "";
|
|
20951
|
+
const rows = group.rows.map((row) => renderRow(text2, esc, row)).join("");
|
|
20952
|
+
return `<section class="doctor-group" data-group="${esc(group.id)}">` + `<h2 class="doctor-group-title">${esc(group.title)}</h2>` + rows + `</section>`;
|
|
20953
|
+
}
|
|
20954
|
+
function renderReport(mount, report, text2, esc) {
|
|
20955
|
+
const summary = mount.querySelector(".doctor-summary");
|
|
20956
|
+
if (summary) {
|
|
20957
|
+
const message = report.worstStatus === "error" ? text2.worstError : report.worstStatus === "warn" ? text2.worstWarn : text2.worstOk;
|
|
20958
|
+
summary.textContent = message;
|
|
20959
|
+
}
|
|
20960
|
+
const content = mount.querySelector(".doctor-content");
|
|
20961
|
+
if (!content)
|
|
20962
|
+
return;
|
|
20963
|
+
if (!report.groups.length) {
|
|
20964
|
+
content.innerHTML = `<div class="doctor-empty">${esc(text2.empty)}</div>`;
|
|
20965
|
+
return;
|
|
20966
|
+
}
|
|
20967
|
+
content.innerHTML = report.groups.map((group) => renderGroup(text2, esc, group)).join("");
|
|
20968
|
+
}
|
|
20969
|
+
function ensureSkeleton(mount, text2, esc) {
|
|
20970
|
+
if (mount.querySelector(".doctor-header"))
|
|
20971
|
+
return;
|
|
20972
|
+
mount.innerHTML = `<div class="doctor-header">` + `<h1>${esc(text2.title)}</h1>` + `<button type="button" class="doctor-refresh">${esc(text2.refresh)}</button>` + `<button type="button" class="doctor-close" aria-label="${esc(text2.close)}" title="${esc(text2.close)}">×</button>` + `</div>` + `<div class="doctor-summary"></div>` + `<div class="doctor-content"></div>`;
|
|
20973
|
+
}
|
|
20974
|
+
function createDoctorView(deps) {
|
|
20975
|
+
function getMount() {
|
|
20976
|
+
return deps.$("#doctor-sheet");
|
|
20977
|
+
}
|
|
20978
|
+
function getOverlay() {
|
|
20979
|
+
return deps.$("#doctor-sheet-overlay");
|
|
20980
|
+
}
|
|
20981
|
+
function setRefreshState(mount, busy) {
|
|
20982
|
+
const btn = mount.querySelector(".doctor-refresh");
|
|
20983
|
+
if (!btn)
|
|
20984
|
+
return;
|
|
20985
|
+
btn.disabled = busy;
|
|
20986
|
+
}
|
|
20987
|
+
async function load(mount) {
|
|
20988
|
+
viewGeneration += 1;
|
|
20989
|
+
const myGen = viewGeneration;
|
|
20990
|
+
const lang = deps.getLanguage();
|
|
20991
|
+
const text2 = doctorText(lang);
|
|
20992
|
+
setRefreshState(mount, true);
|
|
20993
|
+
const content = mount.querySelector(".doctor-content");
|
|
20994
|
+
if (content)
|
|
20995
|
+
content.innerHTML = `<div class="doctor-empty">${deps.escapeHtml(text2.refreshing)}</div>`;
|
|
20996
|
+
const summary = mount.querySelector(".doctor-summary");
|
|
20997
|
+
if (summary)
|
|
20998
|
+
summary.textContent = "";
|
|
20999
|
+
try {
|
|
21000
|
+
const res = await deps.trackLoad(fetch("/_doctor"));
|
|
21001
|
+
if (myGen !== viewGeneration)
|
|
21002
|
+
return;
|
|
21003
|
+
if (!res.ok) {
|
|
21004
|
+
throw new Error(`HTTP ${res.status}`);
|
|
21005
|
+
}
|
|
21006
|
+
const data = await res.json();
|
|
21007
|
+
if (myGen !== viewGeneration)
|
|
21008
|
+
return;
|
|
21009
|
+
renderReport(mount, data, text2, deps.escapeHtml);
|
|
21010
|
+
deps.onWorstStatusChange?.(data.worstStatus);
|
|
21011
|
+
} catch (err) {
|
|
21012
|
+
if (myGen !== viewGeneration)
|
|
21013
|
+
return;
|
|
21014
|
+
if (content) {
|
|
21015
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
21016
|
+
content.innerHTML = `<div class="doctor-empty">${deps.escapeHtml(`${text2.loadFailed}: ${message}`)}</div>`;
|
|
21017
|
+
}
|
|
21018
|
+
deps.onWorstStatusChange?.(null);
|
|
21019
|
+
} finally {
|
|
21020
|
+
if (myGen === viewGeneration)
|
|
21021
|
+
setRefreshState(mount, false);
|
|
21022
|
+
}
|
|
21023
|
+
}
|
|
21024
|
+
function applyLocalizedLabels(mount, text2) {
|
|
21025
|
+
const title = mount.querySelector(".doctor-header h1");
|
|
21026
|
+
if (title)
|
|
21027
|
+
title.textContent = text2.title;
|
|
21028
|
+
const refreshBtn = mount.querySelector(".doctor-refresh");
|
|
21029
|
+
if (refreshBtn)
|
|
21030
|
+
refreshBtn.textContent = text2.refresh;
|
|
21031
|
+
const closeBtn = mount.querySelector(".doctor-close");
|
|
21032
|
+
if (closeBtn) {
|
|
21033
|
+
closeBtn.setAttribute("aria-label", text2.close);
|
|
21034
|
+
closeBtn.setAttribute("title", text2.close);
|
|
21035
|
+
}
|
|
21036
|
+
}
|
|
21037
|
+
function bindOnce(mount) {
|
|
21038
|
+
if (mount.dataset.bound)
|
|
21039
|
+
return;
|
|
21040
|
+
mount.dataset.bound = "1";
|
|
21041
|
+
const text2 = doctorText(deps.getLanguage());
|
|
21042
|
+
ensureSkeleton(mount, text2, deps.escapeHtml);
|
|
21043
|
+
const refreshBtn = mount.querySelector(".doctor-refresh");
|
|
21044
|
+
refreshBtn?.addEventListener("click", (event) => {
|
|
21045
|
+
event.preventDefault();
|
|
21046
|
+
load(mount);
|
|
21047
|
+
});
|
|
21048
|
+
const closeBtn = mount.querySelector(".doctor-close");
|
|
21049
|
+
closeBtn?.addEventListener("click", (event) => {
|
|
21050
|
+
event.preventDefault();
|
|
21051
|
+
deps.onCloseRequest?.();
|
|
21052
|
+
});
|
|
21053
|
+
}
|
|
21054
|
+
function isOpen() {
|
|
21055
|
+
const mount = getMount();
|
|
21056
|
+
return mount ? !mount.hidden : false;
|
|
21057
|
+
}
|
|
21058
|
+
async function open() {
|
|
21059
|
+
const mount = getMount();
|
|
21060
|
+
if (!mount)
|
|
21061
|
+
return;
|
|
21062
|
+
bindOnce(mount);
|
|
21063
|
+
applyLocalizedLabels(mount, doctorText(deps.getLanguage()));
|
|
21064
|
+
mount.hidden = false;
|
|
21065
|
+
mount.setAttribute("aria-hidden", "false");
|
|
21066
|
+
mount.removeAttribute("inert");
|
|
21067
|
+
const overlay = getOverlay();
|
|
21068
|
+
if (overlay) {
|
|
21069
|
+
overlay.hidden = false;
|
|
21070
|
+
overlay.setAttribute("aria-hidden", "false");
|
|
21071
|
+
}
|
|
21072
|
+
document.body.classList.add("doctor-sheet-open");
|
|
21073
|
+
await load(mount);
|
|
21074
|
+
}
|
|
21075
|
+
function close() {
|
|
21076
|
+
const mount = getMount();
|
|
21077
|
+
if (!mount)
|
|
21078
|
+
return;
|
|
21079
|
+
mount.hidden = true;
|
|
21080
|
+
mount.setAttribute("aria-hidden", "true");
|
|
21081
|
+
mount.setAttribute("inert", "");
|
|
21082
|
+
const overlay = getOverlay();
|
|
21083
|
+
if (overlay) {
|
|
21084
|
+
overlay.hidden = true;
|
|
21085
|
+
overlay.setAttribute("aria-hidden", "true");
|
|
21086
|
+
}
|
|
21087
|
+
document.body.classList.remove("doctor-sheet-open");
|
|
21088
|
+
viewGeneration += 1;
|
|
21089
|
+
}
|
|
21090
|
+
async function refresh() {
|
|
21091
|
+
const mount = getMount();
|
|
21092
|
+
if (!mount)
|
|
21093
|
+
return;
|
|
21094
|
+
await load(mount);
|
|
21095
|
+
}
|
|
21096
|
+
return { open, close, isOpen, refresh };
|
|
21097
|
+
}
|
|
21098
|
+
|
|
20858
21099
|
// web-src/views/empty-diff-pane.ts
|
|
20859
21100
|
function showEmptyHistoryDiffPane(deps) {
|
|
20860
21101
|
if (deps.diff)
|
|
@@ -21501,7 +21742,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21501
21742
|
const force = options.force === true;
|
|
21502
21743
|
const mount = options.mount || (force ? activeMount : defaultMount);
|
|
21503
21744
|
activateMount(mount);
|
|
21504
|
-
entering = entering.then(() => doEnterHistory(force)).catch(() => {
|
|
21745
|
+
entering = entering.then(() => doEnterHistory(force)).catch(() => {
|
|
21746
|
+
return;
|
|
21747
|
+
});
|
|
21505
21748
|
return entering;
|
|
21506
21749
|
}
|
|
21507
21750
|
async function doEnterHistory(force = false) {
|
|
@@ -21835,6 +22078,19 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21835
22078
|
text: "In large repositories the sidebar loads folder children on demand. Folders you open are remembered and automatically re-expanded after a reload."
|
|
21836
22079
|
}
|
|
21837
22080
|
]
|
|
22081
|
+
},
|
|
22082
|
+
{
|
|
22083
|
+
title: "Environment doctor",
|
|
22084
|
+
blocks: [
|
|
22085
|
+
{
|
|
22086
|
+
kind: "paragraph",
|
|
22087
|
+
text: "Toggle the \uD83E\uDE7A icon in the header to slide in a diagnostic sheet from the right. It works on top of any screen (Repository, Diff, History, Datastores) and the open state is preserved in the URL as ?doctor=open so links are reproducible."
|
|
22088
|
+
},
|
|
22089
|
+
{
|
|
22090
|
+
kind: "paragraph",
|
|
22091
|
+
text: "Each row reports OK / WARN / ERROR with a remediation hint when relevant. The check groups are Runtime (Node / Bun / NODE_MODULE_VERSION), Package (version + execution origin including npx cache), SQLite driver, Snapshot store, Git, Discovery summary, Docker / Compose (CLI / v2 plugin / daemon / compose config dry-parse / compose ps health per discovered service), and Server. The most common hint is the npx cache fix for better-sqlite3 NODE_MODULE_VERSION mismatch (rm -rf ~/.npm/_npx then re-run with npx -y @youtyan/code-viewer@latest)."
|
|
22092
|
+
}
|
|
22093
|
+
]
|
|
21838
22094
|
}
|
|
21839
22095
|
]
|
|
21840
22096
|
},
|
|
@@ -22398,6 +22654,19 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
22398
22654
|
text: "大きいリポジトリではサイドバーがフォルダの中身を必要に応じて読み込みます。開いたフォルダは記憶され、次回のリロード時に同じ状態で展開し直されます。"
|
|
22399
22655
|
}
|
|
22400
22656
|
]
|
|
22657
|
+
},
|
|
22658
|
+
{
|
|
22659
|
+
title: "環境ドクター",
|
|
22660
|
+
blocks: [
|
|
22661
|
+
{
|
|
22662
|
+
kind: "paragraph",
|
|
22663
|
+
text: "ヘッダ右の \uD83E\uDE7A アイコンで、右からスライドする診断シートを開きます。Repository / Diff / History / Datastores などどの画面の上にも重ねて表示でき、開閉状態は URL の ?doctor=open に同期されるのでリンク共有で復元できます。"
|
|
22664
|
+
},
|
|
22665
|
+
{
|
|
22666
|
+
kind: "paragraph",
|
|
22667
|
+
text: "各項目は OK / WARN / ERROR で表示され、必要に応じて対処手順のヒントが付きます。診断グループは Runtime (Node / Bun / NODE_MODULE_VERSION)、Package (バージョン + 実行元: npx cache / global / local / bunx)、SQLite driver、Snapshot store、Git、Discovery summary、Docker / Compose (CLI / v2 plugin / daemon / compose config dry parse / compose ps による各サービスのヘルス)、Server (待ち受けポート) の 8 つ。よくあるヒントは npx キャッシュ起因の better-sqlite3 NODE_MODULE_VERSION 不一致で、rm -rf ~/.npm/_npx の後に npx -y @youtyan/code-viewer@latest を再実行する手順を表示します。"
|
|
22668
|
+
}
|
|
22669
|
+
]
|
|
22401
22670
|
}
|
|
22402
22671
|
]
|
|
22403
22672
|
},
|
|
@@ -23386,7 +23655,9 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
23386
23655
|
if (!GdpExpandLogic.shouldAttachTrailingExpand(data?.lines?.length || 0))
|
|
23387
23656
|
return;
|
|
23388
23657
|
attachTrailingExpandControls(item, file, ref, refPath);
|
|
23389
|
-
}).catch(() => {
|
|
23658
|
+
}).catch(() => {
|
|
23659
|
+
return;
|
|
23660
|
+
});
|
|
23390
23661
|
}
|
|
23391
23662
|
function insertContextRows(targetTr, lines, newStart, oldStart, dir, sideIndex) {
|
|
23392
23663
|
const tbody = targetTr.parentElement;
|
|
@@ -23525,7 +23796,9 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
23525
23796
|
function fetchRefs() {
|
|
23526
23797
|
return fetch("/_refs").then((r2) => r2.json()).then((refs) => {
|
|
23527
23798
|
Object.assign(REFS, refs);
|
|
23528
|
-
}).catch(() => {
|
|
23799
|
+
}).catch(() => {
|
|
23800
|
+
return;
|
|
23801
|
+
});
|
|
23529
23802
|
}
|
|
23530
23803
|
fetchRefs();
|
|
23531
23804
|
let popTab = "commits";
|
|
@@ -28581,7 +28854,9 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
28581
28854
|
headers: actionHeaders(),
|
|
28582
28855
|
body,
|
|
28583
28856
|
keepalive: options.keepalive
|
|
28584
|
-
}).catch(() => {
|
|
28857
|
+
}).catch(() => {
|
|
28858
|
+
return;
|
|
28859
|
+
});
|
|
28585
28860
|
}
|
|
28586
28861
|
let pendingViewPatch = null;
|
|
28587
28862
|
let pendingViewTimer = null;
|
|
@@ -28654,7 +28929,9 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
28654
28929
|
headers: actionHeaders(),
|
|
28655
28930
|
body,
|
|
28656
28931
|
keepalive
|
|
28657
|
-
}).catch(() => {
|
|
28932
|
+
}).catch(() => {
|
|
28933
|
+
return;
|
|
28934
|
+
});
|
|
28658
28935
|
};
|
|
28659
28936
|
if (options.keepalive) {
|
|
28660
28937
|
if (pendingViewTimer !== null)
|
|
@@ -28690,7 +28967,9 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
28690
28967
|
headers: actionHeaders(),
|
|
28691
28968
|
body,
|
|
28692
28969
|
keepalive
|
|
28693
|
-
}).catch(() => {
|
|
28970
|
+
}).catch(() => {
|
|
28971
|
+
return;
|
|
28972
|
+
});
|
|
28694
28973
|
}
|
|
28695
28974
|
function savedScopeOmitDirs() {
|
|
28696
28975
|
return APP_SETTINGS.scopeOmitDirs ? normalizeScopeOmitDirs(APP_SETTINGS.scopeOmitDirs) : null;
|
|
@@ -29886,7 +30165,8 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
29886
30165
|
} : { view: route.screen };
|
|
29887
30166
|
}
|
|
29888
30167
|
function replaceUrlWithCurrentRoute() {
|
|
29889
|
-
const
|
|
30168
|
+
const base2 = withAnnotationSessionParam(buildRoute(STATE.route));
|
|
30169
|
+
const url = withDoctorOverlay(base2, parseDoctorOverlay(window.location.pathname, window.location.search));
|
|
29890
30170
|
const current = window.location.pathname + window.location.search;
|
|
29891
30171
|
if (url !== current) {
|
|
29892
30172
|
history.replaceState(historyStateForRoute(STATE.route), "", url + window.location.hash);
|
|
@@ -29950,7 +30230,7 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
29950
30230
|
if (nextRoute.screen === "repo" || nextRoute.screen === "file" && (nextRoute.view === "blob" || nextRoute.view === "blame" || nextRoute.view === "history")) {
|
|
29951
30231
|
STATE.repoRef = nextRoute.ref || "worktree";
|
|
29952
30232
|
}
|
|
29953
|
-
const url = withAnnotationSessionParam(buildRoute(nextRoute));
|
|
30233
|
+
const url = withDoctorOverlay(withAnnotationSessionParam(buildRoute(nextRoute)), parseDoctorOverlay(window.location.pathname, window.location.search));
|
|
29954
30234
|
const state = historyStateForRoute(nextRoute);
|
|
29955
30235
|
if (replace2)
|
|
29956
30236
|
history.replaceState(state, "", url);
|
|
@@ -30225,6 +30505,10 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
30225
30505
|
$("#sb-expand-all").addEventListener("click", () => setAllSidebarDirsCollapsed(false));
|
|
30226
30506
|
$("#sb-collapse-all").addEventListener("click", () => setAllSidebarDirsCollapsed(true));
|
|
30227
30507
|
$("#viewer-settings")?.addEventListener("click", toggleScopeSettings);
|
|
30508
|
+
$("#doctor-btn")?.addEventListener("click", (event) => {
|
|
30509
|
+
event.preventDefault();
|
|
30510
|
+
toggleDoctorSheet();
|
|
30511
|
+
});
|
|
30228
30512
|
$("#scope-settings-close")?.addEventListener("click", closeScopeSettings);
|
|
30229
30513
|
$("#scope-omit-reset")?.addEventListener("click", resetScopeSettings);
|
|
30230
30514
|
$("#viewer-language")?.addEventListener("change", (event) => {
|
|
@@ -30704,6 +30988,7 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
30704
30988
|
} else
|
|
30705
30989
|
load();
|
|
30706
30990
|
syncLineRefPill();
|
|
30991
|
+
syncDoctorSheetFromUrl();
|
|
30707
30992
|
});
|
|
30708
30993
|
function syncRefInputs() {
|
|
30709
30994
|
const fi = $("#ref-from"), ti = $("#ref-to");
|
|
@@ -30750,7 +31035,9 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
30750
31035
|
STATE.to = range.to;
|
|
30751
31036
|
activeHistoryPathFilter = pathFilter || null;
|
|
30752
31037
|
syncRefInputs();
|
|
30753
|
-
return load().then(() => {
|
|
31038
|
+
return load().then(() => {
|
|
31039
|
+
return;
|
|
31040
|
+
});
|
|
30754
31041
|
},
|
|
30755
31042
|
showEmptyDiffPane: () => {
|
|
30756
31043
|
if (activeFileHistoryDiffHost || activeFileHistoryEmptyHost) {
|
|
@@ -30792,6 +31079,69 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
30792
31079
|
getLanguage: () => STATE.language,
|
|
30793
31080
|
trackLoad
|
|
30794
31081
|
});
|
|
31082
|
+
const DOCTOR_VIEW = createDoctorView({
|
|
31083
|
+
$: (sel) => document.querySelector(sel),
|
|
31084
|
+
escapeHtml: escapeHtml3,
|
|
31085
|
+
trackLoad,
|
|
31086
|
+
getLanguage: () => STATE.language,
|
|
31087
|
+
onWorstStatusChange: (status) => {
|
|
31088
|
+
const badge = document.getElementById("doctor-badge");
|
|
31089
|
+
if (!badge)
|
|
31090
|
+
return;
|
|
31091
|
+
if (status === "error") {
|
|
31092
|
+
badge.hidden = false;
|
|
31093
|
+
badge.dataset.level = "error";
|
|
31094
|
+
} else if (status === "warn") {
|
|
31095
|
+
badge.hidden = false;
|
|
31096
|
+
badge.dataset.level = "warn";
|
|
31097
|
+
} else {
|
|
31098
|
+
badge.hidden = true;
|
|
31099
|
+
badge.removeAttribute("data-level");
|
|
31100
|
+
}
|
|
31101
|
+
},
|
|
31102
|
+
onCloseRequest: () => closeDoctorSheet()
|
|
31103
|
+
});
|
|
31104
|
+
function isDoctorOverlayOpen() {
|
|
31105
|
+
return parseDoctorOverlay(window.location.pathname, window.location.search);
|
|
31106
|
+
}
|
|
31107
|
+
function updateUrlForDoctorOverlay(open) {
|
|
31108
|
+
const current = window.location.pathname + window.location.search;
|
|
31109
|
+
const next = withDoctorOverlay(current, open);
|
|
31110
|
+
if (next !== current) {
|
|
31111
|
+
history.replaceState(history.state, "", next + window.location.hash);
|
|
31112
|
+
}
|
|
31113
|
+
}
|
|
31114
|
+
function openDoctorSheet() {
|
|
31115
|
+
updateUrlForDoctorOverlay(true);
|
|
31116
|
+
DOCTOR_VIEW.open();
|
|
31117
|
+
}
|
|
31118
|
+
function closeDoctorSheet() {
|
|
31119
|
+
DOCTOR_VIEW.close();
|
|
31120
|
+
updateUrlForDoctorOverlay(false);
|
|
31121
|
+
}
|
|
31122
|
+
function toggleDoctorSheet() {
|
|
31123
|
+
if (isDoctorOverlayOpen() || DOCTOR_VIEW.isOpen())
|
|
31124
|
+
closeDoctorSheet();
|
|
31125
|
+
else
|
|
31126
|
+
openDoctorSheet();
|
|
31127
|
+
}
|
|
31128
|
+
function syncDoctorSheetFromUrl() {
|
|
31129
|
+
const shouldOpen = isDoctorOverlayOpen();
|
|
31130
|
+
const open = DOCTOR_VIEW.isOpen();
|
|
31131
|
+
if (shouldOpen && !open)
|
|
31132
|
+
DOCTOR_VIEW.open();
|
|
31133
|
+
else if (!shouldOpen && open)
|
|
31134
|
+
DOCTOR_VIEW.close();
|
|
31135
|
+
}
|
|
31136
|
+
document.getElementById("doctor-sheet-overlay")?.addEventListener("click", () => closeDoctorSheet());
|
|
31137
|
+
document.addEventListener("keydown", (event) => {
|
|
31138
|
+
if (event.key !== "Escape")
|
|
31139
|
+
return;
|
|
31140
|
+
if (!DOCTOR_VIEW.isOpen())
|
|
31141
|
+
return;
|
|
31142
|
+
event.preventDefault();
|
|
31143
|
+
closeDoctorSheet();
|
|
31144
|
+
});
|
|
30795
31145
|
const DATABASE_VIEW = createDatabaseView({
|
|
30796
31146
|
setRoute,
|
|
30797
31147
|
setPageMode,
|
|
@@ -30852,6 +31202,7 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
30852
31202
|
syncRefInputs();
|
|
30853
31203
|
syncHeaderMenu();
|
|
30854
31204
|
syncLineRefPill();
|
|
31205
|
+
syncDoctorSheetFromUrl();
|
|
30855
31206
|
if (isSameBlobFileRoute(previousRoute, STATE.route) && routeBlobPreview(previousRoute) !== routeBlobPreview(STATE.route) && switchSourceTab(routeBlobPreview(STATE.route) ? "preview" : "code", {
|
|
30856
31207
|
updateRoute: false
|
|
30857
31208
|
})) {
|
package/web/index.html
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
<div class="global-actions">
|
|
34
34
|
<button id="annotations-toggle" class="global-icon-action" title="code annotations" aria-label="code annotations">💬<span id="annotations-count" hidden></span></button>
|
|
35
35
|
<button id="viewer-settings" class="global-icon-action" title="viewer settings" aria-label="viewer settings"></button>
|
|
36
|
+
<button id="doctor-btn" class="global-icon-action" title="environment doctor" aria-label="environment doctor">🩺<span id="doctor-badge" class="doctor-badge" hidden></span></button>
|
|
36
37
|
<button id="auto-update" class="global-icon-action active" title="auto update on file change">auto</button>
|
|
37
38
|
<button id="cancel-requests" class="global-icon-action" title="no in-flight requests" aria-label="cancel in-flight requests" disabled>stop</button>
|
|
38
39
|
<button id="theme" title="toggle theme">🌗</button>
|
|
@@ -251,6 +252,8 @@
|
|
|
251
252
|
<div id="query-history-content"></div>
|
|
252
253
|
</aside>
|
|
253
254
|
|
|
255
|
+
<div id="doctor-sheet-overlay" class="doctor-sheet-overlay" hidden aria-hidden="true"></div>
|
|
256
|
+
<aside id="doctor-sheet" class="doctor-sheet" hidden aria-hidden="true" inert aria-label="environment doctor"></aside>
|
|
254
257
|
<main id="content">
|
|
255
258
|
<section id="history-commit-info" hidden></section>
|
|
256
259
|
<div id="empty" class="empty hidden">
|