@youtyan/code-viewer 0.8.2 → 0.8.4
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 +6 -0
- package/dist/code-viewer.js +792 -651
- package/package.json +1 -1
- package/web/app.js +125 -42
- package/web/style.css +46 -0
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -13336,6 +13336,19 @@ ${frontmatter.yaml}
|
|
|
13336
13336
|
return btn;
|
|
13337
13337
|
}
|
|
13338
13338
|
|
|
13339
|
+
// web-src/views/database/query-value.ts
|
|
13340
|
+
function formatQueryValue(value) {
|
|
13341
|
+
if (value === null)
|
|
13342
|
+
return "NULL";
|
|
13343
|
+
if (value instanceof Uint8Array)
|
|
13344
|
+
return `<blob ${value.byteLength} bytes>`;
|
|
13345
|
+
if (typeof value === "boolean")
|
|
13346
|
+
return value ? "true" : "false";
|
|
13347
|
+
if (typeof value === "object")
|
|
13348
|
+
return JSON.stringify(value);
|
|
13349
|
+
return String(value);
|
|
13350
|
+
}
|
|
13351
|
+
|
|
13339
13352
|
// web-src/views/database/shiki-sql.ts
|
|
13340
13353
|
function highlightSqlToInnerHtml(code2, highlighter) {
|
|
13341
13354
|
if (!highlighter || !code2)
|
|
@@ -13517,7 +13530,7 @@ ${frontmatter.yaml}
|
|
|
13517
13530
|
tr.appendChild(tdNum);
|
|
13518
13531
|
for (const value of row) {
|
|
13519
13532
|
const td = document.createElement("td");
|
|
13520
|
-
td.textContent =
|
|
13533
|
+
td.textContent = formatQueryValue(value);
|
|
13521
13534
|
if (value === null)
|
|
13522
13535
|
td.classList.add("null");
|
|
13523
13536
|
tr.appendChild(td);
|
|
@@ -13677,17 +13690,6 @@ ${frontmatter.yaml}
|
|
|
13677
13690
|
localize
|
|
13678
13691
|
};
|
|
13679
13692
|
}
|
|
13680
|
-
function formatValue(value) {
|
|
13681
|
-
if (value === null)
|
|
13682
|
-
return "NULL";
|
|
13683
|
-
if (value instanceof Uint8Array)
|
|
13684
|
-
return `<blob ${value.byteLength} bytes>`;
|
|
13685
|
-
if (typeof value === "boolean")
|
|
13686
|
-
return value ? "true" : "false";
|
|
13687
|
-
if (typeof value === "object")
|
|
13688
|
-
return JSON.stringify(value);
|
|
13689
|
-
return String(value);
|
|
13690
|
-
}
|
|
13691
13693
|
|
|
13692
13694
|
// web-src/views/database/query-history-view.ts
|
|
13693
13695
|
function createQueryHistoryView(callbacks) {
|
|
@@ -13996,7 +13998,7 @@ ${frontmatter.yaml}
|
|
|
13996
13998
|
tr.appendChild(tdNum);
|
|
13997
13999
|
for (const value of row) {
|
|
13998
14000
|
const td = document.createElement("td");
|
|
13999
|
-
td.textContent =
|
|
14001
|
+
td.textContent = formatQueryValue(value);
|
|
14000
14002
|
if (value === null)
|
|
14001
14003
|
td.classList.add("null");
|
|
14002
14004
|
tr.appendChild(td);
|
|
@@ -14131,17 +14133,6 @@ ${frontmatter.yaml}
|
|
|
14131
14133
|
return iso;
|
|
14132
14134
|
}
|
|
14133
14135
|
}
|
|
14134
|
-
function formatValue2(value) {
|
|
14135
|
-
if (value === null)
|
|
14136
|
-
return "NULL";
|
|
14137
|
-
if (value instanceof Uint8Array)
|
|
14138
|
-
return `<blob ${value.byteLength} bytes>`;
|
|
14139
|
-
if (typeof value === "boolean")
|
|
14140
|
-
return value ? "true" : "false";
|
|
14141
|
-
if (typeof value === "object")
|
|
14142
|
-
return JSON.stringify(value);
|
|
14143
|
-
return String(value);
|
|
14144
|
-
}
|
|
14145
14136
|
|
|
14146
14137
|
// web-src/views/database/redis-explorer.ts
|
|
14147
14138
|
function isBinaryItem(item) {
|
|
@@ -19042,7 +19033,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19042
19033
|
}
|
|
19043
19034
|
for (let c2 = 0;c2 < columnNames.length; c2++) {
|
|
19044
19035
|
const original = rowData[c2];
|
|
19045
|
-
const originalShown = original === null ? null : original instanceof Uint8Array ?
|
|
19036
|
+
const originalShown = original === null ? null : original instanceof Uint8Array ? formatValue(original) : String(original);
|
|
19046
19037
|
const hasOverride = pendingForRow?.edits.has(c2) ?? false;
|
|
19047
19038
|
const shown = hasOverride ? pendingForRow?.edits.get(c2) ?? null : originalShown;
|
|
19048
19039
|
const ro = !editableRow || columns[c2]?.primaryKey === true || original instanceof Uint8Array;
|
|
@@ -19118,7 +19109,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19118
19109
|
cell.className = "db-grid-cell";
|
|
19119
19110
|
cell.style.width = `${getColWidth(columnNames[c2])}px`;
|
|
19120
19111
|
const val = rowData[c2];
|
|
19121
|
-
cell.textContent =
|
|
19112
|
+
cell.textContent = formatValue(val);
|
|
19122
19113
|
if (val === null)
|
|
19123
19114
|
cell.classList.add("null");
|
|
19124
19115
|
else if (val instanceof Uint8Array)
|
|
@@ -19715,7 +19706,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19715
19706
|
onEditModeChange
|
|
19716
19707
|
};
|
|
19717
19708
|
}
|
|
19718
|
-
function
|
|
19709
|
+
function formatValue(value) {
|
|
19719
19710
|
if (value === null)
|
|
19720
19711
|
return "NULL";
|
|
19721
19712
|
if (value instanceof Uint8Array)
|
|
@@ -26055,6 +26046,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
26055
26046
|
{
|
|
26056
26047
|
kind: "paragraph",
|
|
26057
26048
|
text: "In large repositories the sidebar loads folder children on demand. Folders you open are remembered and automatically re-expanded after a reload."
|
|
26049
|
+
},
|
|
26050
|
+
{
|
|
26051
|
+
kind: "paragraph",
|
|
26052
|
+
text: 'Symlinks show a distinct icon and a "→ target" label so they are never mistaken for a regular file or folder, and clicking one navigates to its resolved target. A broken symlink is visually flagged and disabled. Files with pending git changes (new, modified, renamed, deleted) show a status badge in the tree instead of the regular type icon.'
|
|
26058
26053
|
}
|
|
26059
26054
|
]
|
|
26060
26055
|
},
|
|
@@ -26722,6 +26717,10 @@ code-viewer query agent-help`
|
|
|
26722
26717
|
{
|
|
26723
26718
|
kind: "paragraph",
|
|
26724
26719
|
text: "大きいリポジトリではサイドバーがフォルダの中身を必要に応じて読み込みます。開いたフォルダは記憶され、次回のリロード時に同じ状態で展開し直されます。"
|
|
26720
|
+
},
|
|
26721
|
+
{
|
|
26722
|
+
kind: "paragraph",
|
|
26723
|
+
text: "シンボリックリンクは専用アイコンと「→ リンク先」ラベルで表示されるため通常のファイル/フォルダと区別でき、クリックするとリンク先に遷移します。リンク切れのシンボリックリンクは無効化されたことが分かる表示になります。未コミットの git 変更(新規・変更・リネーム・削除)があるファイルは、通常の種類アイコンの代わりにステータスバッジがツリーに表示されます。"
|
|
26725
26724
|
}
|
|
26726
26725
|
]
|
|
26727
26726
|
},
|
|
@@ -30719,6 +30718,11 @@ code-viewer query agent-help`
|
|
|
30719
30718
|
node.children_omitted = true;
|
|
30720
30719
|
node.children_omitted_reason = f2.children_omitted_reason;
|
|
30721
30720
|
}
|
|
30721
|
+
if (f2.is_symlink) {
|
|
30722
|
+
node.is_symlink = true;
|
|
30723
|
+
node.symlink_target = f2.symlink_target;
|
|
30724
|
+
node.resolved_path = f2.resolved_path;
|
|
30725
|
+
}
|
|
30722
30726
|
continue;
|
|
30723
30727
|
}
|
|
30724
30728
|
node.files.push(f2);
|
|
@@ -30768,6 +30772,8 @@ code-viewer query agent-help`
|
|
|
30768
30772
|
li.dataset.childrenOmittedReason = dir.children_omitted_reason;
|
|
30769
30773
|
if (dir.explicit)
|
|
30770
30774
|
li.dataset.explicit = "true";
|
|
30775
|
+
if (dir.is_symlink)
|
|
30776
|
+
li.classList.add("symlink-row");
|
|
30771
30777
|
if (dir.children_omitted) {
|
|
30772
30778
|
li.classList.add("children-omitted");
|
|
30773
30779
|
li.classList.add(dir.children_omitted_reason === "heavy" ? "children-omitted-heavy" : "children-omitted-internal");
|
|
@@ -30801,6 +30807,9 @@ code-viewer query agent-help`
|
|
|
30801
30807
|
omitted.title = badge.title;
|
|
30802
30808
|
label.appendChild(omitted);
|
|
30803
30809
|
}
|
|
30810
|
+
const dirSymlinkLabel = symlinkTargetLabel(dir);
|
|
30811
|
+
if (dirSymlinkLabel)
|
|
30812
|
+
label.appendChild(dirSymlinkLabel);
|
|
30804
30813
|
li.appendChild(label);
|
|
30805
30814
|
li.appendChild(createOpenPathButton(dir.path, "directory", openDirectoryInOsTitle()));
|
|
30806
30815
|
const collapsed = STATE.collapsedDirs.has(dir.path);
|
|
@@ -30839,7 +30848,8 @@ code-viewer query agent-help`
|
|
|
30839
30848
|
display_path: dir.path,
|
|
30840
30849
|
type: "tree",
|
|
30841
30850
|
children_omitted: dir.children_omitted,
|
|
30842
|
-
children_omitted_reason: dir.children_omitted_reason
|
|
30851
|
+
children_omitted_reason: dir.children_omitted_reason,
|
|
30852
|
+
resolved_path: dir.resolved_path
|
|
30843
30853
|
});
|
|
30844
30854
|
scheduleMainSurfaceFocus();
|
|
30845
30855
|
});
|
|
@@ -30902,6 +30912,11 @@ code-viewer query agent-help`
|
|
|
30902
30912
|
node.children_omitted = true;
|
|
30903
30913
|
node.children_omitted_reason = entry.children_omitted_reason;
|
|
30904
30914
|
}
|
|
30915
|
+
if (entry.is_symlink) {
|
|
30916
|
+
node.is_symlink = true;
|
|
30917
|
+
node.symlink_target = entry.symlink_target;
|
|
30918
|
+
node.resolved_path = entry.resolved_path;
|
|
30919
|
+
}
|
|
30905
30920
|
return;
|
|
30906
30921
|
}
|
|
30907
30922
|
if (!node.files.some((file) => file.path === entry.path))
|
|
@@ -30937,7 +30952,12 @@ code-viewer query agent-help`
|
|
|
30937
30952
|
type: meta.ref === "worktree" && entry.type === "commit" && !entry.submodule ? "tree" : entry.type,
|
|
30938
30953
|
submodule: entry.submodule,
|
|
30939
30954
|
children_omitted: entry.children_omitted,
|
|
30940
|
-
children_omitted_reason: entry.children_omitted_reason
|
|
30955
|
+
children_omitted_reason: entry.children_omitted_reason,
|
|
30956
|
+
is_symlink: entry.is_symlink,
|
|
30957
|
+
symlink_target: entry.symlink_target,
|
|
30958
|
+
symlink_target_type: entry.symlink_target_type,
|
|
30959
|
+
resolved_path: entry.resolved_path,
|
|
30960
|
+
status: entry.status
|
|
30941
30961
|
}));
|
|
30942
30962
|
mergeSidebarTreeEntries(entries);
|
|
30943
30963
|
SIDEBAR_LAZY_LOADED_DIRS.add(dir.path);
|
|
@@ -30957,6 +30977,8 @@ code-viewer query agent-help`
|
|
|
30957
30977
|
li.dataset.childrenOmittedReason = dir.children_omitted_reason;
|
|
30958
30978
|
if (dir.explicit)
|
|
30959
30979
|
li.dataset.explicit = "true";
|
|
30980
|
+
if (dir.is_symlink)
|
|
30981
|
+
li.classList.add("symlink-row");
|
|
30960
30982
|
if (dir.children_omitted) {
|
|
30961
30983
|
li.classList.add("children-omitted");
|
|
30962
30984
|
li.classList.add(dir.children_omitted_reason === "heavy" ? "children-omitted-heavy" : "children-omitted-internal");
|
|
@@ -30990,6 +31012,9 @@ code-viewer query agent-help`
|
|
|
30990
31012
|
omitted.title = badge.title;
|
|
30991
31013
|
label.appendChild(omitted);
|
|
30992
31014
|
}
|
|
31015
|
+
const dirSymlinkLabel = symlinkTargetLabel(dir);
|
|
31016
|
+
if (dirSymlinkLabel)
|
|
31017
|
+
label.appendChild(dirSymlinkLabel);
|
|
30993
31018
|
li.appendChild(label);
|
|
30994
31019
|
li.appendChild(createOpenPathButton(dir.path, "directory", openDirectoryInOsTitle()));
|
|
30995
31020
|
const updateIcon = () => {
|
|
@@ -31077,16 +31102,38 @@ code-viewer query agent-help`
|
|
|
31077
31102
|
return tag;
|
|
31078
31103
|
}
|
|
31079
31104
|
function sidebarEntryIcon(f2) {
|
|
31105
|
+
if (f2.is_symlink)
|
|
31106
|
+
return iconSvg("octicon-link", LINK_16_PATH);
|
|
31080
31107
|
return f2.type === "commit" ? iconSvg("octicon-git-branch", GIT_BRANCH_16_PATH) : fileEntryIcon();
|
|
31081
31108
|
}
|
|
31109
|
+
function symlinkTargetLabel(f2) {
|
|
31110
|
+
if (!f2.is_symlink)
|
|
31111
|
+
return null;
|
|
31112
|
+
const broken = f2.symlink_target_type === "missing";
|
|
31113
|
+
const label = document.createElement("span");
|
|
31114
|
+
label.className = broken ? "symlink-target broken" : "symlink-target";
|
|
31115
|
+
label.textContent = `→ ${f2.symlink_target || "?"}`;
|
|
31116
|
+
label.title = broken ? `Broken symlink → ${f2.symlink_target || ""}` : `Symlink → ${f2.symlink_target || ""}`;
|
|
31117
|
+
return label;
|
|
31118
|
+
}
|
|
31082
31119
|
function createTreeFileRow(f2, depth, onFileClick) {
|
|
31083
31120
|
const li = document.createElement("li");
|
|
31084
31121
|
li.className = "tree-file";
|
|
31085
31122
|
li.tabIndex = -1;
|
|
31086
31123
|
li.dataset.path = f2.path;
|
|
31087
31124
|
li.dataset.type = f2.type || "blob";
|
|
31125
|
+
const brokenSymlink = f2.is_symlink && f2.symlink_target_type === "missing";
|
|
31126
|
+
const deletedEntry = !!onFileClick && f2.status === "D";
|
|
31127
|
+
if (f2.is_symlink)
|
|
31128
|
+
li.classList.add("symlink-row");
|
|
31088
31129
|
if (f2.type === "commit") {
|
|
31089
31130
|
li.title = commitEntryBadge(f2.submodule).title;
|
|
31131
|
+
} else if (brokenSymlink) {
|
|
31132
|
+
li.classList.add("symlink-broken-row", "gdp-row-disabled");
|
|
31133
|
+
li.setAttribute("aria-disabled", "true");
|
|
31134
|
+
} else if (deletedEntry) {
|
|
31135
|
+
li.classList.add("gdp-row-disabled");
|
|
31136
|
+
li.setAttribute("aria-disabled", "true");
|
|
31090
31137
|
}
|
|
31091
31138
|
li.classList.toggle("viewed", !onFileClick && STATE.viewedFiles.has(f2.path));
|
|
31092
31139
|
li.classList.toggle("hidden-by-tests", STATE.hideTests && !isRepositorySidebarMode() && isTestPath(f2.path || ""));
|
|
@@ -31107,17 +31154,22 @@ code-viewer query agent-help`
|
|
|
31107
31154
|
name.textContent = f2.path.split("/").pop();
|
|
31108
31155
|
name.title = f2.path;
|
|
31109
31156
|
li.appendChild(name);
|
|
31157
|
+
const symlinkLabel = symlinkTargetLabel(f2);
|
|
31158
|
+
if (symlinkLabel)
|
|
31159
|
+
li.appendChild(symlinkLabel);
|
|
31110
31160
|
const kindTag = fileKindTag(f2);
|
|
31111
31161
|
if (kindTag)
|
|
31112
31162
|
li.appendChild(kindTag);
|
|
31113
31163
|
li.addEventListener("click", () => {
|
|
31164
|
+
if (brokenSymlink || deletedEntry)
|
|
31165
|
+
return;
|
|
31114
31166
|
if (onFileClick)
|
|
31115
31167
|
onFileClick(f2);
|
|
31116
31168
|
else
|
|
31117
31169
|
scrollToFile(f2.path);
|
|
31118
31170
|
scheduleMainSurfaceFocus();
|
|
31119
31171
|
});
|
|
31120
|
-
if (!onFileClick)
|
|
31172
|
+
if (!onFileClick && !brokenSymlink)
|
|
31121
31173
|
li.addEventListener("mouseenter", () => prefetchByPath(f2.path), {
|
|
31122
31174
|
passive: true
|
|
31123
31175
|
});
|
|
@@ -32022,7 +32074,8 @@ code-viewer query agent-help`
|
|
|
32022
32074
|
sortColumnLabels,
|
|
32023
32075
|
repositoryFallback,
|
|
32024
32076
|
repositoryRootFallback,
|
|
32025
|
-
commitEntryMeta
|
|
32077
|
+
commitEntryMeta,
|
|
32078
|
+
fileBadge
|
|
32026
32079
|
} = deps;
|
|
32027
32080
|
let REPO_SORT = {
|
|
32028
32081
|
key: "name",
|
|
@@ -32068,9 +32121,21 @@ code-viewer query agent-help`
|
|
|
32068
32121
|
function commitEntryIcon() {
|
|
32069
32122
|
return iconSvg("octicon-git-branch", GIT_BRANCH_16_PATH);
|
|
32070
32123
|
}
|
|
32124
|
+
function symlinkEntryIcon() {
|
|
32125
|
+
return iconSvg("octicon-link", LINK_16_PATH);
|
|
32126
|
+
}
|
|
32071
32127
|
function isWorktreeRef(ref) {
|
|
32072
32128
|
return canTrashWorktreeRef(ref);
|
|
32073
32129
|
}
|
|
32130
|
+
function repoEntryTypeIcon(entry, browsable, nonBrowsableCommit) {
|
|
32131
|
+
const icon = document.createElement("span");
|
|
32132
|
+
icon.className = browsable ? "dir-icon" : nonBrowsableCommit ? "d2h-icon-wrapper gdp-repo-row-gitlink-icon" : "d2h-icon-wrapper";
|
|
32133
|
+
if (browsable)
|
|
32134
|
+
setFolderIcon(icon, true);
|
|
32135
|
+
else
|
|
32136
|
+
icon.innerHTML = entry.is_symlink ? symlinkEntryIcon() : entry.type === "commit" ? commitEntryIcon() : fileEntryIcon();
|
|
32137
|
+
return icon;
|
|
32138
|
+
}
|
|
32074
32139
|
function canBrowseRepoEntry(entry, ref) {
|
|
32075
32140
|
return entry.type === "tree" || entry.type === "commit" && isWorktreeRef(ref) && !entry.submodule;
|
|
32076
32141
|
}
|
|
@@ -32448,28 +32513,31 @@ code-viewer query agent-help`
|
|
|
32448
32513
|
sortedRepoEntries(meta.entries, meta.ref).forEach((entry) => {
|
|
32449
32514
|
const browsable = canBrowseRepoEntry(entry, meta.ref);
|
|
32450
32515
|
const nonBrowsableCommit = entry.type === "commit" && !browsable;
|
|
32516
|
+
const brokenSymlink = !!entry.is_symlink && entry.symlink_target_type === "missing";
|
|
32517
|
+
const deletedEntry = entry.status === "D";
|
|
32451
32518
|
const row = document.createElement("button");
|
|
32452
32519
|
row.type = "button";
|
|
32453
|
-
row.className = nonBrowsableCommit ? `gdp-repo-row ${entry.type} gdp-repo-row-gitlink` : `gdp-repo-row ${entry.type}`;
|
|
32454
|
-
|
|
32455
|
-
|
|
32456
|
-
|
|
32457
|
-
setFolderIcon(icon, true);
|
|
32458
|
-
else
|
|
32459
|
-
icon.innerHTML = entry.type === "commit" ? commitEntryIcon() : fileEntryIcon();
|
|
32520
|
+
row.className = nonBrowsableCommit ? `gdp-repo-row ${entry.type} gdp-repo-row-gitlink` : entry.is_symlink ? `gdp-repo-row ${entry.type} symlink-row${brokenSymlink ? " symlink-broken-row gdp-row-disabled" : ""}` : `gdp-repo-row ${entry.type}`;
|
|
32521
|
+
if (deletedEntry)
|
|
32522
|
+
row.classList.add("gdp-row-disabled");
|
|
32523
|
+
const icon = entry.status ? fileBadge(entry.status) : repoEntryTypeIcon(entry, browsable, nonBrowsableCommit);
|
|
32460
32524
|
const name = document.createElement("span");
|
|
32461
32525
|
name.className = "name";
|
|
32462
32526
|
name.textContent = entry.name;
|
|
32463
32527
|
if (nonBrowsableCommit) {
|
|
32464
32528
|
row.title = commitEntryMeta(entry.submodule).title;
|
|
32465
32529
|
row.setAttribute("aria-disabled", "true");
|
|
32530
|
+
} else if (brokenSymlink || deletedEntry) {
|
|
32531
|
+
row.setAttribute("aria-disabled", "true");
|
|
32466
32532
|
}
|
|
32467
32533
|
const metaBlock = createRepoEntryMeta(entry, browsable);
|
|
32468
32534
|
const size = createRepoEntrySize(entry);
|
|
32469
32535
|
row.append(icon, name, metaBlock, size);
|
|
32470
32536
|
row.addEventListener("click", () => {
|
|
32537
|
+
if (brokenSymlink || deletedEntry)
|
|
32538
|
+
return;
|
|
32471
32539
|
if (browsable) {
|
|
32472
|
-
setRoute(repoRoute(meta.ref, entry.path));
|
|
32540
|
+
setRoute(repoRoute(meta.ref, entry.resolved_path ?? entry.path));
|
|
32473
32541
|
loadRepo();
|
|
32474
32542
|
} else if (entry.type === "blob") {
|
|
32475
32543
|
setRoute({
|
|
@@ -32578,12 +32646,17 @@ code-viewer query agent-help`
|
|
|
32578
32646
|
type: canBrowseRepoEntry(entry, normalizedRef) ? "tree" : entry.type,
|
|
32579
32647
|
submodule: entry.submodule,
|
|
32580
32648
|
children_omitted: entry.children_omitted,
|
|
32581
|
-
children_omitted_reason: entry.children_omitted_reason
|
|
32649
|
+
children_omitted_reason: entry.children_omitted_reason,
|
|
32650
|
+
is_symlink: entry.is_symlink,
|
|
32651
|
+
symlink_target: entry.symlink_target,
|
|
32652
|
+
symlink_target_type: entry.symlink_target_type,
|
|
32653
|
+
resolved_path: entry.resolved_path,
|
|
32654
|
+
status: entry.status
|
|
32582
32655
|
}));
|
|
32583
32656
|
setRepoSidebarRef(normalizedRef);
|
|
32584
32657
|
renderSidebar(files, (file) => {
|
|
32585
32658
|
if (file.type === "tree") {
|
|
32586
|
-
setRoute(repoRoute(normalizedRef, file.path));
|
|
32659
|
+
setRoute(repoRoute(normalizedRef, file.resolved_path ?? file.path));
|
|
32587
32660
|
loadRepo();
|
|
32588
32661
|
return;
|
|
32589
32662
|
}
|
|
@@ -32649,6 +32722,15 @@ code-viewer query agent-help`
|
|
|
32649
32722
|
meta.title = badge.title;
|
|
32650
32723
|
return meta;
|
|
32651
32724
|
}
|
|
32725
|
+
if (entry.is_symlink) {
|
|
32726
|
+
const broken = entry.symlink_target_type === "missing";
|
|
32727
|
+
meta.classList.add("symlink-target");
|
|
32728
|
+
if (broken)
|
|
32729
|
+
meta.classList.add("broken");
|
|
32730
|
+
meta.textContent = `→ ${entry.symlink_target || "?"}`;
|
|
32731
|
+
meta.title = broken ? `Broken symlink → ${entry.symlink_target || ""}` : `Symlink → ${entry.symlink_target || ""}`;
|
|
32732
|
+
return meta;
|
|
32733
|
+
}
|
|
32652
32734
|
const updated = formatFileDate(entry.updated_at || entry.commit_updated_at);
|
|
32653
32735
|
const created = formatFileDate(entry.created_at);
|
|
32654
32736
|
if (browsable && updated) {
|
|
@@ -36077,7 +36159,8 @@ code-viewer query agent-help`
|
|
|
36077
36159
|
commitEntryMeta: (submodule) => {
|
|
36078
36160
|
const text3 = uiText().repo;
|
|
36079
36161
|
return submodule ? { label: text3.submoduleLabel, title: text3.submoduleTitle } : { label: text3.gitlinkLabel, title: text3.gitlinkTitle };
|
|
36080
|
-
}
|
|
36162
|
+
},
|
|
36163
|
+
fileBadge: (status) => DIFF_VIEW.fileBadge(status)
|
|
36081
36164
|
});
|
|
36082
36165
|
const {
|
|
36083
36166
|
loadRepo,
|
package/web/style.css
CHANGED
|
@@ -2646,6 +2646,45 @@ body.gdp-help-page #content {
|
|
|
2646
2646
|
color: var(--accent-emph);
|
|
2647
2647
|
}
|
|
2648
2648
|
|
|
2649
|
+
/* "→ target" sublabel next to a symlink name in the sidebar tree, and the
|
|
2650
|
+
same marker's meta-column form in the repo listing (.gdp-repo-row
|
|
2651
|
+
.meta.symlink-target below). Uses --done (violet) rather than the usual
|
|
2652
|
+
muted meta color so a symlink row reads as distinct at a glance, not
|
|
2653
|
+
just on hover/title. Broken links (target missing/outside the repo)
|
|
2654
|
+
switch to the danger color instead. */
|
|
2655
|
+
.symlink-target {
|
|
2656
|
+
overflow: hidden;
|
|
2657
|
+
text-overflow: ellipsis;
|
|
2658
|
+
white-space: nowrap;
|
|
2659
|
+
color: var(--done);
|
|
2660
|
+
font-weight: 500;
|
|
2661
|
+
font-size: 12px;
|
|
2662
|
+
margin-left: 6px;
|
|
2663
|
+
}
|
|
2664
|
+
.symlink-target.broken { color: var(--danger); }
|
|
2665
|
+
/* Recolor the row's own type icon (file icon, or the shared blue dir-icon)
|
|
2666
|
+
to match the target label, so the symlink signal isn't limited to the
|
|
2667
|
+
sublabel text. */
|
|
2668
|
+
#filelist.tree .tree-file.symlink-row .d2h-icon-wrapper,
|
|
2669
|
+
#filelist.tree .tree-dir.symlink-row .dir-icon,
|
|
2670
|
+
.gdp-repo-row.symlink-row .d2h-icon-wrapper,
|
|
2671
|
+
.gdp-repo-row.symlink-row .dir-icon {
|
|
2672
|
+
color: var(--done);
|
|
2673
|
+
}
|
|
2674
|
+
.tree-file.symlink-broken-row .d2h-icon-wrapper,
|
|
2675
|
+
.gdp-repo-row.symlink-broken-row .d2h-icon-wrapper {
|
|
2676
|
+
color: var(--danger);
|
|
2677
|
+
}
|
|
2678
|
+
/* Shared "disabled row" treatment: a broken symlink or a synthesized
|
|
2679
|
+
deleted-file row (see deletedTreeEntriesForPath in preview.ts) - both are
|
|
2680
|
+
badged but cannot actually be opened. */
|
|
2681
|
+
.tree-file.gdp-row-disabled,
|
|
2682
|
+
.tree-dir.gdp-row-disabled,
|
|
2683
|
+
.gdp-repo-row.gdp-row-disabled {
|
|
2684
|
+
cursor: default;
|
|
2685
|
+
opacity: 0.7;
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2649
2688
|
/* ===== Main content area ===== */
|
|
2650
2689
|
#content {
|
|
2651
2690
|
margin-left: var(--sidebar-w);
|
|
@@ -4595,6 +4634,13 @@ body.gdp-file-detail-page #empty {
|
|
|
4595
4634
|
font-size: 11px;
|
|
4596
4635
|
line-height: 1.4;
|
|
4597
4636
|
}
|
|
4637
|
+
.gdp-repo-row .meta.symlink-target.broken { color: var(--danger); }
|
|
4638
|
+
/* Disabled row (broken symlink or synthesized deleted-file entry): opening
|
|
4639
|
+
it would just 404, so no hover affordance - same treatment as
|
|
4640
|
+
.gdp-repo-row-gitlink above. */
|
|
4641
|
+
.gdp-repo-row.gdp-row-disabled:hover {
|
|
4642
|
+
background: var(--bg);
|
|
4643
|
+
}
|
|
4598
4644
|
.gdp-context-menu {
|
|
4599
4645
|
position: fixed;
|
|
4600
4646
|
z-index: 1000;
|