@youtyan/code-viewer 0.6.1 → 0.6.3
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 +24 -4
- package/dist/code-viewer.js +1036 -312
- package/package.json +1 -1
- package/web/app.js +2053 -266
- package/web/index.html +40 -13
- package/web/style.css +787 -41
package/web/app.js
CHANGED
|
@@ -21,6 +21,48 @@
|
|
|
21
21
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
+
// web-src/core/diff-file-kinds.ts
|
|
25
|
+
var HEAVY_SIZE_CLASSES = new Set(["medium", "large", "huge"]);
|
|
26
|
+
function classifyDiffFileKind(file) {
|
|
27
|
+
const status = (file.status || "")[0]?.toUpperCase();
|
|
28
|
+
const heavy = HEAVY_SIZE_CLASSES.has(file.size_class || "");
|
|
29
|
+
const media = !!file.media_kind;
|
|
30
|
+
return {
|
|
31
|
+
added: status === "A",
|
|
32
|
+
deleted: status === "D",
|
|
33
|
+
renamed: status === "R",
|
|
34
|
+
heavy,
|
|
35
|
+
binary: !media && (file.size_class === "binary" || !!file.binary),
|
|
36
|
+
media
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function summarizeDiffFileKinds(files) {
|
|
40
|
+
const counts = {
|
|
41
|
+
added: 0,
|
|
42
|
+
deleted: 0,
|
|
43
|
+
renamed: 0,
|
|
44
|
+
heavy: 0,
|
|
45
|
+
binary: 0,
|
|
46
|
+
media: 0
|
|
47
|
+
};
|
|
48
|
+
for (const file of files) {
|
|
49
|
+
const kind = classifyDiffFileKind(file);
|
|
50
|
+
if (kind.added)
|
|
51
|
+
counts.added++;
|
|
52
|
+
if (kind.deleted)
|
|
53
|
+
counts.deleted++;
|
|
54
|
+
if (kind.renamed)
|
|
55
|
+
counts.renamed++;
|
|
56
|
+
if (kind.heavy)
|
|
57
|
+
counts.heavy++;
|
|
58
|
+
if (kind.binary)
|
|
59
|
+
counts.binary++;
|
|
60
|
+
if (kind.media)
|
|
61
|
+
counts.media++;
|
|
62
|
+
}
|
|
63
|
+
return counts;
|
|
64
|
+
}
|
|
65
|
+
|
|
24
66
|
// web-src/core/file-path-copy.ts
|
|
25
67
|
function filePathClipboardText(path) {
|
|
26
68
|
return path || "";
|
|
@@ -55,6 +97,13 @@ ${lines.join(`
|
|
|
55
97
|
|
|
56
98
|
// web-src/core/ai-context-copy.ts
|
|
57
99
|
var AI_CONTEXT_LARGE_SELECTION_LINE_THRESHOLD = 300;
|
|
100
|
+
var DATABASE_QUERY_SQL_MAX_CHARS = 200;
|
|
101
|
+
function truncateOneLine(text, maxChars) {
|
|
102
|
+
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
103
|
+
if (collapsed.length <= maxChars)
|
|
104
|
+
return collapsed;
|
|
105
|
+
return `${collapsed.slice(0, maxChars)}...`;
|
|
106
|
+
}
|
|
58
107
|
function lineRange(line) {
|
|
59
108
|
return typeof line === "number" ? { start: line, end: line } : { start: line.start, end: line.end };
|
|
60
109
|
}
|
|
@@ -104,13 +153,14 @@ ${lines.join(`
|
|
|
104
153
|
`)}
|
|
105
154
|
\`\`\``;
|
|
106
155
|
}
|
|
107
|
-
function historyLine(route) {
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
156
|
+
function historyLine(route, diffFrom, diffTo) {
|
|
157
|
+
if (route.commit) {
|
|
158
|
+
const ref = route.ref && route.ref !== "worktree" && route.ref !== "HEAD" ? ` (ref: ${route.ref})` : "";
|
|
159
|
+
return `commit: ${route.commit}${ref}`;
|
|
160
|
+
}
|
|
161
|
+
return `History: ${diffFrom}..${diffTo}${commitOrRefSuffix(route)}`;
|
|
112
162
|
}
|
|
113
|
-
function databaseLine(route) {
|
|
163
|
+
function databaseLine(route, querySql) {
|
|
114
164
|
const parts = [];
|
|
115
165
|
if (route.db)
|
|
116
166
|
parts.push(`db=${route.db}`);
|
|
@@ -123,16 +173,52 @@ ${lines.join(`
|
|
|
123
173
|
if (route.diffBefore && route.diffAfter) {
|
|
124
174
|
parts.push(`snapshot=${route.diffBefore}..${route.diffAfter}`);
|
|
125
175
|
}
|
|
126
|
-
|
|
176
|
+
if (route.tab === "query" && querySql) {
|
|
177
|
+
const sql = truncateOneLine(querySql, DATABASE_QUERY_SQL_MAX_CHARS);
|
|
178
|
+
if (sql)
|
|
179
|
+
parts.push(`sql=${sql}`);
|
|
180
|
+
}
|
|
181
|
+
return parts.length > 0 ? `database: ${parts.join(", ")}` : "database";
|
|
182
|
+
}
|
|
183
|
+
function diffOverviewLine(from, to, meta, viewedFiles) {
|
|
184
|
+
const base = `Diff: ${from}..${to}`;
|
|
185
|
+
if (!meta?.totals)
|
|
186
|
+
return base;
|
|
187
|
+
const parts = [
|
|
188
|
+
`${meta.totals.files} file${meta.totals.files === 1 ? "" : "s"}`,
|
|
189
|
+
`+${meta.totals.additions}/-${meta.totals.deletions}`
|
|
190
|
+
];
|
|
191
|
+
const viewedTotal = meta.files.length;
|
|
192
|
+
if (viewedFiles && viewedTotal > 0) {
|
|
193
|
+
const viewed = meta.files.filter((file) => viewedFiles.has(file.path)).length;
|
|
194
|
+
parts.push(`${viewed}/${viewedTotal} viewed`);
|
|
195
|
+
}
|
|
196
|
+
const kinds = summarizeDiffFileKinds(meta.files);
|
|
197
|
+
const kindParts = [];
|
|
198
|
+
if (kinds.added)
|
|
199
|
+
kindParts.push(`${kinds.added} added`);
|
|
200
|
+
if (kinds.deleted)
|
|
201
|
+
kindParts.push(`${kinds.deleted} deleted`);
|
|
202
|
+
if (kinds.renamed)
|
|
203
|
+
kindParts.push(`${kinds.renamed} renamed`);
|
|
204
|
+
if (kinds.heavy)
|
|
205
|
+
kindParts.push(`${kinds.heavy} heavy`);
|
|
206
|
+
if (kinds.binary)
|
|
207
|
+
kindParts.push(`${kinds.binary} binary`);
|
|
208
|
+
if (kinds.media)
|
|
209
|
+
kindParts.push(`${kinds.media} media`);
|
|
210
|
+
if (kindParts.length > 0)
|
|
211
|
+
parts.push(kindParts.join(", "));
|
|
212
|
+
return `${base} (${parts.join(", ")})`;
|
|
127
213
|
}
|
|
128
214
|
function aiContextClipboardText(snapshot) {
|
|
129
215
|
const { route } = snapshot;
|
|
130
216
|
if (route.screen === "database")
|
|
131
|
-
return databaseLine(route);
|
|
217
|
+
return databaseLine(route, snapshot.databaseQuerySql);
|
|
132
218
|
if (route.screen === "history")
|
|
133
|
-
return historyLine(route);
|
|
219
|
+
return historyLine(route, snapshot.diffFrom, snapshot.diffTo);
|
|
134
220
|
if (route.screen === "diff" && !route.path) {
|
|
135
|
-
return
|
|
221
|
+
return diffOverviewLine(snapshot.diffFrom, snapshot.diffTo, snapshot.diffMeta, snapshot.viewedFiles);
|
|
136
222
|
}
|
|
137
223
|
return referenceLine(route, snapshot.selectionCode);
|
|
138
224
|
}
|
|
@@ -401,6 +487,30 @@ ${lines.join(`
|
|
|
401
487
|
"M7.47 2.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 1 1-1.06 1.06L8 3.81 4.28 7.53a.75.75 0 0 1-1.06-1.06Z",
|
|
402
488
|
"M7.47 6.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 1 1-1.06 1.06L8 7.81l-3.72 3.72a.75.75 0 1 1-1.06-1.06Z"
|
|
403
489
|
];
|
|
490
|
+
var PLAY_16_PATH = "M4.75 3.625a.75.75 0 0 1 1.148-.635l6 3.875a.75.75 0 0 1 0 1.27l-6 3.875A.75.75 0 0 1 4.75 11.375Z";
|
|
491
|
+
var PAUSE_16_PATHS = [
|
|
492
|
+
"M4.75 3A.75.75 0 0 1 5.5 2.25h1A.75.75 0 0 1 7.25 3v10a.75.75 0 0 1-.75.75h-1A.75.75 0 0 1 4.75 13Z",
|
|
493
|
+
"M8.75 3a.75.75 0 0 1 .75-.75h1a.75.75 0 0 1 .75.75v10a.75.75 0 0 1-.75.75h-1a.75.75 0 0 1-.75-.75Z"
|
|
494
|
+
];
|
|
495
|
+
var PREVIOUS_16_PATHS = [
|
|
496
|
+
"M3.75 3a.75.75 0 0 1 .75.75v8.5a.75.75 0 0 1-1.5 0v-8.5A.75.75 0 0 1 3.75 3Z",
|
|
497
|
+
"M12.22 3.22a.749.749 0 0 1 0 1.06L8.5 8l3.72 3.72a.749.749 0 1 1-1.06 1.06L6.91 8.53a.749.749 0 0 1 0-1.06l4.25-4.25a.749.749 0 0 1 1.06 0Z"
|
|
498
|
+
];
|
|
499
|
+
var NEXT_16_PATHS = [
|
|
500
|
+
"M12.25 3a.75.75 0 0 1 .75.75v8.5a.75.75 0 0 1-1.5 0v-8.5a.75.75 0 0 1 .75-.75Z",
|
|
501
|
+
"M3.78 3.22a.749.749 0 0 1 1.06 0l4.25 4.25a.749.749 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.06-1.06L7.5 8 3.78 4.28a.749.749 0 0 1 0-1.06Z"
|
|
502
|
+
];
|
|
503
|
+
var VOLUME_UNMUTED_16_PATHS = [
|
|
504
|
+
"M7.563 2.069A.75.75 0 0 1 8 2.75v10.5a.75.75 0 0 1-1.188.61L3.766 11.5H1.75A1.75 1.75 0 0 1 0 9.75v-3.5C0 5.284.784 4.5 1.75 4.5h2.016l3.046-2.36a.75.75 0 0 1 .751-.071ZM6.5 4.279 4.484 5.841A.75.75 0 0 1 4.025 6H1.75a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h2.275a.75.75 0 0 1 .459.159L6.5 11.721Z",
|
|
505
|
+
"M10.28 5.22a.749.749 0 0 1 1.06 0 3.93 3.93 0 0 1 0 5.56.749.749 0 1 1-1.06-1.06 2.43 2.43 0 0 0 0-3.44.749.749 0 0 1 0-1.06Z",
|
|
506
|
+
"M12.39 3.11a.749.749 0 0 1 1.06 0 6.91 6.91 0 0 1 0 9.78.749.749 0 0 1-1.06-1.06 5.41 5.41 0 0 0 0-7.66.749.749 0 0 1 0-1.06Z"
|
|
507
|
+
];
|
|
508
|
+
var VOLUME_MUTED_16_PATHS = [
|
|
509
|
+
VOLUME_UNMUTED_16_PATHS[0],
|
|
510
|
+
"M10.28 6.22 11.5 7.44l1.22-1.22a.749.749 0 1 1 1.06 1.06L12.56 8.5l1.22 1.22a.749.749 0 1 1-1.06 1.06L11.5 9.56l-1.22 1.22a.749.749 0 1 1-1.06-1.06l1.22-1.22-1.22-1.22a.749.749 0 1 1 1.06-1.06Z"
|
|
511
|
+
];
|
|
512
|
+
var X_16_PATH = "M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z";
|
|
513
|
+
var SYNC_16_PATH = "M1.705 8.005a.75.75 0 0 1 .834.656 5.5 5.5 0 0 0 9.592 2.97l-1.204-1.204a.25.25 0 0 1 .177-.427h3.646a.25.25 0 0 1 .25.25v3.646a.25.25 0 0 1-.427.177l-1.38-1.38A7.002 7.002 0 0 1 1.05 8.84a.75.75 0 0 1 .656-.834ZM8 2.5a5.487 5.487 0 0 0-4.131 1.869l1.204 1.204A.25.25 0 0 1 4.896 6H1.25A.25.25 0 0 1 1 5.75V2.104a.25.25 0 0 1 .427-.177l1.38 1.38A7.002 7.002 0 0 1 14.95 7.16a.75.75 0 0 1-1.49.178A5.5 5.5 0 0 0 8 2.5Z";
|
|
404
514
|
function iconSvg(className, paths) {
|
|
405
515
|
const pathList = Array.isArray(paths) ? paths : [paths];
|
|
406
516
|
return '<svg class="octicon ' + className + '" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true">' + pathList.map((path) => `<path fill="currentColor" d="${path}"></path>`).join("") + "</svg>";
|
|
@@ -409,6 +519,12 @@ ${lines.join(`
|
|
|
409
519
|
var COMMENT_DISCUSSION_16_PATH = "M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z";
|
|
410
520
|
var PULSE_16_PATH = "M6 2c.306 0 .582.187.696.471L10 10.731l1.304-3.26A.751.751 0 0 1 12 7h3.25a.75.75 0 0 1 0 1.5h-2.742l-1.812 4.528a.751.751 0 0 1-1.392 0L6 4.77 4.696 8.03A.75.75 0 0 1 4 8.5H.75a.75.75 0 0 1 0-1.5h2.742l1.812-4.529A.751.751 0 0 1 6 2Z";
|
|
411
521
|
var MOON_16_PATH = "M9.598 1.591a.749.749 0 0 1 .785-.175 7.001 7.001 0 1 1-8.967 8.967.75.75 0 0 1 .961-.96 5.5 5.5 0 0 0 7.046-7.046.75.75 0 0 1 .175-.786Zm1.616 1.945a7 7 0 0 1-7.678 7.678 5.499 5.499 0 1 0 7.678-7.678Z";
|
|
522
|
+
var SEARCH_16_PATH = "M10.68 11.74a6 6 0 0 1-7.917-8.984 6 6 0 0 1 8.997 7.905l3.05 3.05a.75.75 0 1 1-1.06 1.06l-3.07-3.03ZM11.5 7a4.499 4.499 0 1 1-8.997 0A4.499 4.499 0 0 1 11.5 7Z";
|
|
523
|
+
var DOWNLOAD_16_PATHS = [
|
|
524
|
+
"M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z",
|
|
525
|
+
"M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"
|
|
526
|
+
];
|
|
527
|
+
var LINK_16_PATH = "m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z";
|
|
412
528
|
|
|
413
529
|
// web-src/core/keyboard.ts
|
|
414
530
|
function isImeComposing(event) {
|
|
@@ -522,7 +638,8 @@ ${lines.join(`
|
|
|
522
638
|
{ action: "toggle-theme", key: "t" },
|
|
523
639
|
{ action: "open-help", key: "?", shift: true },
|
|
524
640
|
{ action: "copy-ai-context", key: "y" },
|
|
525
|
-
{ action: "copy-ai-context-with-code", key: "y", shift: true }
|
|
641
|
+
{ action: "copy-ai-context-with-code", key: "y", shift: true },
|
|
642
|
+
{ action: "next-unviewed-file", key: "n" }
|
|
526
643
|
];
|
|
527
644
|
function resolveKeymapAction(event, context) {
|
|
528
645
|
const key = event.key.toLowerCase();
|
|
@@ -1553,6 +1670,11 @@ ${lines.join(`
|
|
|
1553
1670
|
}
|
|
1554
1671
|
|
|
1555
1672
|
// web-src/views/annotations-player.ts
|
|
1673
|
+
function setIconButton(button, label, iconClass, paths) {
|
|
1674
|
+
button.innerHTML = iconSvg(iconClass, paths);
|
|
1675
|
+
button.title = label;
|
|
1676
|
+
button.setAttribute("aria-label", label);
|
|
1677
|
+
}
|
|
1556
1678
|
function createAnnotationsPlayer(deps) {
|
|
1557
1679
|
const bar = deps.$("#annotation-player");
|
|
1558
1680
|
const toggleBtn = deps.$("#annotation-player-toggle");
|
|
@@ -1609,9 +1731,11 @@ ${lines.join(`
|
|
|
1609
1731
|
}
|
|
1610
1732
|
function render(state) {
|
|
1611
1733
|
bar.classList.toggle("playing", state.status === "playing");
|
|
1612
|
-
toggleBtn.
|
|
1734
|
+
setIconButton(toggleBtn, state.status === "playing" ? "Pause annotation playback" : "Play annotation playback", state.status === "playing" ? "octicon-pause" : "octicon-play", state.status === "playing" ? PAUSE_16_PATHS : PLAY_16_PATH);
|
|
1735
|
+
setIconButton(prevBtn, "Previous annotation", "octicon-skip-back", PREVIOUS_16_PATHS);
|
|
1736
|
+
setIconButton(nextBtn, "Next annotation", "octicon-skip-forward", NEXT_16_PATHS);
|
|
1613
1737
|
progress.textContent = state.status === "idle" || state.index < 0 ? `${state.total}` : `${state.index + 1}/${state.total}`;
|
|
1614
|
-
muteBtn.
|
|
1738
|
+
setIconButton(muteBtn, state.muted ? "Unmute annotation playback" : "Mute annotation playback", state.muted ? "octicon-volume-muted" : "octicon-volume-unmuted", state.muted ? VOLUME_MUTED_16_PATHS : VOLUME_UNMUTED_16_PATHS);
|
|
1615
1739
|
prevBtn.disabled = state.status === "idle";
|
|
1616
1740
|
nextBtn.disabled = state.status === "idle";
|
|
1617
1741
|
}
|
|
@@ -8206,6 +8330,14 @@ ${frontmatter.yaml}
|
|
|
8206
8330
|
const annotationListCountEl = $("#annotation-list-count");
|
|
8207
8331
|
const annotationCaptureDb = $("#annotation-capture-db");
|
|
8208
8332
|
annotationCaptureDb.innerHTML = iconSvg("octicon-plus", PLUS_16_PATH);
|
|
8333
|
+
const annotationDetailPrev = $("#annotation-detail-prev");
|
|
8334
|
+
const annotationDetailNext = $("#annotation-detail-next");
|
|
8335
|
+
annotationDetailPrev.innerHTML = iconSvg("octicon-skip-back", PREVIOUS_16_PATHS);
|
|
8336
|
+
annotationDetailPrev.title = "previous annotation";
|
|
8337
|
+
annotationDetailPrev.setAttribute("aria-label", "previous annotation");
|
|
8338
|
+
annotationDetailNext.innerHTML = iconSvg("octicon-skip-forward", NEXT_16_PATHS);
|
|
8339
|
+
annotationDetailNext.title = "next annotation";
|
|
8340
|
+
annotationDetailNext.setAttribute("aria-label", "next annotation");
|
|
8209
8341
|
function updateDatabaseCaptureButton() {
|
|
8210
8342
|
annotationCaptureDb.hidden = deps.getRoute().screen !== "database";
|
|
8211
8343
|
}
|
|
@@ -8842,11 +8974,10 @@ ${frontmatter.yaml}
|
|
|
8842
8974
|
edit.addEventListener("click", () => {
|
|
8843
8975
|
openAnnotationEditForm(entry);
|
|
8844
8976
|
});
|
|
8845
|
-
|
|
8846
|
-
head?.insertBefore(
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
$("#annotation-detail-next").disabled = index >= session.entries.length - 1;
|
|
8977
|
+
head?.insertBefore(copyRef, annotationDetailPrev);
|
|
8978
|
+
head?.insertBefore(edit, annotationDetailPrev);
|
|
8979
|
+
annotationDetailPrev.disabled = index <= 0;
|
|
8980
|
+
annotationDetailNext.disabled = index >= session.entries.length - 1;
|
|
8850
8981
|
annotationDetail.hidden = false;
|
|
8851
8982
|
setAnnotationPanelOpen(true);
|
|
8852
8983
|
updateActiveHighlights();
|
|
@@ -9077,10 +9208,10 @@ ${frontmatter.yaml}
|
|
|
9077
9208
|
postAnnotationAction({ action: "clear" });
|
|
9078
9209
|
});
|
|
9079
9210
|
$("#annotation-detail-close").addEventListener("click", hideAnnotationDetail);
|
|
9080
|
-
|
|
9211
|
+
annotationDetailPrev.addEventListener("click", () => {
|
|
9081
9212
|
stepAnnotation(-1);
|
|
9082
9213
|
});
|
|
9083
|
-
|
|
9214
|
+
annotationDetailNext.addEventListener("click", () => {
|
|
9084
9215
|
stepAnnotation(1);
|
|
9085
9216
|
});
|
|
9086
9217
|
$("#annotation-detail-location").addEventListener("click", (e2) => {
|
|
@@ -9659,6 +9790,15 @@ ${frontmatter.yaml}
|
|
|
9659
9790
|
schemaTab: "Schema",
|
|
9660
9791
|
selectDatastore: "Select datastore",
|
|
9661
9792
|
selectSchema: "Select PostgreSQL schema",
|
|
9793
|
+
refreshDatastores: "Refresh datastores",
|
|
9794
|
+
refreshDatastoresShort: "Refresh",
|
|
9795
|
+
refreshDatastoresBusy: "Refreshing...",
|
|
9796
|
+
refreshDatastoresTitle: "Refresh the datastore list",
|
|
9797
|
+
refreshDatastoresUnchanged: "No datastore changes",
|
|
9798
|
+
refreshDatastoresChanged: (added, removed) => [
|
|
9799
|
+
added > 0 ? `+${added} datastore${added === 1 ? "" : "s"}` : "",
|
|
9800
|
+
removed > 0 ? `-${removed} datastore${removed === 1 ? "" : "s"}` : ""
|
|
9801
|
+
].filter(Boolean).join(" / "),
|
|
9662
9802
|
toolbar: "Datastore tools",
|
|
9663
9803
|
query: "Query",
|
|
9664
9804
|
queryTitle: "Query Editor",
|
|
@@ -9674,6 +9814,8 @@ ${frontmatter.yaml}
|
|
|
9674
9814
|
closeTab: (label) => `Close ${label}`,
|
|
9675
9815
|
loadingSchema: "Loading schema…",
|
|
9676
9816
|
noDatastores: "No datastores found",
|
|
9817
|
+
noDatastoresHint: "Start a database service or add a SQLite file, then refresh this list.",
|
|
9818
|
+
noDatastoreTab: "No datastore",
|
|
9677
9819
|
dockerLimitReached: "Docker discovery reached the service limit; some compose services may be hidden.",
|
|
9678
9820
|
inferFkLabel: "Rails FK inference",
|
|
9679
9821
|
inferFkTitle: "Infer FK from Rails-style <name>_id → <names>.id",
|
|
@@ -9683,12 +9825,29 @@ ${frontmatter.yaml}
|
|
|
9683
9825
|
grid: {
|
|
9684
9826
|
searchPlaceholder: "Search all columns…",
|
|
9685
9827
|
columnFilterPlaceholder: (column) => `${column}…`,
|
|
9828
|
+
clearFiltersLabel: "Clear filters",
|
|
9829
|
+
clearFiltersAction: (count) => `Clear ${count} active filter${count === 1 ? "" : "s"}`,
|
|
9830
|
+
refreshLabel: "Reload table",
|
|
9831
|
+
refreshFilteredLabel: "Reload filtered rows",
|
|
9832
|
+
refreshingLabel: "Reloading...",
|
|
9833
|
+
refreshAction: "Reload this table, keeping search and column filters",
|
|
9834
|
+
refreshActionWithFilters: (count) => `Reload this table, keeping ${count} active filter${count === 1 ? "" : "s"}`,
|
|
9835
|
+
refreshResultChanged: (delta, total) => {
|
|
9836
|
+
const abs = Math.abs(delta).toLocaleString();
|
|
9837
|
+
const sign = delta > 0 ? "+" : "-";
|
|
9838
|
+
return `Rows ${sign}${abs} (${total} now)`;
|
|
9839
|
+
},
|
|
9840
|
+
refreshResultUnchanged: (total) => `Rows unchanged (${total})`,
|
|
9686
9841
|
exportAction: "Export",
|
|
9687
9842
|
foreignKeyHint: "Foreign key — click to view related rows",
|
|
9688
9843
|
relatedEmpty: "No matching row in the referenced table",
|
|
9844
|
+
filteredEmptyTitle: (count) => `No rows match ${count} active filter${count === 1 ? "" : "s"}`,
|
|
9845
|
+
filteredEmptyHint: "The table was loaded, but the current search or column filters hide every row.",
|
|
9846
|
+
filteredEmptyAction: "Clear filters",
|
|
9689
9847
|
statusRows: (n2) => `${n2} rows`,
|
|
9690
9848
|
statusSort: (column, dir) => `Sort: ${column} ${dir}`,
|
|
9691
|
-
statusFilters: (n2) => `${n2} filter(s)
|
|
9849
|
+
statusFilters: (n2) => `${n2} filter(s)`,
|
|
9850
|
+
statusRefreshing: (filters) => filters > 0 ? `Reloading with ${filters} active filter${filters === 1 ? "" : "s"}…` : "Reloading current table…"
|
|
9692
9851
|
},
|
|
9693
9852
|
edit: {
|
|
9694
9853
|
editMode: "Edit",
|
|
@@ -9712,6 +9871,9 @@ ${frontmatter.yaml}
|
|
|
9712
9871
|
indexes: "Indexes",
|
|
9713
9872
|
triggers: "Triggers",
|
|
9714
9873
|
ddl: "DDL",
|
|
9874
|
+
refreshLabel: "Refresh schema",
|
|
9875
|
+
refreshAction: "Refresh this table schema",
|
|
9876
|
+
refreshingLabel: "Refreshing...",
|
|
9715
9877
|
copyDdl: "Copy DDL",
|
|
9716
9878
|
copied: "Copied!",
|
|
9717
9879
|
colName: "Column",
|
|
@@ -9749,8 +9911,10 @@ ${frontmatter.yaml}
|
|
|
9749
9911
|
statusExplain: (ms) => `Explain (${ms}ms)`
|
|
9750
9912
|
},
|
|
9751
9913
|
history: {
|
|
9752
|
-
refresh: "Refresh",
|
|
9753
|
-
refreshTitle: "Refresh history",
|
|
9914
|
+
refresh: "Refresh history",
|
|
9915
|
+
refreshTitle: "Refresh query history",
|
|
9916
|
+
refreshResultAdded: (count) => `+${count} queries`,
|
|
9917
|
+
refreshResultUnchanged: "No new queries",
|
|
9754
9918
|
clearAll: "Clear All",
|
|
9755
9919
|
clearTitle: "Delete all query history",
|
|
9756
9920
|
selectPlaceholder: "Select a query to view details",
|
|
@@ -9761,6 +9925,10 @@ ${frontmatter.yaml}
|
|
|
9761
9925
|
delete: "Delete",
|
|
9762
9926
|
confirmDelete: "Confirm delete",
|
|
9763
9927
|
confirmClear: "Confirm clear",
|
|
9928
|
+
executorAi: "AI",
|
|
9929
|
+
executorUser: "User",
|
|
9930
|
+
rowsLabel: (rows, truncated) => `${rows}${truncated ? "+" : ""} rows`,
|
|
9931
|
+
elapsedLabel: (ms) => `${ms}ms`,
|
|
9764
9932
|
truncatedRows: (saved, total) => `Showing ${saved} of ${total} rows`
|
|
9765
9933
|
},
|
|
9766
9934
|
sessionLog: {
|
|
@@ -9944,6 +10112,15 @@ ${frontmatter.yaml}
|
|
|
9944
10112
|
schemaTab: "スキーマ",
|
|
9945
10113
|
selectDatastore: "データストアを選択",
|
|
9946
10114
|
selectSchema: "PostgreSQL スキーマを選択",
|
|
10115
|
+
refreshDatastores: "データストアを更新",
|
|
10116
|
+
refreshDatastoresShort: "更新",
|
|
10117
|
+
refreshDatastoresBusy: "更新中...",
|
|
10118
|
+
refreshDatastoresTitle: "データストア一覧を更新",
|
|
10119
|
+
refreshDatastoresUnchanged: "データストアに変化なし",
|
|
10120
|
+
refreshDatastoresChanged: (added, removed) => [
|
|
10121
|
+
added > 0 ? `+${added} データストア` : "",
|
|
10122
|
+
removed > 0 ? `-${removed} データストア` : ""
|
|
10123
|
+
].filter(Boolean).join(" / "),
|
|
9947
10124
|
toolbar: "データストアツール",
|
|
9948
10125
|
query: "クエリ",
|
|
9949
10126
|
queryTitle: "クエリエディタ",
|
|
@@ -9959,6 +10136,8 @@ ${frontmatter.yaml}
|
|
|
9959
10136
|
closeTab: (label) => `${label} を閉じる`,
|
|
9960
10137
|
loadingSchema: "スキーマを読み込み中…",
|
|
9961
10138
|
noDatastores: "データストアが見つかりません",
|
|
10139
|
+
noDatastoresHint: "DB サービスを起動するか SQLite ファイルを追加してから、一覧を更新してください。",
|
|
10140
|
+
noDatastoreTab: "未検出",
|
|
9962
10141
|
dockerLimitReached: "Docker のサービス数が上限に達しました。一部の compose サービスは表示されていない可能性があります。",
|
|
9963
10142
|
inferFkLabel: "Rails FK 推測",
|
|
9964
10143
|
inferFkTitle: "Rails 命名規約 (<name>_id → <names>.id) から FK を推測",
|
|
@@ -9968,12 +10147,29 @@ ${frontmatter.yaml}
|
|
|
9968
10147
|
grid: {
|
|
9969
10148
|
searchPlaceholder: "全カラムを検索…",
|
|
9970
10149
|
columnFilterPlaceholder: (column) => `${column}…`,
|
|
10150
|
+
clearFiltersLabel: "フィルタ解除",
|
|
10151
|
+
clearFiltersAction: (count) => `有効なフィルタ ${count} 件を解除`,
|
|
10152
|
+
refreshLabel: "表を再読込",
|
|
10153
|
+
refreshFilteredLabel: "絞り込み再読込",
|
|
10154
|
+
refreshingLabel: "更新中...",
|
|
10155
|
+
refreshAction: "検索/列フィルタを保持して、この表だけ再読み込み",
|
|
10156
|
+
refreshActionWithFilters: (count) => `有効なフィルタ ${count} 件を保持して、この表だけ再読み込み`,
|
|
10157
|
+
refreshResultChanged: (delta, total) => {
|
|
10158
|
+
const abs = Math.abs(delta).toLocaleString();
|
|
10159
|
+
const sign = delta > 0 ? "+" : "-";
|
|
10160
|
+
return `行数 ${sign}${abs} (現在 ${total})`;
|
|
10161
|
+
},
|
|
10162
|
+
refreshResultUnchanged: (total) => `行数変化なし (${total})`,
|
|
9971
10163
|
exportAction: "エクスポート",
|
|
9972
10164
|
foreignKeyHint: "外部キー: クリックして関連データを表示",
|
|
9973
10165
|
relatedEmpty: "参照先に該当する行がありません",
|
|
10166
|
+
filteredEmptyTitle: (count) => `フィルタ ${count} 件に一致する行がありません`,
|
|
10167
|
+
filteredEmptyHint: "表は読み込めていますが、現在の検索/列フィルタですべての行が隠れています。",
|
|
10168
|
+
filteredEmptyAction: "フィルタ解除",
|
|
9974
10169
|
statusRows: (n2) => `${n2} 行`,
|
|
9975
10170
|
statusSort: (column, dir) => `並び替え: ${column} ${dir}`,
|
|
9976
|
-
statusFilters: (n2) => `フィルタ ${n2}
|
|
10171
|
+
statusFilters: (n2) => `フィルタ ${n2} 件`,
|
|
10172
|
+
statusRefreshing: (filters) => filters > 0 ? `フィルタ ${filters} 件を保持して再読み込み中…` : "この表を再読み込み中…"
|
|
9977
10173
|
},
|
|
9978
10174
|
edit: {
|
|
9979
10175
|
editMode: "編集",
|
|
@@ -9997,6 +10193,9 @@ ${frontmatter.yaml}
|
|
|
9997
10193
|
indexes: "インデックス",
|
|
9998
10194
|
triggers: "トリガー",
|
|
9999
10195
|
ddl: "DDL",
|
|
10196
|
+
refreshLabel: "スキーマを更新",
|
|
10197
|
+
refreshAction: "この表のスキーマを再読み込み",
|
|
10198
|
+
refreshingLabel: "更新中...",
|
|
10000
10199
|
copyDdl: "DDL をコピー",
|
|
10001
10200
|
copied: "コピーしました",
|
|
10002
10201
|
colName: "カラム",
|
|
@@ -10034,8 +10233,10 @@ ${frontmatter.yaml}
|
|
|
10034
10233
|
statusExplain: (ms) => `Explain (${ms}ms)`
|
|
10035
10234
|
},
|
|
10036
10235
|
history: {
|
|
10037
|
-
refresh: "
|
|
10038
|
-
refreshTitle: "
|
|
10236
|
+
refresh: "クエリ履歴を更新",
|
|
10237
|
+
refreshTitle: "クエリ履歴を再読み込み",
|
|
10238
|
+
refreshResultAdded: (count) => `+${count} 件`,
|
|
10239
|
+
refreshResultUnchanged: "新しいクエリはありません",
|
|
10039
10240
|
clearAll: "すべて削除",
|
|
10040
10241
|
clearTitle: "クエリ履歴をすべて削除",
|
|
10041
10242
|
selectPlaceholder: "クエリを選択すると詳細が表示されます",
|
|
@@ -10046,6 +10247,10 @@ ${frontmatter.yaml}
|
|
|
10046
10247
|
delete: "削除",
|
|
10047
10248
|
confirmDelete: "削除を確認",
|
|
10048
10249
|
confirmClear: "全削除を確認",
|
|
10250
|
+
executorAi: "AI",
|
|
10251
|
+
executorUser: "ユーザー",
|
|
10252
|
+
rowsLabel: (rows, truncated) => `${rows}${truncated ? "+" : ""} 行`,
|
|
10253
|
+
elapsedLabel: (ms) => `${ms}ms`,
|
|
10049
10254
|
truncatedRows: (saved, total) => `全 ${total} 行中 ${saved} 行を表示`
|
|
10050
10255
|
},
|
|
10051
10256
|
sessionLog: {
|
|
@@ -11861,16 +12066,22 @@ ${frontmatter.yaml}
|
|
|
11861
12066
|
const toolbar = document.createElement("div");
|
|
11862
12067
|
toolbar.className = "db-query-history-toolbar";
|
|
11863
12068
|
const refreshBtn = document.createElement("button");
|
|
11864
|
-
refreshBtn.className = "db-query-history-action";
|
|
12069
|
+
refreshBtn.className = "db-query-history-action db-query-history-refresh";
|
|
11865
12070
|
refreshBtn.type = "button";
|
|
11866
|
-
refreshBtn.
|
|
11867
|
-
|
|
12071
|
+
refreshBtn.innerHTML = iconSvg("octicon-sync", SYNC_16_PATH);
|
|
12072
|
+
const refreshLabel = document.createElement("span");
|
|
12073
|
+
refreshLabel.className = "db-query-history-action-label";
|
|
12074
|
+
refreshBtn.appendChild(refreshLabel);
|
|
12075
|
+
const refreshResult = document.createElement("span");
|
|
12076
|
+
refreshResult.className = "db-refresh-result db-query-history-refresh-result";
|
|
12077
|
+
refreshResult.setAttribute("aria-live", "polite");
|
|
12078
|
+
refreshResult.hidden = true;
|
|
11868
12079
|
const clearBtn = document.createElement("button");
|
|
11869
12080
|
clearBtn.className = "db-query-history-action db-query-history-danger";
|
|
11870
12081
|
clearBtn.type = "button";
|
|
11871
12082
|
clearBtn.textContent = text2().history.clearAll;
|
|
11872
12083
|
clearBtn.title = text2().history.clearTitle;
|
|
11873
|
-
toolbar.append(refreshBtn, clearBtn);
|
|
12084
|
+
toolbar.append(refreshBtn, refreshResult, clearBtn);
|
|
11874
12085
|
const body = document.createElement("div");
|
|
11875
12086
|
body.className = "db-query-history-body-split";
|
|
11876
12087
|
const listCol = document.createElement("div");
|
|
@@ -11894,6 +12105,50 @@ ${frontmatter.yaml}
|
|
|
11894
12105
|
let inFlightRefresh = null;
|
|
11895
12106
|
const entryRowsById = new Map;
|
|
11896
12107
|
let selectedEntryRow = null;
|
|
12108
|
+
let refreshResultState = { type: "none" };
|
|
12109
|
+
function syncRefreshButtonLabel() {
|
|
12110
|
+
refreshLabel.textContent = text2().history.refresh;
|
|
12111
|
+
refreshBtn.title = text2().history.refreshTitle;
|
|
12112
|
+
refreshBtn.setAttribute("aria-label", text2().history.refreshTitle);
|
|
12113
|
+
}
|
|
12114
|
+
function setRefreshBusy(isBusy) {
|
|
12115
|
+
refreshBtn.disabled = isBusy;
|
|
12116
|
+
refreshBtn.classList.toggle("spinning", isBusy);
|
|
12117
|
+
refreshBtn.setAttribute("aria-busy", isBusy ? "true" : "false");
|
|
12118
|
+
}
|
|
12119
|
+
function refreshResultText() {
|
|
12120
|
+
switch (refreshResultState.type) {
|
|
12121
|
+
case "none":
|
|
12122
|
+
return "";
|
|
12123
|
+
case "added":
|
|
12124
|
+
return text2().history.refreshResultAdded(refreshResultState.count);
|
|
12125
|
+
case "unchanged":
|
|
12126
|
+
return text2().history.refreshResultUnchanged;
|
|
12127
|
+
default: {
|
|
12128
|
+
const exhaustive = refreshResultState;
|
|
12129
|
+
return exhaustive;
|
|
12130
|
+
}
|
|
12131
|
+
}
|
|
12132
|
+
}
|
|
12133
|
+
function syncRefreshResult() {
|
|
12134
|
+
const message = refreshResultText();
|
|
12135
|
+
refreshResult.textContent = message;
|
|
12136
|
+
refreshResult.hidden = message.length === 0;
|
|
12137
|
+
refreshResult.classList.toggle("changed", refreshResultState.type === "added");
|
|
12138
|
+
}
|
|
12139
|
+
function clearRefreshResult() {
|
|
12140
|
+
refreshResultState = { type: "none" };
|
|
12141
|
+
syncRefreshResult();
|
|
12142
|
+
}
|
|
12143
|
+
function setRefreshResult(previousEntries, nextEntries) {
|
|
12144
|
+
const previousIds = new Set(previousEntries.map((entry) => entry.id));
|
|
12145
|
+
const added = nextEntries.filter((entry) => !previousIds.has(entry.id)).length;
|
|
12146
|
+
refreshResultState = added > 0 ? { type: "added", count: added } : { type: "unchanged" };
|
|
12147
|
+
syncRefreshResult();
|
|
12148
|
+
}
|
|
12149
|
+
syncRefreshButtonLabel();
|
|
12150
|
+
setRefreshBusy(false);
|
|
12151
|
+
syncRefreshResult();
|
|
11897
12152
|
function currentRefreshParams() {
|
|
11898
12153
|
const dbId = callbacks.getDbId();
|
|
11899
12154
|
const schema = callbacks.getSchema();
|
|
@@ -11930,6 +12185,10 @@ ${frontmatter.yaml}
|
|
|
11930
12185
|
if (!options.force && refreshKey === lastRefreshKey && now - lastRefreshAt < 1000) {
|
|
11931
12186
|
return;
|
|
11932
12187
|
}
|
|
12188
|
+
const previousEntries = options.announceResult ? [...entries] : null;
|
|
12189
|
+
if (options.announceResult)
|
|
12190
|
+
clearRefreshResult();
|
|
12191
|
+
setRefreshBusy(true);
|
|
11933
12192
|
const promise = (async () => {
|
|
11934
12193
|
const res = await fetch(`/_db/history${params}`);
|
|
11935
12194
|
if (!res.ok)
|
|
@@ -11938,6 +12197,8 @@ ${frontmatter.yaml}
|
|
|
11938
12197
|
if (currentRefreshParams().key !== refreshKey)
|
|
11939
12198
|
return;
|
|
11940
12199
|
entries = state.entries;
|
|
12200
|
+
if (previousEntries)
|
|
12201
|
+
setRefreshResult(previousEntries, entries);
|
|
11941
12202
|
lastRefreshKey = refreshKey;
|
|
11942
12203
|
lastRefreshAt = Date.now();
|
|
11943
12204
|
if (selectedEntryId && !entries.some((entry) => entry.id === selectedEntryId)) {
|
|
@@ -11949,8 +12210,10 @@ ${frontmatter.yaml}
|
|
|
11949
12210
|
try {
|
|
11950
12211
|
await promise;
|
|
11951
12212
|
} finally {
|
|
11952
|
-
if (inFlightRefresh?.promise === promise)
|
|
12213
|
+
if (inFlightRefresh?.promise === promise) {
|
|
11953
12214
|
inFlightRefresh = null;
|
|
12215
|
+
setRefreshBusy(false);
|
|
12216
|
+
}
|
|
11954
12217
|
}
|
|
11955
12218
|
}
|
|
11956
12219
|
function render() {
|
|
@@ -11987,6 +12250,7 @@ ${frontmatter.yaml}
|
|
|
11987
12250
|
}
|
|
11988
12251
|
function renderDetail(entry) {
|
|
11989
12252
|
detailCol.innerHTML = "";
|
|
12253
|
+
const meta = renderEntryMeta(entry, "detail");
|
|
11990
12254
|
const actions = document.createElement("div");
|
|
11991
12255
|
actions.className = "db-query-history-detail-actions";
|
|
11992
12256
|
const useBtn = document.createElement("button");
|
|
@@ -12021,7 +12285,7 @@ ${frontmatter.yaml}
|
|
|
12021
12285
|
const sqlBlock = document.createElement("pre");
|
|
12022
12286
|
sqlBlock.className = "db-query-history-sql";
|
|
12023
12287
|
sqlBlock.textContent = entry.sql;
|
|
12024
|
-
detailCol.append(actions, sqlBlock);
|
|
12288
|
+
detailCol.append(meta, actions, sqlBlock);
|
|
12025
12289
|
if (entry.body) {
|
|
12026
12290
|
const bodyBlock = document.createElement("div");
|
|
12027
12291
|
bodyBlock.className = "db-query-history-body";
|
|
@@ -12047,26 +12311,30 @@ ${frontmatter.yaml}
|
|
|
12047
12311
|
}
|
|
12048
12312
|
item.dataset.id = entry.id;
|
|
12049
12313
|
entryRowsById.set(entry.id, item);
|
|
12314
|
+
const meta = renderEntryMeta(entry, "entry");
|
|
12315
|
+
const title = document.createElement("div");
|
|
12316
|
+
title.className = "db-query-history-entry-title";
|
|
12317
|
+
title.textContent = entry.title || (entry.sql.length > 80 ? `${entry.sql.slice(0, 80)}...` : entry.sql);
|
|
12318
|
+
item.append(meta, title);
|
|
12319
|
+
item.addEventListener("click", () => selectEntry(entry));
|
|
12320
|
+
return item;
|
|
12321
|
+
}
|
|
12322
|
+
function renderEntryMeta(entry, mode) {
|
|
12050
12323
|
const meta = document.createElement("div");
|
|
12051
|
-
meta.className = "db-query-history-entry-meta";
|
|
12324
|
+
meta.className = mode === "detail" ? "db-query-history-detail-meta" : "db-query-history-entry-meta";
|
|
12052
12325
|
const byIcon = document.createElement("span");
|
|
12053
12326
|
byIcon.className = "db-query-history-by";
|
|
12054
|
-
|
|
12327
|
+
const executor = entry.executedBy === "ai" ? text2().history.executorAi : text2().history.executorUser;
|
|
12328
|
+
byIcon.textContent = mode === "detail" ? executor : `[${executor}]`;
|
|
12055
12329
|
const time = document.createElement("span");
|
|
12056
12330
|
time.className = "db-query-history-time";
|
|
12057
12331
|
time.textContent = formatTime(entry.executedAt);
|
|
12058
12332
|
time.title = entry.executedAt;
|
|
12059
12333
|
const stats = document.createElement("span");
|
|
12060
12334
|
stats.className = "db-query-history-stats";
|
|
12061
|
-
|
|
12062
|
-
stats.textContent = `${entry.rowCount}${truncMark} rows, ${entry.elapsedMs}ms`;
|
|
12335
|
+
stats.textContent = `${text2().history.rowsLabel(entry.rowCount, entry.truncated)}, ${text2().history.elapsedLabel(entry.elapsedMs)}`;
|
|
12063
12336
|
meta.append(byIcon, time, stats);
|
|
12064
|
-
|
|
12065
|
-
title.className = "db-query-history-entry-title";
|
|
12066
|
-
title.textContent = entry.title || (entry.sql.length > 80 ? `${entry.sql.slice(0, 80)}...` : entry.sql);
|
|
12067
|
-
item.append(meta, title);
|
|
12068
|
-
item.addEventListener("click", () => selectEntry(entry));
|
|
12069
|
-
return item;
|
|
12337
|
+
return meta;
|
|
12070
12338
|
}
|
|
12071
12339
|
function renderPreviewTable(entry) {
|
|
12072
12340
|
const wrapper = document.createElement("div");
|
|
@@ -12175,17 +12443,19 @@ ${frontmatter.yaml}
|
|
|
12175
12443
|
body: JSON.stringify(dbId ? { db: dbId, ...schema ? { schema } : {} } : {})
|
|
12176
12444
|
});
|
|
12177
12445
|
entries = [];
|
|
12446
|
+
clearRefreshResult();
|
|
12178
12447
|
render();
|
|
12179
12448
|
} catch {}
|
|
12180
12449
|
});
|
|
12181
12450
|
refreshBtn.addEventListener("click", () => {
|
|
12182
|
-
refresh({ force: true });
|
|
12451
|
+
refresh({ force: true, announceResult: true });
|
|
12183
12452
|
});
|
|
12184
12453
|
function clear() {
|
|
12185
12454
|
entries = [];
|
|
12186
12455
|
expandedIds.clear();
|
|
12187
12456
|
lastRefreshKey = null;
|
|
12188
12457
|
lastRefreshAt = 0;
|
|
12458
|
+
clearRefreshResult();
|
|
12189
12459
|
if (clearConfirmTimer) {
|
|
12190
12460
|
clearTimeout(clearConfirmTimer);
|
|
12191
12461
|
clearConfirmTimer = null;
|
|
@@ -12196,8 +12466,8 @@ ${frontmatter.yaml}
|
|
|
12196
12466
|
render();
|
|
12197
12467
|
}
|
|
12198
12468
|
function localize() {
|
|
12199
|
-
|
|
12200
|
-
|
|
12469
|
+
syncRefreshButtonLabel();
|
|
12470
|
+
syncRefreshResult();
|
|
12201
12471
|
if (clearBtn.dataset.confirm !== "1") {
|
|
12202
12472
|
clearBtn.textContent = text2().history.clearAll;
|
|
12203
12473
|
}
|
|
@@ -14261,7 +14531,25 @@ ${frontmatter.yaml}
|
|
|
14261
14531
|
const el = document.createElement("div");
|
|
14262
14532
|
el.className = "db-schema-view";
|
|
14263
14533
|
el.hidden = true;
|
|
14534
|
+
let refreshBusy = false;
|
|
14535
|
+
let refreshBtn = null;
|
|
14536
|
+
let refreshLabel = null;
|
|
14264
14537
|
let lastArgs = null;
|
|
14538
|
+
function syncRefreshButton() {
|
|
14539
|
+
if (!refreshBtn || !refreshLabel)
|
|
14540
|
+
return;
|
|
14541
|
+
const t2 = text2().schema;
|
|
14542
|
+
refreshBtn.title = t2.refreshAction;
|
|
14543
|
+
refreshBtn.setAttribute("aria-label", t2.refreshAction);
|
|
14544
|
+
refreshBtn.setAttribute("aria-busy", refreshBusy ? "true" : "false");
|
|
14545
|
+
refreshBtn.disabled = refreshBusy;
|
|
14546
|
+
refreshBtn.classList.toggle("spinning", refreshBusy);
|
|
14547
|
+
refreshLabel.textContent = refreshBusy ? t2.refreshingLabel : t2.refreshLabel;
|
|
14548
|
+
}
|
|
14549
|
+
function setRefreshBusy(busy) {
|
|
14550
|
+
refreshBusy = busy;
|
|
14551
|
+
syncRefreshButton();
|
|
14552
|
+
}
|
|
14265
14553
|
function render(table2, columns, indexes, extra) {
|
|
14266
14554
|
lastArgs = { table: table2, columns, indexes, extra };
|
|
14267
14555
|
const t2 = text2().schema;
|
|
@@ -14269,7 +14557,29 @@ ${frontmatter.yaml}
|
|
|
14269
14557
|
el.innerHTML = "";
|
|
14270
14558
|
const header = document.createElement("div");
|
|
14271
14559
|
header.className = "db-schema-header";
|
|
14272
|
-
|
|
14560
|
+
const headerTitle = document.createElement("span");
|
|
14561
|
+
headerTitle.className = "db-schema-header-title";
|
|
14562
|
+
headerTitle.textContent = `Schema: ${table2}`;
|
|
14563
|
+
header.appendChild(headerTitle);
|
|
14564
|
+
if (deps.onRefresh) {
|
|
14565
|
+
refreshBtn = document.createElement("button");
|
|
14566
|
+
refreshBtn.type = "button";
|
|
14567
|
+
refreshBtn.className = "db-btn db-btn-icon db-grid-refresh db-schema-refresh";
|
|
14568
|
+
refreshBtn.innerHTML = iconSvg("octicon-sync", SYNC_16_PATH);
|
|
14569
|
+
refreshLabel = document.createElement("span");
|
|
14570
|
+
refreshLabel.className = "db-grid-refresh-label";
|
|
14571
|
+
refreshBtn.appendChild(refreshLabel);
|
|
14572
|
+
refreshBtn.addEventListener("click", () => {
|
|
14573
|
+
if (refreshBusy)
|
|
14574
|
+
return;
|
|
14575
|
+
deps.onRefresh?.();
|
|
14576
|
+
});
|
|
14577
|
+
header.appendChild(refreshBtn);
|
|
14578
|
+
syncRefreshButton();
|
|
14579
|
+
} else {
|
|
14580
|
+
refreshBtn = null;
|
|
14581
|
+
refreshLabel = null;
|
|
14582
|
+
}
|
|
14273
14583
|
el.appendChild(header);
|
|
14274
14584
|
const colSectionHeader = document.createElement("div");
|
|
14275
14585
|
colSectionHeader.className = "db-schema-section-header";
|
|
@@ -14432,13 +14742,16 @@ ${frontmatter.yaml}
|
|
|
14432
14742
|
el.hidden = true;
|
|
14433
14743
|
el.innerHTML = "";
|
|
14434
14744
|
lastArgs = null;
|
|
14745
|
+
refreshBtn = null;
|
|
14746
|
+
refreshLabel = null;
|
|
14747
|
+
refreshBusy = false;
|
|
14435
14748
|
}
|
|
14436
14749
|
function localize() {
|
|
14437
14750
|
if (!lastArgs || el.hidden)
|
|
14438
14751
|
return;
|
|
14439
14752
|
render(lastArgs.table, lastArgs.columns, lastArgs.indexes, lastArgs.extra);
|
|
14440
14753
|
}
|
|
14441
|
-
return { el, render, clear, localize };
|
|
14754
|
+
return { el, render, clear, localize, setRefreshBusy };
|
|
14442
14755
|
}
|
|
14443
14756
|
|
|
14444
14757
|
// web-src/views/database/session-log.ts
|
|
@@ -15866,7 +16179,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15866
16179
|
filterBar.className = "db-grid-filter-bar";
|
|
15867
16180
|
const filterIcon = document.createElement("span");
|
|
15868
16181
|
filterIcon.className = "db-grid-filter-icon";
|
|
15869
|
-
filterIcon.
|
|
16182
|
+
filterIcon.setAttribute("aria-hidden", "true");
|
|
16183
|
+
filterIcon.innerHTML = iconSvg("octicon-search", SEARCH_16_PATH);
|
|
15870
16184
|
const filterInput = document.createElement("input");
|
|
15871
16185
|
filterInput.type = "search";
|
|
15872
16186
|
filterInput.className = "db-grid-filter-input";
|
|
@@ -15874,9 +16188,24 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15874
16188
|
filterInput.autocomplete = "off";
|
|
15875
16189
|
const filterClear = document.createElement("button");
|
|
15876
16190
|
filterClear.type = "button";
|
|
15877
|
-
filterClear.className = "db-btn db-btn-
|
|
15878
|
-
filterClear.textContent =
|
|
16191
|
+
filterClear.className = "db-btn db-btn-sm db-grid-filter-clear";
|
|
16192
|
+
filterClear.textContent = text2().grid.clearFiltersLabel;
|
|
15879
16193
|
filterClear.hidden = true;
|
|
16194
|
+
const refreshBtn = document.createElement("button");
|
|
16195
|
+
refreshBtn.type = "button";
|
|
16196
|
+
refreshBtn.className = "db-btn db-btn-icon db-grid-refresh";
|
|
16197
|
+
refreshBtn.title = text2().grid.refreshAction;
|
|
16198
|
+
refreshBtn.setAttribute("aria-label", text2().grid.refreshAction);
|
|
16199
|
+
refreshBtn.setAttribute("aria-busy", "false");
|
|
16200
|
+
refreshBtn.innerHTML = iconSvg("octicon-sync", SYNC_16_PATH);
|
|
16201
|
+
const refreshLabel = document.createElement("span");
|
|
16202
|
+
refreshLabel.className = "db-grid-refresh-label";
|
|
16203
|
+
refreshLabel.textContent = text2().grid.refreshLabel;
|
|
16204
|
+
refreshBtn.appendChild(refreshLabel);
|
|
16205
|
+
const refreshResult = document.createElement("span");
|
|
16206
|
+
refreshResult.className = "db-refresh-result db-grid-refresh-result";
|
|
16207
|
+
refreshResult.setAttribute("aria-live", "polite");
|
|
16208
|
+
refreshResult.hidden = true;
|
|
15880
16209
|
const exportWrap = document.createElement("div");
|
|
15881
16210
|
exportWrap.className = "db-grid-export";
|
|
15882
16211
|
const exportBtn = document.createElement("button");
|
|
@@ -15884,7 +16213,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15884
16213
|
exportBtn.className = "db-btn db-btn-icon db-grid-export-toggle";
|
|
15885
16214
|
exportBtn.title = text2().grid.exportAction;
|
|
15886
16215
|
exportBtn.setAttribute("aria-label", text2().grid.exportAction);
|
|
15887
|
-
exportBtn.
|
|
16216
|
+
exportBtn.innerHTML = iconSvg("octicon-download", DOWNLOAD_16_PATHS);
|
|
15888
16217
|
const exportMenu = document.createElement("div");
|
|
15889
16218
|
exportMenu.className = "db-grid-export-menu";
|
|
15890
16219
|
exportMenu.hidden = true;
|
|
@@ -15944,7 +16273,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15944
16273
|
const editStatus = document.createElement("span");
|
|
15945
16274
|
editStatus.className = "db-grid-edit-status";
|
|
15946
16275
|
editWrap.append(newRowBtn, commitBtn, discardBtn, editStatus);
|
|
15947
|
-
|
|
16276
|
+
const filterActions = document.createElement("div");
|
|
16277
|
+
filterActions.className = "db-grid-filter-actions";
|
|
16278
|
+
filterActions.append(refreshBtn, refreshResult, exportWrap);
|
|
16279
|
+
filterBar.append(filterIcon, filterInput, filterClear, editWrap, filterActions);
|
|
15948
16280
|
const headerWrap = document.createElement("div");
|
|
15949
16281
|
headerWrap.className = "db-grid-header-wrap";
|
|
15950
16282
|
const headerRow = document.createElement("div");
|
|
@@ -15961,6 +16293,31 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15961
16293
|
spacer.className = "db-grid-spacer";
|
|
15962
16294
|
const body = document.createElement("div");
|
|
15963
16295
|
body.className = "db-grid-body";
|
|
16296
|
+
const filteredEmpty = document.createElement("div");
|
|
16297
|
+
filteredEmpty.className = "db-pane-empty";
|
|
16298
|
+
filteredEmpty.hidden = true;
|
|
16299
|
+
const filteredEmptyIcon = document.createElement("div");
|
|
16300
|
+
filteredEmptyIcon.className = "db-pane-empty-icon";
|
|
16301
|
+
filteredEmptyIcon.innerHTML = iconSvg("octicon-search", SEARCH_16_PATH);
|
|
16302
|
+
const filteredEmptyTitle = document.createElement("div");
|
|
16303
|
+
filteredEmptyTitle.className = "db-pane-empty-title";
|
|
16304
|
+
const filteredEmptyHint = document.createElement("div");
|
|
16305
|
+
filteredEmptyHint.className = "db-pane-empty-hint";
|
|
16306
|
+
const filteredEmptyActions = document.createElement("div");
|
|
16307
|
+
filteredEmptyActions.className = "db-pane-empty-actions";
|
|
16308
|
+
filteredEmptyActions.hidden = true;
|
|
16309
|
+
const filteredEmptyReloadAction = document.createElement("button");
|
|
16310
|
+
filteredEmptyReloadAction.type = "button";
|
|
16311
|
+
filteredEmptyReloadAction.className = "db-btn db-btn-primary db-btn-sm";
|
|
16312
|
+
filteredEmptyReloadAction.hidden = true;
|
|
16313
|
+
filteredEmptyReloadAction.disabled = true;
|
|
16314
|
+
const filteredEmptyAction = document.createElement("button");
|
|
16315
|
+
filteredEmptyAction.type = "button";
|
|
16316
|
+
filteredEmptyAction.className = "db-btn db-btn-sm";
|
|
16317
|
+
filteredEmptyAction.hidden = true;
|
|
16318
|
+
filteredEmptyAction.disabled = true;
|
|
16319
|
+
filteredEmptyActions.append(filteredEmptyReloadAction, filteredEmptyAction);
|
|
16320
|
+
filteredEmpty.append(filteredEmptyIcon, filteredEmptyTitle, filteredEmptyHint, filteredEmptyActions);
|
|
15964
16321
|
const detailPanel = document.createElement("div");
|
|
15965
16322
|
detailPanel.className = "db-grid-detail-panel";
|
|
15966
16323
|
detailPanel.hidden = true;
|
|
@@ -15968,7 +16325,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15968
16325
|
detailResize.className = "db-grid-detail-resize";
|
|
15969
16326
|
detailResize.addEventListener("mousedown", startDetailResize);
|
|
15970
16327
|
detailPanel.appendChild(detailResize);
|
|
15971
|
-
viewport.append(spacer, body);
|
|
16328
|
+
viewport.append(spacer, body, filteredEmpty);
|
|
15972
16329
|
el.append(filterBar, headerWrap, filterRowWrap, viewport, detailPanel);
|
|
15973
16330
|
function panelMaxHeight() {
|
|
15974
16331
|
const containerH = el.clientHeight || window.innerHeight;
|
|
@@ -16046,6 +16403,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16046
16403
|
let loadController = new AbortController;
|
|
16047
16404
|
let rafId = 0;
|
|
16048
16405
|
let statusEl = null;
|
|
16406
|
+
let isRefreshing = false;
|
|
16407
|
+
let refreshResultState = null;
|
|
16049
16408
|
let filterTimer = null;
|
|
16050
16409
|
let selectedRowIndex = -1;
|
|
16051
16410
|
let activeCellRowIndex = -1;
|
|
@@ -16140,19 +16499,109 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16140
16499
|
syncContentWidth();
|
|
16141
16500
|
renderViewport();
|
|
16142
16501
|
}
|
|
16143
|
-
function
|
|
16502
|
+
function collectColumnFilters() {
|
|
16144
16503
|
const filters = [];
|
|
16145
16504
|
for (const [col, val] of columnFilters) {
|
|
16146
16505
|
if (val)
|
|
16147
16506
|
filters.push({ column: col, value: val });
|
|
16148
16507
|
}
|
|
16149
|
-
|
|
16508
|
+
return filters;
|
|
16509
|
+
}
|
|
16510
|
+
function collectFilters() {
|
|
16511
|
+
const filters = collectColumnFilters();
|
|
16512
|
+
if (globalSearchValue) {
|
|
16150
16513
|
for (const col of columnNames) {
|
|
16151
|
-
filters.
|
|
16514
|
+
if (!filters.some((filter) => filter.column === col && filter.value === globalSearchValue)) {
|
|
16515
|
+
filters.push({ column: col, value: globalSearchValue });
|
|
16516
|
+
}
|
|
16152
16517
|
}
|
|
16153
16518
|
}
|
|
16154
16519
|
return filters;
|
|
16155
16520
|
}
|
|
16521
|
+
function activeFilterCount() {
|
|
16522
|
+
return columnFilters.size + (globalSearchValue ? 1 : 0);
|
|
16523
|
+
}
|
|
16524
|
+
function syncRefreshButton() {
|
|
16525
|
+
const count = activeFilterCount();
|
|
16526
|
+
const t2 = text2().grid;
|
|
16527
|
+
refreshLabel.textContent = isRefreshing ? t2.refreshingLabel : count > 0 ? t2.refreshFilteredLabel : t2.refreshLabel;
|
|
16528
|
+
const action = count > 0 ? t2.refreshActionWithFilters(count) : t2.refreshAction;
|
|
16529
|
+
refreshBtn.classList.toggle("has-filters", count > 0);
|
|
16530
|
+
refreshBtn.title = action;
|
|
16531
|
+
refreshBtn.setAttribute("aria-label", action);
|
|
16532
|
+
refreshBtn.setAttribute("aria-busy", isRefreshing ? "true" : "false");
|
|
16533
|
+
}
|
|
16534
|
+
function syncRefreshResult() {
|
|
16535
|
+
const result = refreshResultState;
|
|
16536
|
+
refreshResult.hidden = !result;
|
|
16537
|
+
refreshResult.classList.toggle("changed", !!result && result.delta !== 0);
|
|
16538
|
+
if (!result) {
|
|
16539
|
+
refreshResult.textContent = "";
|
|
16540
|
+
return;
|
|
16541
|
+
}
|
|
16542
|
+
const t2 = text2().grid;
|
|
16543
|
+
const total = result.totalRows.toLocaleString();
|
|
16544
|
+
refreshResult.textContent = result.delta === 0 ? t2.refreshResultUnchanged(total) : t2.refreshResultChanged(result.delta, total);
|
|
16545
|
+
}
|
|
16546
|
+
function clearRefreshResult() {
|
|
16547
|
+
refreshResultState = null;
|
|
16548
|
+
syncRefreshResult();
|
|
16549
|
+
}
|
|
16550
|
+
function setRefreshResult(previousTotalRows, nextTotalRows) {
|
|
16551
|
+
refreshResultState = {
|
|
16552
|
+
delta: nextTotalRows - previousTotalRows,
|
|
16553
|
+
totalRows: nextTotalRows
|
|
16554
|
+
};
|
|
16555
|
+
syncRefreshResult();
|
|
16556
|
+
}
|
|
16557
|
+
function syncFilterClearButton() {
|
|
16558
|
+
const count = activeFilterCount();
|
|
16559
|
+
const t2 = text2().grid;
|
|
16560
|
+
filterClear.hidden = count === 0;
|
|
16561
|
+
filterClear.textContent = t2.clearFiltersLabel;
|
|
16562
|
+
const action = t2.clearFiltersAction(count);
|
|
16563
|
+
filterClear.title = action;
|
|
16564
|
+
filterClear.setAttribute("aria-label", action);
|
|
16565
|
+
}
|
|
16566
|
+
function syncFilteredEmptyState() {
|
|
16567
|
+
const count = activeFilterCount();
|
|
16568
|
+
const show = totalRows === 0 && count > 0;
|
|
16569
|
+
filteredEmpty.hidden = !show;
|
|
16570
|
+
filteredEmptyActions.hidden = !show;
|
|
16571
|
+
filteredEmptyReloadAction.hidden = !show;
|
|
16572
|
+
filteredEmptyReloadAction.disabled = !show || isRefreshing;
|
|
16573
|
+
filteredEmptyAction.hidden = !show;
|
|
16574
|
+
filteredEmptyAction.disabled = !show;
|
|
16575
|
+
if (!show)
|
|
16576
|
+
return;
|
|
16577
|
+
const t2 = text2().grid;
|
|
16578
|
+
const reloadAction = t2.refreshActionWithFilters(count);
|
|
16579
|
+
filteredEmptyTitle.textContent = t2.filteredEmptyTitle(count);
|
|
16580
|
+
filteredEmptyHint.textContent = t2.filteredEmptyHint;
|
|
16581
|
+
filteredEmptyReloadAction.textContent = isRefreshing ? t2.refreshingLabel : t2.refreshFilteredLabel;
|
|
16582
|
+
filteredEmptyReloadAction.title = reloadAction;
|
|
16583
|
+
filteredEmptyReloadAction.setAttribute("aria-label", reloadAction);
|
|
16584
|
+
filteredEmptyReloadAction.setAttribute("aria-busy", isRefreshing ? "true" : "false");
|
|
16585
|
+
filteredEmptyAction.textContent = t2.filteredEmptyAction;
|
|
16586
|
+
filteredEmptyAction.title = t2.clearFiltersAction(count);
|
|
16587
|
+
filteredEmptyAction.setAttribute("aria-label", t2.clearFiltersAction(count));
|
|
16588
|
+
}
|
|
16589
|
+
function clearAllFilters() {
|
|
16590
|
+
globalSearchValue = "";
|
|
16591
|
+
filterInput.value = "";
|
|
16592
|
+
columnFilters.clear();
|
|
16593
|
+
clearRefreshResult();
|
|
16594
|
+
filterRow.querySelectorAll(".db-grid-col-filter").forEach((input) => {
|
|
16595
|
+
input.value = "";
|
|
16596
|
+
});
|
|
16597
|
+
syncFilterClearButton();
|
|
16598
|
+
syncRefreshButton();
|
|
16599
|
+
syncFilteredEmptyState();
|
|
16600
|
+
}
|
|
16601
|
+
function clearFiltersAndReload() {
|
|
16602
|
+
clearAllFilters();
|
|
16603
|
+
invalidateData();
|
|
16604
|
+
}
|
|
16156
16605
|
function resetSelectionAndDetail() {
|
|
16157
16606
|
selectedRowIndex = -1;
|
|
16158
16607
|
detailPanel.hidden = true;
|
|
@@ -16169,11 +16618,60 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16169
16618
|
function invalidateData() {
|
|
16170
16619
|
pageCache = new Map;
|
|
16171
16620
|
pendingPages = new Map;
|
|
16621
|
+
clearRefreshResult();
|
|
16172
16622
|
startNewLoadGeneration();
|
|
16173
16623
|
viewport.scrollTop = 0;
|
|
16174
16624
|
resetSelectionAndDetail();
|
|
16175
16625
|
return ensurePage(0);
|
|
16176
16626
|
}
|
|
16627
|
+
async function refreshCurrentTable() {
|
|
16628
|
+
if (!currentTable || refreshBtn.disabled)
|
|
16629
|
+
return;
|
|
16630
|
+
const refreshTable = currentTable;
|
|
16631
|
+
const previousTotalRows = totalRows;
|
|
16632
|
+
const refreshFilterKey = JSON.stringify(collectFilters());
|
|
16633
|
+
const scrollTop = viewport.scrollTop;
|
|
16634
|
+
const pageStart = Math.floor(scrollTop / ROW_HEIGHT / PAGE_SIZE) * PAGE_SIZE;
|
|
16635
|
+
refreshBtn.disabled = true;
|
|
16636
|
+
refreshBtn.classList.add("spinning");
|
|
16637
|
+
isRefreshing = true;
|
|
16638
|
+
clearRefreshResult();
|
|
16639
|
+
syncRefreshButton();
|
|
16640
|
+
syncFilteredEmptyState();
|
|
16641
|
+
updateStatus();
|
|
16642
|
+
if (filterTimer) {
|
|
16643
|
+
clearTimeout(filterTimer);
|
|
16644
|
+
filterTimer = null;
|
|
16645
|
+
}
|
|
16646
|
+
pageCache = new Map;
|
|
16647
|
+
pendingPages = new Map;
|
|
16648
|
+
startNewLoadGeneration();
|
|
16649
|
+
const refreshGeneration = loadGeneration;
|
|
16650
|
+
resetSelectionAndDetail();
|
|
16651
|
+
viewport.scrollTop = scrollTop;
|
|
16652
|
+
renderViewport();
|
|
16653
|
+
try {
|
|
16654
|
+
await ensurePage(pageStart);
|
|
16655
|
+
} finally {
|
|
16656
|
+
const endedInError = statusEl?.classList.contains("db-pane-error");
|
|
16657
|
+
isRefreshing = false;
|
|
16658
|
+
refreshBtn.classList.remove("spinning");
|
|
16659
|
+
refreshBtn.disabled = false;
|
|
16660
|
+
syncRefreshButton();
|
|
16661
|
+
syncFilteredEmptyState();
|
|
16662
|
+
if (!endedInError) {
|
|
16663
|
+
if (loadGeneration === refreshGeneration && JSON.stringify(collectFilters()) === refreshFilterKey) {
|
|
16664
|
+
setRefreshResult(previousTotalRows, totalRows);
|
|
16665
|
+
callbacks.onRefreshComplete?.({
|
|
16666
|
+
table: refreshTable,
|
|
16667
|
+
totalRows,
|
|
16668
|
+
filters: collectFilters()
|
|
16669
|
+
});
|
|
16670
|
+
}
|
|
16671
|
+
updateStatus();
|
|
16672
|
+
}
|
|
16673
|
+
}
|
|
16674
|
+
}
|
|
16177
16675
|
function clear() {
|
|
16178
16676
|
cleanupResize();
|
|
16179
16677
|
clearActiveCell();
|
|
@@ -16182,10 +16680,13 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16182
16680
|
columnNames = [];
|
|
16183
16681
|
totalRows = 0;
|
|
16184
16682
|
sort = null;
|
|
16683
|
+
isRefreshing = false;
|
|
16185
16684
|
columnFilters.clear();
|
|
16186
16685
|
globalSearchValue = "";
|
|
16686
|
+
clearRefreshResult();
|
|
16187
16687
|
filterInput.value = "";
|
|
16188
|
-
|
|
16688
|
+
syncFilterClearButton();
|
|
16689
|
+
syncRefreshButton();
|
|
16189
16690
|
filterRow.innerHTML = "";
|
|
16190
16691
|
pageCache = new Map;
|
|
16191
16692
|
pendingPages = new Map;
|
|
@@ -16278,7 +16779,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16278
16779
|
header.className = "db-related-header";
|
|
16279
16780
|
const title = document.createElement("span");
|
|
16280
16781
|
title.className = "db-related-title";
|
|
16281
|
-
title.
|
|
16782
|
+
title.setAttribute("aria-hidden", "true");
|
|
16783
|
+
title.innerHTML = iconSvg("octicon-link", LINK_16_PATH);
|
|
16282
16784
|
relatedCrumbEl = document.createElement("span");
|
|
16283
16785
|
relatedCrumbEl.className = "db-related-crumbs";
|
|
16284
16786
|
const copyBtn = document.createElement("button");
|
|
@@ -16582,7 +17084,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16582
17084
|
cell.classList.add("db-grid-header-fk");
|
|
16583
17085
|
const fkIcon = document.createElement("span");
|
|
16584
17086
|
fkIcon.className = "db-grid-header-fk-icon";
|
|
16585
|
-
fkIcon.
|
|
17087
|
+
fkIcon.innerHTML = iconSvg("octicon-link", LINK_16_PATH);
|
|
16586
17088
|
fkIcon.title = text2().grid.foreignKeyHint;
|
|
16587
17089
|
label.appendChild(fkIcon);
|
|
16588
17090
|
}
|
|
@@ -16668,6 +17170,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16668
17170
|
} else {
|
|
16669
17171
|
columnFilters.delete(col.name);
|
|
16670
17172
|
}
|
|
17173
|
+
clearRefreshResult();
|
|
17174
|
+
syncFilterClearButton();
|
|
17175
|
+
syncRefreshButton();
|
|
16671
17176
|
scheduleFilter();
|
|
16672
17177
|
});
|
|
16673
17178
|
input.addEventListener("keydown", (e2) => {
|
|
@@ -16676,6 +17181,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16676
17181
|
if (e2.key === "Escape") {
|
|
16677
17182
|
input.value = "";
|
|
16678
17183
|
columnFilters.delete(col.name);
|
|
17184
|
+
clearRefreshResult();
|
|
17185
|
+
syncFilterClearButton();
|
|
17186
|
+
syncRefreshButton();
|
|
16679
17187
|
scheduleFilter();
|
|
16680
17188
|
}
|
|
16681
17189
|
});
|
|
@@ -16687,6 +17195,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
16687
17195
|
if (filterTimer)
|
|
16688
17196
|
clearTimeout(filterTimer);
|
|
16689
17197
|
filterTimer = setTimeout(() => {
|
|
17198
|
+
filterTimer = null;
|
|
16690
17199
|
invalidateData();
|
|
16691
17200
|
}, FILTER_DEBOUNCE_MS);
|
|
16692
17201
|
}
|
|
@@ -17065,6 +17574,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17065
17574
|
for (let i2 = startRow;i2 < endRow; i2++) {
|
|
17066
17575
|
body.appendChild(i2 < totalRows ? buildDataRow(i2) : buildDraftRow(i2 - totalRows));
|
|
17067
17576
|
}
|
|
17577
|
+
syncFilteredEmptyState();
|
|
17068
17578
|
if (focusRestore) {
|
|
17069
17579
|
const next = body.querySelector(`.db-grid-cell-input[data-edit-row="${focusRestore.row}"][data-edit-col="${focusRestore.col}"]`);
|
|
17070
17580
|
if (next) {
|
|
@@ -17114,15 +17624,18 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17114
17624
|
const parts = [t2.statusRows(totalRows.toLocaleString())];
|
|
17115
17625
|
if (sort)
|
|
17116
17626
|
parts.push(t2.statusSort(sort.column, sort.direction.toUpperCase()));
|
|
17117
|
-
const
|
|
17118
|
-
if (
|
|
17119
|
-
parts.push(t2.statusFilters(
|
|
17627
|
+
const filterCount = activeFilterCount();
|
|
17628
|
+
if (filterCount > 0)
|
|
17629
|
+
parts.push(t2.statusFilters(filterCount));
|
|
17630
|
+
if (isRefreshing)
|
|
17631
|
+
parts.push(t2.statusRefreshing(filterCount));
|
|
17120
17632
|
const textNode = statusEl.firstChild;
|
|
17121
17633
|
if (textNode && textNode.nodeType === Node.TEXT_NODE) {
|
|
17122
17634
|
textNode.textContent = `${parts.join(" | ")} `;
|
|
17123
17635
|
} else {
|
|
17124
17636
|
statusEl.insertBefore(document.createTextNode(`${parts.join(" | ")} `), statusEl.firstChild);
|
|
17125
17637
|
}
|
|
17638
|
+
syncRefreshResult();
|
|
17126
17639
|
}
|
|
17127
17640
|
function showError(message) {
|
|
17128
17641
|
clear();
|
|
@@ -17161,13 +17674,14 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17161
17674
|
if (state.search !== undefined) {
|
|
17162
17675
|
globalSearchValue = state.search;
|
|
17163
17676
|
filterInput.value = state.search;
|
|
17164
|
-
filterClear.hidden = !globalSearchValue;
|
|
17165
17677
|
}
|
|
17166
17678
|
columnFilters.clear();
|
|
17167
17679
|
for (const filter of state.filters || []) {
|
|
17168
17680
|
if (filter.column && filter.value)
|
|
17169
17681
|
columnFilters.set(filter.column, filter.value);
|
|
17170
17682
|
}
|
|
17683
|
+
syncFilterClearButton();
|
|
17684
|
+
syncRefreshButton();
|
|
17171
17685
|
sort = state.sort || null;
|
|
17172
17686
|
const targetRowIndex = state.row && state.row > 0 ? state.row - 1 : -1;
|
|
17173
17687
|
renderHeader();
|
|
@@ -17180,7 +17694,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17180
17694
|
}
|
|
17181
17695
|
}
|
|
17182
17696
|
function getState() {
|
|
17183
|
-
const filters =
|
|
17697
|
+
const filters = collectColumnFilters();
|
|
17184
17698
|
return {
|
|
17185
17699
|
...globalSearchValue ? { search: globalSearchValue } : {},
|
|
17186
17700
|
...filters.length ? { filters } : {},
|
|
@@ -17190,7 +17704,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17190
17704
|
}
|
|
17191
17705
|
filterInput.addEventListener("input", () => {
|
|
17192
17706
|
globalSearchValue = filterInput.value.trim();
|
|
17193
|
-
|
|
17707
|
+
clearRefreshResult();
|
|
17708
|
+
syncFilterClearButton();
|
|
17709
|
+
syncRefreshButton();
|
|
17194
17710
|
scheduleFilter();
|
|
17195
17711
|
});
|
|
17196
17712
|
filterInput.addEventListener("keydown", (e2) => {
|
|
@@ -17199,15 +17715,24 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17199
17715
|
if (e2.key === "Escape") {
|
|
17200
17716
|
filterInput.value = "";
|
|
17201
17717
|
globalSearchValue = "";
|
|
17202
|
-
|
|
17718
|
+
clearRefreshResult();
|
|
17719
|
+
syncFilterClearButton();
|
|
17720
|
+
syncRefreshButton();
|
|
17203
17721
|
scheduleFilter();
|
|
17204
17722
|
}
|
|
17205
17723
|
});
|
|
17206
17724
|
filterClear.addEventListener("click", () => {
|
|
17207
|
-
|
|
17208
|
-
|
|
17209
|
-
|
|
17210
|
-
|
|
17725
|
+
clearFiltersAndReload();
|
|
17726
|
+
});
|
|
17727
|
+
filteredEmptyAction.addEventListener("click", () => {
|
|
17728
|
+
clearFiltersAndReload();
|
|
17729
|
+
filterInput.focus?.();
|
|
17730
|
+
});
|
|
17731
|
+
filteredEmptyReloadAction.addEventListener("click", () => {
|
|
17732
|
+
refreshCurrentTable();
|
|
17733
|
+
});
|
|
17734
|
+
refreshBtn.addEventListener("click", () => {
|
|
17735
|
+
refreshCurrentTable();
|
|
17211
17736
|
});
|
|
17212
17737
|
const onViewportScroll = () => {
|
|
17213
17738
|
headerWrap.scrollLeft = viewport.scrollLeft;
|
|
@@ -17236,6 +17761,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17236
17761
|
function localize() {
|
|
17237
17762
|
const t2 = text2();
|
|
17238
17763
|
filterInput.placeholder = t2.grid.searchPlaceholder;
|
|
17764
|
+
syncFilterClearButton();
|
|
17765
|
+
syncRefreshButton();
|
|
17766
|
+
syncRefreshResult();
|
|
17767
|
+
syncFilteredEmptyState();
|
|
17239
17768
|
exportBtn.title = t2.grid.exportAction;
|
|
17240
17769
|
exportBtn.setAttribute("aria-label", t2.grid.exportAction);
|
|
17241
17770
|
newRowBtn.textContent = t2.edit.newRow;
|
|
@@ -17517,6 +18046,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17517
18046
|
return {
|
|
17518
18047
|
el,
|
|
17519
18048
|
load,
|
|
18049
|
+
refresh: refreshCurrentTable,
|
|
17520
18050
|
showError,
|
|
17521
18051
|
applyState,
|
|
17522
18052
|
getState,
|
|
@@ -17575,7 +18105,14 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17575
18105
|
filterInput.className = "db-table-filter";
|
|
17576
18106
|
filterInput.type = "text";
|
|
17577
18107
|
filterInput.placeholder = "Filter tables...";
|
|
17578
|
-
|
|
18108
|
+
const filterClear = document.createElement("button");
|
|
18109
|
+
filterClear.className = "db-table-filter-clear";
|
|
18110
|
+
filterClear.type = "button";
|
|
18111
|
+
filterClear.title = "Clear table filter";
|
|
18112
|
+
filterClear.setAttribute("aria-label", "Clear table filter");
|
|
18113
|
+
filterClear.innerHTML = iconSvg("octicon-x", X_16_PATH);
|
|
18114
|
+
filterClear.hidden = true;
|
|
18115
|
+
filterWrap.append(filterInput, filterClear);
|
|
17579
18116
|
const el = document.createElement("div");
|
|
17580
18117
|
el.className = "db-table-list";
|
|
17581
18118
|
wrapper.append(filterWrap, el);
|
|
@@ -17735,13 +18272,37 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17735
18272
|
}
|
|
17736
18273
|
}
|
|
17737
18274
|
}
|
|
18275
|
+
function syncFilterClearButton() {
|
|
18276
|
+
filterClear.hidden = filterInput.value.length === 0;
|
|
18277
|
+
}
|
|
18278
|
+
function clearFilter() {
|
|
18279
|
+
if (!filterInput.value)
|
|
18280
|
+
return;
|
|
18281
|
+
filterInput.value = "";
|
|
18282
|
+
renderFiltered(allTables, "");
|
|
18283
|
+
filterInput.focus();
|
|
18284
|
+
}
|
|
17738
18285
|
function renderFiltered(tables, filter) {
|
|
17739
18286
|
el.innerHTML = "";
|
|
18287
|
+
syncFilterClearButton();
|
|
17740
18288
|
const filtered = filter ? tables.filter((t2) => t2.name.toLowerCase().includes(filter.toLowerCase())) : tables;
|
|
17741
18289
|
if (filtered.length === 0) {
|
|
17742
18290
|
const empty = document.createElement("div");
|
|
17743
18291
|
empty.className = "db-table-list-empty";
|
|
17744
18292
|
empty.textContent = filter ? "No matching tables" : "No tables found";
|
|
18293
|
+
if (filter) {
|
|
18294
|
+
const actions = document.createElement("div");
|
|
18295
|
+
actions.className = "db-pane-empty-actions db-table-list-empty-actions";
|
|
18296
|
+
const clear = document.createElement("button");
|
|
18297
|
+
clear.type = "button";
|
|
18298
|
+
clear.className = "db-btn db-btn-sm";
|
|
18299
|
+
clear.textContent = "Clear filter";
|
|
18300
|
+
clear.title = "Clear table filter";
|
|
18301
|
+
clear.setAttribute("aria-label", "Clear table filter");
|
|
18302
|
+
clear.addEventListener("click", clearFilter);
|
|
18303
|
+
actions.appendChild(clear);
|
|
18304
|
+
empty.appendChild(actions);
|
|
18305
|
+
}
|
|
17745
18306
|
el.appendChild(empty);
|
|
17746
18307
|
return;
|
|
17747
18308
|
}
|
|
@@ -17811,23 +18372,37 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17811
18372
|
filterInput.value = "";
|
|
17812
18373
|
renderFiltered(tables, "");
|
|
17813
18374
|
}
|
|
17814
|
-
|
|
18375
|
+
function handleFilterInput() {
|
|
17815
18376
|
renderFiltered(allTables, filterInput.value);
|
|
17816
|
-
}
|
|
18377
|
+
}
|
|
18378
|
+
filterInput.addEventListener("input", handleFilterInput);
|
|
18379
|
+
filterClear.addEventListener("click", clearFilter);
|
|
17817
18380
|
function setActive(table2) {
|
|
17818
18381
|
activeTable = table2;
|
|
17819
18382
|
el.querySelectorAll(".db-table-item").forEach((item) => {
|
|
17820
18383
|
item.classList.toggle("active", item.dataset.table === table2);
|
|
17821
18384
|
});
|
|
17822
18385
|
}
|
|
18386
|
+
function updateRowCount(table2, rowCount) {
|
|
18387
|
+
allTables = allTables.map((entry) => entry.name === table2 ? { ...entry, rowCount } : entry);
|
|
18388
|
+
for (const node of el.querySelectorAll(".db-table-node")) {
|
|
18389
|
+
if (node.dataset.table !== table2)
|
|
18390
|
+
continue;
|
|
18391
|
+
const count = node.querySelector(".db-table-count");
|
|
18392
|
+
if (count)
|
|
18393
|
+
count.textContent = rowCount != null ? formatRowCount(rowCount) : "";
|
|
18394
|
+
}
|
|
18395
|
+
}
|
|
17823
18396
|
function dispose() {
|
|
17824
18397
|
closeContextMenu();
|
|
17825
18398
|
allTables = [];
|
|
17826
18399
|
expandedTables.clear();
|
|
17827
18400
|
columnCache.clear();
|
|
17828
18401
|
activeTable = null;
|
|
18402
|
+
filterInput.removeEventListener("input", handleFilterInput);
|
|
18403
|
+
filterClear.removeEventListener("click", clearFilter);
|
|
17829
18404
|
}
|
|
17830
|
-
return { el: wrapper, render, setActive, dispose };
|
|
18405
|
+
return { el: wrapper, render, setActive, updateRowCount, dispose };
|
|
17831
18406
|
}
|
|
17832
18407
|
function formatRowCount(n2) {
|
|
17833
18408
|
if (n2 >= 1e6)
|
|
@@ -17981,11 +18556,14 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17981
18556
|
return value;
|
|
17982
18557
|
}
|
|
17983
18558
|
let lastFiles = [];
|
|
18559
|
+
let noDatastoresAvailable = false;
|
|
17984
18560
|
let currentSchema = initial.schema ?? null;
|
|
17985
18561
|
let currentTable = initial.table ?? null;
|
|
17986
18562
|
let loadGeneration = 0;
|
|
17987
18563
|
const tableSelectGuard = createAbortGuard();
|
|
17988
18564
|
let historyRefreshPending = null;
|
|
18565
|
+
let isRefreshingDatastores = false;
|
|
18566
|
+
let datastoreRefreshResult = null;
|
|
17989
18567
|
const dbSelect = document.createElement("select");
|
|
17990
18568
|
dbSelect.className = "db-file-select";
|
|
17991
18569
|
reloc(() => {
|
|
@@ -17997,9 +18575,29 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
17997
18575
|
reloc(() => {
|
|
17998
18576
|
schemaSelect.title = paneText().nav.selectSchema;
|
|
17999
18577
|
});
|
|
18578
|
+
const dbRefreshBtn = makeIconButton({
|
|
18579
|
+
label: paneText().nav.refreshDatastores,
|
|
18580
|
+
title: paneText().nav.refreshDatastoresTitle,
|
|
18581
|
+
pathD: SYNC_16_PATH,
|
|
18582
|
+
onClick: () => {
|
|
18583
|
+
refreshDatastoreList();
|
|
18584
|
+
}
|
|
18585
|
+
});
|
|
18586
|
+
dbRefreshBtn.classList.add("db-refresh-btn");
|
|
18587
|
+
const dbRefreshLabel = document.createElement("span");
|
|
18588
|
+
dbRefreshLabel.className = "db-refresh-label";
|
|
18589
|
+
dbRefreshBtn.appendChild(dbRefreshLabel);
|
|
18590
|
+
const dbRefreshResult = document.createElement("span");
|
|
18591
|
+
dbRefreshResult.className = "db-refresh-result";
|
|
18592
|
+
dbRefreshResult.hidden = true;
|
|
18593
|
+
dbRefreshResult.setAttribute("aria-live", "polite");
|
|
18594
|
+
syncDbRefreshButton();
|
|
18595
|
+
const dbSelectRow = document.createElement("div");
|
|
18596
|
+
dbSelectRow.className = "db-select-row";
|
|
18597
|
+
dbSelectRow.append(dbSelect, dbRefreshBtn, dbRefreshResult);
|
|
18000
18598
|
const dbToolbar = document.createElement("div");
|
|
18001
18599
|
dbToolbar.className = "db-toolbar";
|
|
18002
|
-
dbToolbar.append(
|
|
18600
|
+
dbToolbar.append(dbSelectRow, schemaSelect);
|
|
18003
18601
|
const tabBar = document.createElement("div");
|
|
18004
18602
|
tabBar.className = "db-tab-bar";
|
|
18005
18603
|
const tabData = createInnerTab("Data", true);
|
|
@@ -18073,7 +18671,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18073
18671
|
const searchBtn = makeIconButton({
|
|
18074
18672
|
label: "Search",
|
|
18075
18673
|
title: "Search across tables",
|
|
18076
|
-
pathD:
|
|
18674
|
+
pathD: SEARCH_16_PATH,
|
|
18077
18675
|
onClick: () => setActiveTab("search")
|
|
18078
18676
|
});
|
|
18079
18677
|
const snapshotBtn = makeIconButton({
|
|
@@ -18091,6 +18689,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18091
18689
|
});
|
|
18092
18690
|
reloc(() => {
|
|
18093
18691
|
const t2 = paneText().nav;
|
|
18692
|
+
localizeIconButton(dbRefreshBtn, t2.refreshDatastores, t2.refreshDatastoresTitle);
|
|
18693
|
+
syncDbRefreshButton();
|
|
18094
18694
|
localizeIconButton(queryBtn, t2.query, t2.queryTitle);
|
|
18095
18695
|
localizeIconButton(erBtn, t2.er, t2.erTitle);
|
|
18096
18696
|
localizeIconButton(searchBtn, t2.search, t2.searchTitle);
|
|
@@ -18145,7 +18745,13 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18145
18745
|
},
|
|
18146
18746
|
getText: () => paneText(),
|
|
18147
18747
|
getEditable: () => isSqlKind(currentDbInfo?.kind),
|
|
18148
|
-
applyMutations: (mutations) => applyRowMutations(mutations)
|
|
18748
|
+
applyMutations: (mutations) => applyRowMutations(mutations),
|
|
18749
|
+
onRefreshComplete: ({ table: table2, filters }) => {
|
|
18750
|
+
if (filters.length === 0) {
|
|
18751
|
+
return;
|
|
18752
|
+
}
|
|
18753
|
+
refreshTableRowCount(table2);
|
|
18754
|
+
}
|
|
18149
18755
|
});
|
|
18150
18756
|
const editModeToggle = makePrefToggle({
|
|
18151
18757
|
title: paneText().edit.editModeTitle,
|
|
@@ -18177,7 +18783,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18177
18783
|
});
|
|
18178
18784
|
if (initial.sqlDraft)
|
|
18179
18785
|
queryEditor.setSql(initial.sqlDraft, { silent: true });
|
|
18180
|
-
const schemaView = createSchemaView({
|
|
18786
|
+
const schemaView = createSchemaView({
|
|
18787
|
+
getText: () => paneText(),
|
|
18788
|
+
onRefresh: () => refreshCurrentSchemaView()
|
|
18789
|
+
});
|
|
18181
18790
|
const erDiagram = createErDiagram({ getText: () => paneText() });
|
|
18182
18791
|
const globalSearchView = createGlobalSearchView({
|
|
18183
18792
|
getDbId: () => currentDbInfo?.id || null,
|
|
@@ -18268,9 +18877,30 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18268
18877
|
s3Explorer.el.hidden = true;
|
|
18269
18878
|
s3Explorer.sidebarSlot.hidden = true;
|
|
18270
18879
|
explorerSidebarHost.append(redisExplorer.sidebarSlot, esExplorer.sidebarSlot, s3Explorer.sidebarSlot);
|
|
18880
|
+
const noDatastoresPane = document.createElement("div");
|
|
18881
|
+
noDatastoresPane.className = "db-no-datastores";
|
|
18882
|
+
noDatastoresPane.hidden = true;
|
|
18883
|
+
function renderNoDatastoresEmpty() {
|
|
18884
|
+
const t2 = paneText().nav;
|
|
18885
|
+
setPaneEmpty(noDatastoresPane, t2.noDatastores, {
|
|
18886
|
+
hint: t2.noDatastoresHint,
|
|
18887
|
+
iconPath: ICON_PATH_SNAPSHOT
|
|
18888
|
+
});
|
|
18889
|
+
const actionRow = document.createElement("div");
|
|
18890
|
+
actionRow.className = "db-no-datastores-actions";
|
|
18891
|
+
const refresh = document.createElement("button");
|
|
18892
|
+
refresh.type = "button";
|
|
18893
|
+
refresh.className = "db-btn db-btn-primary db-no-datastores-action";
|
|
18894
|
+
refresh.textContent = t2.refreshDatastores;
|
|
18895
|
+
refresh.addEventListener("click", () => {
|
|
18896
|
+
refreshDatastoreList();
|
|
18897
|
+
});
|
|
18898
|
+
actionRow.appendChild(refresh);
|
|
18899
|
+
noDatastoresPane.querySelector(".db-pane-empty")?.appendChild(actionRow);
|
|
18900
|
+
}
|
|
18271
18901
|
const mainContent = document.createElement("div");
|
|
18272
18902
|
mainContent.className = "db-main-content";
|
|
18273
|
-
mainContent.append(tabBar, grid.el, queryEditor.el, schemaView.el, erDiagram.el, globalSearchView.el, snapshotView.el, redisExplorer.el, esExplorer.el, s3Explorer.el);
|
|
18903
|
+
mainContent.append(tabBar, grid.el, queryEditor.el, schemaView.el, erDiagram.el, globalSearchView.el, snapshotView.el, redisExplorer.el, esExplorer.el, s3Explorer.el, noDatastoresPane);
|
|
18274
18904
|
queryEditor.el.hidden = true;
|
|
18275
18905
|
globalSearchView.el.hidden = true;
|
|
18276
18906
|
snapshotView.el.hidden = true;
|
|
@@ -18381,6 +19011,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18381
19011
|
function applyVisibility() {
|
|
18382
19012
|
const sqlMode = isSqlKind(currentDbInfo?.kind);
|
|
18383
19013
|
const visibility = computeVisibility(currentDbInfo?.kind, currentTab, userPrefersHistoryOpen);
|
|
19014
|
+
noDatastoresPane.hidden = !noDatastoresAvailable;
|
|
18384
19015
|
toolsSection.hidden = visibility.toolsHidden;
|
|
18385
19016
|
prefsBar.hidden = visibility.toolsHidden;
|
|
18386
19017
|
historyDock.hidden = visibility.historyTabStripHidden;
|
|
@@ -18401,6 +19032,28 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18401
19032
|
esExplorer.sidebarSlot.hidden = visibility.esHidden;
|
|
18402
19033
|
s3Explorer.sidebarSlot.hidden = visibility.s3Hidden;
|
|
18403
19034
|
explorerSidebarHost.hidden = visibility.redisHidden && visibility.esHidden && visibility.s3Hidden;
|
|
19035
|
+
if (noDatastoresAvailable) {
|
|
19036
|
+
toolsSection.hidden = true;
|
|
19037
|
+
prefsBar.hidden = true;
|
|
19038
|
+
historyDock.hidden = true;
|
|
19039
|
+
historyResizer.hidden = true;
|
|
19040
|
+
historyPane.hidden = true;
|
|
19041
|
+
tableList.el.hidden = true;
|
|
19042
|
+
tabBar.hidden = true;
|
|
19043
|
+
grid.el.hidden = true;
|
|
19044
|
+
queryEditor.el.hidden = true;
|
|
19045
|
+
schemaView.el.hidden = true;
|
|
19046
|
+
erDiagram.el.hidden = true;
|
|
19047
|
+
globalSearchView.el.hidden = true;
|
|
19048
|
+
snapshotView.el.hidden = true;
|
|
19049
|
+
redisExplorer.el.hidden = true;
|
|
19050
|
+
esExplorer.el.hidden = true;
|
|
19051
|
+
s3Explorer.el.hidden = true;
|
|
19052
|
+
redisExplorer.sidebarSlot.hidden = true;
|
|
19053
|
+
esExplorer.sidebarSlot.hidden = true;
|
|
19054
|
+
s3Explorer.sidebarSlot.hidden = true;
|
|
19055
|
+
explorerSidebarHost.hidden = true;
|
|
19056
|
+
}
|
|
18404
19057
|
if (!sqlMode) {
|
|
18405
19058
|
queryBtn.classList.remove("active");
|
|
18406
19059
|
erBtn.classList.remove("active");
|
|
@@ -18551,11 +19204,59 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18551
19204
|
errorPrefix: "failed to fetch schema"
|
|
18552
19205
|
});
|
|
18553
19206
|
}
|
|
19207
|
+
function syncCachedTableRowCount(table2, rowCount) {
|
|
19208
|
+
if (!schemaCache)
|
|
19209
|
+
return;
|
|
19210
|
+
let changed = false;
|
|
19211
|
+
const tables = schemaCache.tables.map((entry) => {
|
|
19212
|
+
if (entry.name !== table2 || entry.rowCount === rowCount)
|
|
19213
|
+
return entry;
|
|
19214
|
+
changed = true;
|
|
19215
|
+
return { ...entry, rowCount };
|
|
19216
|
+
});
|
|
19217
|
+
if (!changed)
|
|
19218
|
+
return;
|
|
19219
|
+
schemaCache = { ...schemaCache, tables };
|
|
19220
|
+
tableList.updateRowCount(table2, rowCount);
|
|
19221
|
+
}
|
|
19222
|
+
async function fetchTableRowCount(table2, dbId, schema) {
|
|
19223
|
+
const params = new URLSearchParams({ db: dbId, table: table2 });
|
|
19224
|
+
if (schema)
|
|
19225
|
+
params.set("schema", schema);
|
|
19226
|
+
return logSqlFetch({
|
|
19227
|
+
url: `/_db/table-count?${params}`,
|
|
19228
|
+
kind: "query",
|
|
19229
|
+
label: `_db/table-count ${table2}`,
|
|
19230
|
+
errorPrefix: "failed to fetch table count",
|
|
19231
|
+
rowCountOf: (r2) => r2.rowCount ?? undefined
|
|
19232
|
+
});
|
|
19233
|
+
}
|
|
19234
|
+
async function refreshTableRowCount(table2) {
|
|
19235
|
+
const dbId = currentDbInfo?.id;
|
|
19236
|
+
if (!dbId)
|
|
19237
|
+
return;
|
|
19238
|
+
const schema = currentSchema;
|
|
19239
|
+
const generation = loadGeneration;
|
|
19240
|
+
try {
|
|
19241
|
+
const data = await fetchTableRowCount(table2, dbId, schema);
|
|
19242
|
+
if (generation !== loadGeneration || currentDbInfo?.id !== dbId || currentSchema !== schema || currentTable !== table2) {
|
|
19243
|
+
return;
|
|
19244
|
+
}
|
|
19245
|
+
syncCachedTableRowCount(table2, data.rowCount);
|
|
19246
|
+
} catch (err) {
|
|
19247
|
+
if (!isAbortError2(err)) {
|
|
19248
|
+
console.warn(`failed to refresh table count: ${errorMessage(err)}`);
|
|
19249
|
+
}
|
|
19250
|
+
}
|
|
19251
|
+
}
|
|
18554
19252
|
async function fetchTablePage(table2, offset, limit, sort, filters, signal, eq = []) {
|
|
18555
19253
|
if (!currentDbInfo)
|
|
18556
19254
|
throw new Error("no database selected");
|
|
19255
|
+
const requestDbId = currentDbInfo.id;
|
|
19256
|
+
const requestSchema = currentSchema;
|
|
19257
|
+
const requestGeneration = loadGeneration;
|
|
18557
19258
|
const params = new URLSearchParams({
|
|
18558
|
-
db:
|
|
19259
|
+
db: requestDbId,
|
|
18559
19260
|
table: table2,
|
|
18560
19261
|
offset: String(offset),
|
|
18561
19262
|
limit: String(limit)
|
|
@@ -18571,7 +19272,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18571
19272
|
if (eq.length > 0) {
|
|
18572
19273
|
params.set("eq", JSON.stringify(eq));
|
|
18573
19274
|
}
|
|
18574
|
-
|
|
19275
|
+
const data = await logSqlFetch({
|
|
18575
19276
|
url: `/_db/table?${params}`,
|
|
18576
19277
|
init: signal ? { signal } : undefined,
|
|
18577
19278
|
kind: "query",
|
|
@@ -18580,6 +19281,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18580
19281
|
errorPrefix: "failed to fetch table",
|
|
18581
19282
|
rowCountOf: (r2) => r2.rows.length
|
|
18582
19283
|
});
|
|
19284
|
+
if (filters.length === 0 && eq.length === 0 && currentDbInfo?.id === requestDbId && currentSchema === requestSchema && currentTable === table2 && requestGeneration === loadGeneration) {
|
|
19285
|
+
syncCachedTableRowCount(table2, data.totalRows);
|
|
19286
|
+
}
|
|
19287
|
+
return data;
|
|
18583
19288
|
}
|
|
18584
19289
|
function fetchRelatedPage(table2, offset, limit, sort, filters, eq, signal) {
|
|
18585
19290
|
return fetchTablePage(table2, offset, limit, sort, filters, signal, eq);
|
|
@@ -18891,6 +19596,47 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18891
19596
|
const columns = await fetchColumns(table2);
|
|
18892
19597
|
schemaView.render(table2, columns, schemaCache?.indexes || []);
|
|
18893
19598
|
}
|
|
19599
|
+
async function refreshCurrentSchemaView() {
|
|
19600
|
+
if (!currentDbInfo || !currentTable)
|
|
19601
|
+
return;
|
|
19602
|
+
const generation = loadGeneration;
|
|
19603
|
+
const dbId = currentDbInfo.id;
|
|
19604
|
+
const table2 = currentTable;
|
|
19605
|
+
schemaView.setRefreshBusy(true);
|
|
19606
|
+
try {
|
|
19607
|
+
const schema = await fetchSchema(dbId);
|
|
19608
|
+
if (generation !== loadGeneration || currentDbInfo?.id !== dbId || currentTable !== table2) {
|
|
19609
|
+
return;
|
|
19610
|
+
}
|
|
19611
|
+
currentSchema = schema.schema || currentSchema;
|
|
19612
|
+
schemaCache = schema;
|
|
19613
|
+
tableList.render(schema.tables);
|
|
19614
|
+
const nextTable = schema.tables.some((entry) => entry.name === table2) ? table2 : schema.tables[0]?.name;
|
|
19615
|
+
if (!nextTable) {
|
|
19616
|
+
currentTable = null;
|
|
19617
|
+
grid.clear();
|
|
19618
|
+
schemaView.clear();
|
|
19619
|
+
erDiagram.clear();
|
|
19620
|
+
cb.onStateChange();
|
|
19621
|
+
return;
|
|
19622
|
+
}
|
|
19623
|
+
currentTable = nextTable;
|
|
19624
|
+
tableList.setActive(nextTable);
|
|
19625
|
+
const columns = await fetchColumns(nextTable);
|
|
19626
|
+
if (generation !== loadGeneration || currentDbInfo?.id !== dbId || currentTable !== nextTable) {
|
|
19627
|
+
return;
|
|
19628
|
+
}
|
|
19629
|
+
schemaView.render(nextTable, columns, schema.indexes || []);
|
|
19630
|
+
cb.onStateChange();
|
|
19631
|
+
} catch (err) {
|
|
19632
|
+
if (generation !== loadGeneration || currentDbInfo?.id !== dbId || isAbortError2(err)) {
|
|
19633
|
+
return;
|
|
19634
|
+
}
|
|
19635
|
+
setTableListStatus(errorMessage(err), { error: true });
|
|
19636
|
+
} finally {
|
|
19637
|
+
schemaView.setRefreshBusy(false);
|
|
19638
|
+
}
|
|
19639
|
+
}
|
|
18894
19640
|
async function showDdl(table2) {
|
|
18895
19641
|
if (!currentDbInfo)
|
|
18896
19642
|
return;
|
|
@@ -18935,6 +19681,54 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18935
19681
|
schemaSelect.addEventListener("change", () => {
|
|
18936
19682
|
handleSchemaSelectChange();
|
|
18937
19683
|
});
|
|
19684
|
+
function syncDbRefreshButton() {
|
|
19685
|
+
const text2 = paneText().nav;
|
|
19686
|
+
dbRefreshLabel.textContent = isRefreshingDatastores ? text2.refreshDatastoresBusy : text2.refreshDatastoresShort;
|
|
19687
|
+
dbRefreshBtn.setAttribute("aria-busy", isRefreshingDatastores ? "true" : "false");
|
|
19688
|
+
syncDatastoreRefreshResult();
|
|
19689
|
+
}
|
|
19690
|
+
function syncDatastoreRefreshResult() {
|
|
19691
|
+
const result = datastoreRefreshResult;
|
|
19692
|
+
dbRefreshResult.hidden = !result;
|
|
19693
|
+
dbRefreshResult.classList.toggle("changed", !!result && (result.added > 0 || result.removed > 0));
|
|
19694
|
+
if (!result)
|
|
19695
|
+
return;
|
|
19696
|
+
const text2 = paneText().nav;
|
|
19697
|
+
dbRefreshResult.textContent = result.added > 0 || result.removed > 0 ? text2.refreshDatastoresChanged(result.added, result.removed) : text2.refreshDatastoresUnchanged;
|
|
19698
|
+
}
|
|
19699
|
+
function diffDatastoreFiles(before, after) {
|
|
19700
|
+
const beforeIds = new Set(before.map((file) => file.id));
|
|
19701
|
+
const afterIds = new Set(after.map((file) => file.id));
|
|
19702
|
+
let added = 0;
|
|
19703
|
+
let removed = 0;
|
|
19704
|
+
for (const id of afterIds) {
|
|
19705
|
+
if (!beforeIds.has(id))
|
|
19706
|
+
added++;
|
|
19707
|
+
}
|
|
19708
|
+
for (const id of beforeIds) {
|
|
19709
|
+
if (!afterIds.has(id))
|
|
19710
|
+
removed++;
|
|
19711
|
+
}
|
|
19712
|
+
return { added, removed };
|
|
19713
|
+
}
|
|
19714
|
+
async function refreshDatastoreList() {
|
|
19715
|
+
if (dbRefreshBtn.disabled)
|
|
19716
|
+
return;
|
|
19717
|
+
const beforeFiles = [...lastFiles];
|
|
19718
|
+
isRefreshingDatastores = true;
|
|
19719
|
+
dbRefreshBtn.disabled = true;
|
|
19720
|
+
dbRefreshBtn.classList.add("spinning");
|
|
19721
|
+
syncDbRefreshButton();
|
|
19722
|
+
try {
|
|
19723
|
+
await outerDeps.refreshDatastores();
|
|
19724
|
+
datastoreRefreshResult = cb.isActive() ? diffDatastoreFiles(beforeFiles, lastFiles) : null;
|
|
19725
|
+
} finally {
|
|
19726
|
+
isRefreshingDatastores = false;
|
|
19727
|
+
dbRefreshBtn.classList.remove("spinning");
|
|
19728
|
+
dbRefreshBtn.disabled = false;
|
|
19729
|
+
syncDbRefreshButton();
|
|
19730
|
+
}
|
|
19731
|
+
}
|
|
18938
19732
|
async function handleSchemaSelectChange() {
|
|
18939
19733
|
if (!currentDbInfo || !isPostgresKind(currentDbInfo.kind))
|
|
18940
19734
|
return;
|
|
@@ -18963,6 +19757,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18963
19757
|
const dbId = dbSelect.value;
|
|
18964
19758
|
if (!dbId)
|
|
18965
19759
|
return;
|
|
19760
|
+
datastoreRefreshResult = null;
|
|
19761
|
+
syncDatastoreRefreshResult();
|
|
18966
19762
|
const generation = ++loadGeneration;
|
|
18967
19763
|
const file = lastFiles.find((f2) => f2.id === dbId);
|
|
18968
19764
|
const option = dbSelect.selectedOptions[0];
|
|
@@ -18998,6 +19794,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
18998
19794
|
return;
|
|
18999
19795
|
const files = filesResponse.files;
|
|
19000
19796
|
lastFiles = files;
|
|
19797
|
+
noDatastoresAvailable = files.length === 0;
|
|
19001
19798
|
if (filesResponse.truncated) {
|
|
19002
19799
|
showDockerNotice(paneText().nav.dockerLimitReached);
|
|
19003
19800
|
} else {
|
|
@@ -19010,6 +19807,20 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19010
19807
|
opt.textContent = paneText().nav.noDatastores;
|
|
19011
19808
|
dbSelect.appendChild(opt);
|
|
19012
19809
|
dbSelect.disabled = true;
|
|
19810
|
+
currentDbInfo = null;
|
|
19811
|
+
currentSchema = null;
|
|
19812
|
+
currentTable = null;
|
|
19813
|
+
schemaCache = null;
|
|
19814
|
+
renderSchemaOptions([], null);
|
|
19815
|
+
tableList.render([]);
|
|
19816
|
+
grid.clear();
|
|
19817
|
+
schemaView.clear();
|
|
19818
|
+
erDiagram.clear();
|
|
19819
|
+
redisExplorer.clear();
|
|
19820
|
+
esExplorer.clear();
|
|
19821
|
+
s3Explorer.clear();
|
|
19822
|
+
renderNoDatastoresEmpty();
|
|
19823
|
+
applyVisibility();
|
|
19013
19824
|
cb.onStateChange();
|
|
19014
19825
|
return;
|
|
19015
19826
|
}
|
|
@@ -19204,6 +20015,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19204
20015
|
return target;
|
|
19205
20016
|
}
|
|
19206
20017
|
function getLabel() {
|
|
20018
|
+
if (noDatastoresAvailable)
|
|
20019
|
+
return paneText().nav.noDatastoreTab;
|
|
19207
20020
|
if (!currentDbInfo)
|
|
19208
20021
|
return labelFromDbId(initial.dbId);
|
|
19209
20022
|
const suffix = currentSchema ? ` / ${currentSchema}` : "";
|
|
@@ -19242,6 +20055,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19242
20055
|
function localizePane() {
|
|
19243
20056
|
for (const fn of paneLocalizers)
|
|
19244
20057
|
fn();
|
|
20058
|
+
if (noDatastoresAvailable)
|
|
20059
|
+
renderNoDatastoresEmpty();
|
|
19245
20060
|
grid.localize();
|
|
19246
20061
|
schemaView.localize();
|
|
19247
20062
|
erDiagram.localize();
|
|
@@ -19266,7 +20081,6 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19266
20081
|
}
|
|
19267
20082
|
var ICON_PATH_QUERY = "M5.72 4.22a.75.75 0 0 1 0 1.06L2.81 8l2.91 2.72a.75.75 0 1 1-1.06 1.06L1.22 8.53a.75.75 0 0 1 0-1.06l3.44-3.25a.75.75 0 0 1 1.06 0Zm4.56 0a.75.75 0 0 1 1.06 0l3.44 3.25a.75.75 0 0 1 0 1.06l-3.44 3.25a.75.75 0 1 1-1.06-1.06L13.19 8l-2.91-2.72a.75.75 0 0 1 0-1.06Z";
|
|
19268
20083
|
var ICON_PATH_ER = "M1.5 1.75A.75.75 0 0 1 2.25 1h4.5a.75.75 0 0 1 .75.75v3.5h2v-1.5A.75.75 0 0 1 10.25 3h3.5a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-.75.75h-3.5a.75.75 0 0 1-.75-.75V6.5h-2v3h2v-.75A.75.75 0 0 1 10.25 8h3.5a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-.75.75h-3.5a.75.75 0 0 1-.75-.75v-1.5h-2v3.5a.75.75 0 0 1-.75.75h-4.5a.75.75 0 0 1-.75-.75v-3.5A.75.75 0 0 1 2.25 9h4.5a.75.75 0 0 1 .75.75v.75h-.5v-1H3v3h3V11h.5v-.75a.75.75 0 0 0-.75-.75H3V6.5h2.5V2.5H3Z";
|
|
19269
|
-
var ICON_PATH_SEARCH = "M10.68 11.74a6 6 0 0 1-7.917-8.984 6 6 0 0 1 8.997 7.905l3.05 3.05a.75.75 0 1 1-1.06 1.06l-3.07-3.03ZM11.5 7a4.499 4.499 0 1 1-8.997 0A4.499 4.499 0 0 1 11.5 7Z";
|
|
19270
20084
|
var ICON_PATH_SNAPSHOT = "M3.5 1.75A1.75 1.75 0 0 1 5.25 0h5.5A1.75 1.75 0 0 1 12.5 1.75v.5h1.75A1.75 1.75 0 0 1 16 4v9.25A1.75 1.75 0 0 1 14.25 15H1.75A1.75 1.75 0 0 1 0 13.25V4a1.75 1.75 0 0 1 1.75-1.75H3.5v-.5Zm1.5.5v.5h6v-.5a.25.25 0 0 0-.25-.25h-5.5a.25.25 0 0 0-.25.25Zm-3.25 2a.25.25 0 0 0-.25.25v9.25c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V4a.25.25 0 0 0-.25-.25H1.75ZM8 6a2.75 2.75 0 1 0 0 5.5 2.75 2.75 0 0 0 0-5.5Z";
|
|
19271
20085
|
var ICON_PATH_EDIT_MODE = "M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.61Zm.176 4.823L9.75 4.81l-6.286 6.287a.247.247 0 0 0-.064.108l-.558 1.953 1.953-.558a.249.249 0 0 0 .108-.064l6.286-6.286Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354L12.427 2.49Z";
|
|
19272
20086
|
function makeIconButton(opts) {
|
|
@@ -19897,6 +20711,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
19897
20711
|
setDbUiPref,
|
|
19898
20712
|
onDbUiPrefChange,
|
|
19899
20713
|
loadSqlHistory,
|
|
20714
|
+
refreshDatastores,
|
|
19900
20715
|
sessionLog
|
|
19901
20716
|
}, {
|
|
19902
20717
|
tabId: id,
|
|
@@ -20208,6 +21023,36 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20208
21023
|
}).then(() => doEnter(seq, db, schema, table2, view, options));
|
|
20209
21024
|
await enterQueue;
|
|
20210
21025
|
}
|
|
21026
|
+
async function refreshDatastores() {
|
|
21027
|
+
const seq = lifecycleSeq;
|
|
21028
|
+
enterQueue = enterQueue.catch(() => {
|
|
21029
|
+
return;
|
|
21030
|
+
}).then(() => doRefreshDatastores(seq));
|
|
21031
|
+
await enterQueue;
|
|
21032
|
+
}
|
|
21033
|
+
async function doRefreshDatastores(seq) {
|
|
21034
|
+
if (seq !== lifecycleSeq)
|
|
21035
|
+
return;
|
|
21036
|
+
dbFilesCache = null;
|
|
21037
|
+
if (!mounted || !activeTabId)
|
|
21038
|
+
return;
|
|
21039
|
+
const id = activeTabId;
|
|
21040
|
+
const entry = tabsById.get(id);
|
|
21041
|
+
if (!entry)
|
|
21042
|
+
return;
|
|
21043
|
+
const pendingInitialEnter = ensureInitialEnter(id);
|
|
21044
|
+
if (pendingInitialEnter)
|
|
21045
|
+
await pendingInitialEnter;
|
|
21046
|
+
if (!mounted || activeTabId !== id)
|
|
21047
|
+
return;
|
|
21048
|
+
const state = entry.pane.getState();
|
|
21049
|
+
await entry.pane.enter(state.dbId ?? undefined, state.schema ?? undefined, state.table ?? undefined, state.view, { autoSelectFirst: state.dbId !== null });
|
|
21050
|
+
if (!mounted || activeTabId !== id)
|
|
21051
|
+
return;
|
|
21052
|
+
refreshChipLabel(id);
|
|
21053
|
+
syncActiveRoute();
|
|
21054
|
+
scheduleSave();
|
|
21055
|
+
}
|
|
20211
21056
|
function leave() {
|
|
20212
21057
|
if (!mounted)
|
|
20213
21058
|
return;
|
|
@@ -20285,6 +21130,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20285
21130
|
leave,
|
|
20286
21131
|
handleSse,
|
|
20287
21132
|
localize,
|
|
21133
|
+
refresh: refreshDatastores,
|
|
20288
21134
|
getDbUiPref,
|
|
20289
21135
|
setDbUiPref,
|
|
20290
21136
|
onDbUiPrefChange
|
|
@@ -20483,6 +21329,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20483
21329
|
getServerGeneration,
|
|
20484
21330
|
setServerGeneration,
|
|
20485
21331
|
invalidateRepoSidebar,
|
|
21332
|
+
diffText,
|
|
20486
21333
|
getDiffRoot,
|
|
20487
21334
|
getEmptyPane,
|
|
20488
21335
|
isEmbeddedDiffMode
|
|
@@ -20543,7 +21390,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20543
21390
|
if (!button)
|
|
20544
21391
|
return;
|
|
20545
21392
|
button.setAttribute("aria-pressed", expanded ? "true" : "false");
|
|
20546
|
-
|
|
21393
|
+
const label = expanded ? "Collapse expanded lines" : "Expand all lines";
|
|
21394
|
+
button.title = label;
|
|
21395
|
+
button.setAttribute("aria-label", label);
|
|
20547
21396
|
button.innerHTML = expanded ? iconSvg("octicon-fold", COLLAPSE_ALL_16_PATHS) : iconSvg("octicon-unfold", EXPAND_ALL_16_PATHS);
|
|
20548
21397
|
}
|
|
20549
21398
|
function setProjectBranch(branch) {
|
|
@@ -20554,25 +21403,137 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20554
21403
|
el.textContent = branch;
|
|
20555
21404
|
el.title = branch ? `Current branch: ${branch}` : "";
|
|
20556
21405
|
}
|
|
21406
|
+
let metaFilesForViewedProgress = [];
|
|
21407
|
+
function viewedProgressFor(files) {
|
|
21408
|
+
const total = files.length;
|
|
21409
|
+
const viewed = files.filter((file) => STATE.viewedFiles.has(file.path)).length;
|
|
21410
|
+
return { viewed, total };
|
|
21411
|
+
}
|
|
21412
|
+
function applyViewedProgressChipState(chip, viewed, total) {
|
|
21413
|
+
chip.textContent = diffText().viewedProgress(viewed, total);
|
|
21414
|
+
chip.classList.toggle("chip-viewed-empty", viewed === 0);
|
|
21415
|
+
chip.classList.toggle("chip-viewed-partial", viewed > 0 && viewed < total);
|
|
21416
|
+
chip.classList.toggle("chip-viewed-done", total > 0 && viewed === total);
|
|
21417
|
+
}
|
|
21418
|
+
function syncViewedProgressChip() {
|
|
21419
|
+
const chip = document.querySelector("#meta .chip-viewed");
|
|
21420
|
+
if (chip) {
|
|
21421
|
+
const { viewed, total } = viewedProgressFor(metaFilesForViewedProgress);
|
|
21422
|
+
if (total <= 0)
|
|
21423
|
+
chip.remove();
|
|
21424
|
+
else
|
|
21425
|
+
applyViewedProgressChipState(chip, viewed, total);
|
|
21426
|
+
}
|
|
21427
|
+
syncNextUnviewedButton();
|
|
21428
|
+
}
|
|
21429
|
+
function applyNextUnviewedButtonState(button, hasUnviewed) {
|
|
21430
|
+
const text2 = diffText();
|
|
21431
|
+
button.disabled = !hasUnviewed;
|
|
21432
|
+
button.textContent = hasUnviewed ? text2.nextUnviewed : text2.allViewed;
|
|
21433
|
+
button.title = hasUnviewed ? text2.nextUnviewedTitle : text2.allViewedTitle;
|
|
21434
|
+
}
|
|
21435
|
+
function syncNextUnviewedButton() {
|
|
21436
|
+
const button = document.querySelector("#meta .chip-next-unviewed");
|
|
21437
|
+
if (!button)
|
|
21438
|
+
return;
|
|
21439
|
+
const { total } = viewedProgressFor(metaFilesForViewedProgress);
|
|
21440
|
+
if (total <= 0) {
|
|
21441
|
+
button.remove();
|
|
21442
|
+
return;
|
|
21443
|
+
}
|
|
21444
|
+
applyNextUnviewedButtonState(button, nextUnviewedFilePath() !== null);
|
|
21445
|
+
}
|
|
21446
|
+
function nextUnviewedFilePath() {
|
|
21447
|
+
if (isRepositorySidebarMode())
|
|
21448
|
+
return null;
|
|
21449
|
+
const items = $$("#filelist li[data-path]:not(.hidden):not(.hidden-by-tests)");
|
|
21450
|
+
if (items.length === 0)
|
|
21451
|
+
return null;
|
|
21452
|
+
const currentIndex = items.findIndex((li) => li.classList.contains("active"));
|
|
21453
|
+
for (let offset = 1;offset <= items.length; offset++) {
|
|
21454
|
+
const idx = (currentIndex + offset + items.length) % items.length;
|
|
21455
|
+
const li = items[idx];
|
|
21456
|
+
const path = li.dataset.path || "";
|
|
21457
|
+
const viewed = STATE.viewedFiles.has(path) || li.classList.contains("viewed");
|
|
21458
|
+
if (path && !viewed)
|
|
21459
|
+
return path;
|
|
21460
|
+
}
|
|
21461
|
+
return null;
|
|
21462
|
+
}
|
|
21463
|
+
function scrollToNextUnviewedFile() {
|
|
21464
|
+
const path = nextUnviewedFilePath();
|
|
21465
|
+
if (!path)
|
|
21466
|
+
return false;
|
|
21467
|
+
scrollToFile(path, undefined, { reveal: true });
|
|
21468
|
+
return true;
|
|
21469
|
+
}
|
|
20557
21470
|
function renderMeta(meta) {
|
|
20558
21471
|
const el = $("#meta");
|
|
20559
21472
|
if (!meta) {
|
|
20560
21473
|
el.textContent = "";
|
|
21474
|
+
metaFilesForViewedProgress = [];
|
|
20561
21475
|
return;
|
|
20562
21476
|
}
|
|
20563
21477
|
setProjectName(meta.project || "");
|
|
20564
21478
|
setProjectBranch(meta.branch || "");
|
|
21479
|
+
metaFilesForViewedProgress = meta.files || [];
|
|
20565
21480
|
el.innerHTML = "";
|
|
21481
|
+
const text2 = diffText();
|
|
21482
|
+
if (meta.error) {
|
|
21483
|
+
const error2 = document.createElement("span");
|
|
21484
|
+
error2.className = "chip chip-error";
|
|
21485
|
+
error2.textContent = meta.error;
|
|
21486
|
+
el.appendChild(error2);
|
|
21487
|
+
}
|
|
20566
21488
|
if (meta.totals) {
|
|
20567
|
-
const
|
|
20568
|
-
|
|
20569
|
-
|
|
20570
|
-
el.appendChild(
|
|
21489
|
+
const files = document.createElement("span");
|
|
21490
|
+
files.className = "chip chip-files";
|
|
21491
|
+
files.textContent = text2.files(meta.totals.files);
|
|
21492
|
+
el.appendChild(files);
|
|
21493
|
+
const add2 = document.createElement("span");
|
|
21494
|
+
add2.className = "chip chip-add";
|
|
21495
|
+
add2.textContent = `+${meta.totals.additions}`;
|
|
21496
|
+
el.appendChild(add2);
|
|
21497
|
+
const del = document.createElement("span");
|
|
21498
|
+
del.className = "chip chip-del";
|
|
21499
|
+
del.textContent = `−${meta.totals.deletions}`;
|
|
21500
|
+
el.appendChild(del);
|
|
21501
|
+
}
|
|
21502
|
+
const kinds = summarizeDiffFileKinds(meta.files);
|
|
21503
|
+
const kindChip = (className, label, count) => {
|
|
21504
|
+
if (count <= 0)
|
|
21505
|
+
return;
|
|
21506
|
+
const chip = document.createElement("span");
|
|
21507
|
+
chip.className = `chip ${className}`;
|
|
21508
|
+
chip.textContent = `${count} ${label}`;
|
|
21509
|
+
el.appendChild(chip);
|
|
21510
|
+
};
|
|
21511
|
+
kindChip("chip-added", text2.kindAdded, kinds.added);
|
|
21512
|
+
kindChip("chip-deleted", text2.kindDeleted, kinds.deleted);
|
|
21513
|
+
kindChip("chip-renamed", text2.kindRenamed, kinds.renamed);
|
|
21514
|
+
kindChip("chip-heavy", text2.kindHeavy, kinds.heavy);
|
|
21515
|
+
kindChip("chip-binary", text2.kindBinary, kinds.binary);
|
|
21516
|
+
kindChip("chip-media", text2.kindMedia, kinds.media);
|
|
21517
|
+
const viewedProgress = viewedProgressFor(metaFilesForViewedProgress);
|
|
21518
|
+
if (viewedProgress.total > 0) {
|
|
21519
|
+
const viewed = document.createElement("span");
|
|
21520
|
+
viewed.className = "chip chip-viewed";
|
|
21521
|
+
viewed.title = text2.viewedProgressTitle;
|
|
21522
|
+
applyViewedProgressChipState(viewed, viewedProgress.viewed, viewedProgress.total);
|
|
21523
|
+
el.appendChild(viewed);
|
|
21524
|
+
const nextUnviewed = document.createElement("button");
|
|
21525
|
+
nextUnviewed.type = "button";
|
|
21526
|
+
nextUnviewed.className = "chip chip-next-unviewed";
|
|
21527
|
+
applyNextUnviewedButtonState(nextUnviewed, viewedProgress.viewed < viewedProgress.total);
|
|
21528
|
+
nextUnviewed.addEventListener("click", () => {
|
|
21529
|
+
scrollToNextUnviewedFile();
|
|
21530
|
+
});
|
|
21531
|
+
el.appendChild(nextUnviewed);
|
|
20571
21532
|
}
|
|
20572
21533
|
const u2 = document.createElement("span");
|
|
20573
|
-
u2.className = "updated
|
|
20574
|
-
u2.title =
|
|
20575
|
-
u2.textContent =
|
|
21534
|
+
u2.className = "chip chip-updated";
|
|
21535
|
+
u2.title = text2.updatedTitle;
|
|
21536
|
+
u2.textContent = text2.updated(new Date().toLocaleTimeString([], { hour12: false }));
|
|
20576
21537
|
el.appendChild(u2);
|
|
20577
21538
|
}
|
|
20578
21539
|
let SUPPRESS_SPY_UNTIL = 0;
|
|
@@ -20629,13 +21590,13 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20629
21590
|
window.addEventListener("touchmove", () => {
|
|
20630
21591
|
REANCHOR_UNTIL = 0;
|
|
20631
21592
|
}, { passive: true });
|
|
20632
|
-
function scrollToFile(path, line) {
|
|
21593
|
+
function scrollToFile(path, line, options) {
|
|
20633
21594
|
const card = document.querySelector(diffCardSelector(path));
|
|
20634
21595
|
if (!card)
|
|
20635
21596
|
return;
|
|
20636
21597
|
if (line)
|
|
20637
21598
|
REANCHOR_UNTIL = performance.now() + 4000;
|
|
20638
|
-
markActive(path);
|
|
21599
|
+
markActive(path, { reveal: options?.reveal });
|
|
20639
21600
|
SUPPRESS_SPY_UNTIL = performance.now() + 1500;
|
|
20640
21601
|
const onEnd = () => {
|
|
20641
21602
|
SUPPRESS_SPY_UNTIL = 0;
|
|
@@ -20663,6 +21624,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20663
21624
|
const viewed = STATE.viewedFiles.has(path);
|
|
20664
21625
|
syncViewedCardDisplay(card, viewed);
|
|
20665
21626
|
});
|
|
21627
|
+
syncViewedProgressChip();
|
|
20666
21628
|
}
|
|
20667
21629
|
let CLIENT_REQ_SEQ = 0;
|
|
20668
21630
|
const LOAD_QUEUE = [];
|
|
@@ -20876,6 +21838,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20876
21838
|
setupScrollSpy();
|
|
20877
21839
|
scrollSpyInstalled = true;
|
|
20878
21840
|
}
|
|
21841
|
+
syncViewedProgressChip();
|
|
20879
21842
|
return {
|
|
20880
21843
|
structureChanged: false,
|
|
20881
21844
|
invalidatedCards,
|
|
@@ -21213,7 +22176,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21213
22176
|
const button = card.querySelector(".gdp-file-toggle");
|
|
21214
22177
|
if (button) {
|
|
21215
22178
|
button.setAttribute("aria-expanded", collapsed ? "false" : "true");
|
|
21216
|
-
|
|
22179
|
+
const toggleLabel = collapsed ? "Expand file" : "Collapse file";
|
|
22180
|
+
button.title = toggleLabel;
|
|
22181
|
+
button.setAttribute("aria-label", toggleLabel);
|
|
21217
22182
|
}
|
|
21218
22183
|
const unfold = card.querySelector(".gdp-file-unfold");
|
|
21219
22184
|
if (unfold)
|
|
@@ -21310,6 +22275,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21310
22275
|
toggle.type = "button";
|
|
21311
22276
|
toggle.className = "gdp-file-header-icon gdp-file-toggle";
|
|
21312
22277
|
toggle.title = "Collapse file";
|
|
22278
|
+
toggle.setAttribute("aria-label", "Collapse file");
|
|
21313
22279
|
toggle.setAttribute("aria-expanded", "true");
|
|
21314
22280
|
toggle.innerHTML = iconSvg("octicon-chevron-down", CHEVRON_DOWN_16_PATH);
|
|
21315
22281
|
toggle.addEventListener("click", (e2) => {
|
|
@@ -21331,6 +22297,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21331
22297
|
copy.type = "button";
|
|
21332
22298
|
copy.className = "gdp-file-header-icon gdp-copy-path";
|
|
21333
22299
|
copy.title = "copy file path";
|
|
22300
|
+
copy.setAttribute("aria-label", "copy file path");
|
|
21334
22301
|
copy.innerHTML = iconSvg("octicon-copy", COPY_16_PATHS);
|
|
21335
22302
|
copy.addEventListener("click", async (e2) => {
|
|
21336
22303
|
e2.stopPropagation();
|
|
@@ -21671,6 +22638,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21671
22638
|
addExpandHunksUI,
|
|
21672
22639
|
scheduleIdleHighlight,
|
|
21673
22640
|
scrollToFile,
|
|
22641
|
+
scrollToNextUnviewedFile,
|
|
21674
22642
|
prefetchByPath,
|
|
21675
22643
|
applyDiffRouteFocus,
|
|
21676
22644
|
clearDiffLineFocus,
|
|
@@ -21899,12 +22867,17 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21899
22867
|
deps.clearLoadQueue();
|
|
21900
22868
|
if (deps.empty) {
|
|
21901
22869
|
deps.empty.classList.remove("hidden");
|
|
22870
|
+
deps.empty.classList.remove("empty-with-actions");
|
|
22871
|
+
const text2 = deps.emptyText();
|
|
21902
22872
|
const h2 = deps.empty.querySelector("h2");
|
|
21903
22873
|
if (h2)
|
|
21904
|
-
h2.textContent =
|
|
22874
|
+
h2.textContent = text2.noCommitSelectedTitle;
|
|
21905
22875
|
const p2 = deps.empty.querySelector("p");
|
|
21906
22876
|
if (p2)
|
|
21907
|
-
p2.textContent =
|
|
22877
|
+
p2.textContent = text2.noCommitSelectedBody;
|
|
22878
|
+
const actions = deps.empty.querySelector(".empty-actions");
|
|
22879
|
+
if (actions)
|
|
22880
|
+
actions.hidden = true;
|
|
21908
22881
|
}
|
|
21909
22882
|
deps.setStatus("live");
|
|
21910
22883
|
}
|
|
@@ -21962,14 +22935,37 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21962
22935
|
en: {
|
|
21963
22936
|
worktreeLabel: "Uncommitted changes (Working tree)",
|
|
21964
22937
|
bodyExpandClose: "Collapse",
|
|
21965
|
-
bodyExpandMore: (n2) => `Show more (${n2} lines)
|
|
22938
|
+
bodyExpandMore: (n2) => `Show more (${n2} lines)`,
|
|
22939
|
+
refreshLabel: "Refresh",
|
|
22940
|
+
refreshLabelPending: "Update",
|
|
22941
|
+
refreshTitle: "Refresh commit history",
|
|
22942
|
+
refreshTitlePending: "History may have changed. Refresh",
|
|
22943
|
+
refreshPendingStatus: "History may have changed",
|
|
22944
|
+
refreshResultUpdated: (sha) => `Updated: ${sha} is now latest`,
|
|
22945
|
+
refreshResultUnchanged: "No new commits",
|
|
22946
|
+
refreshResultUnchangedInView: "No new commits in this view",
|
|
22947
|
+
filterClearLabel: "Clear",
|
|
22948
|
+
filterClearTitle: "Clear commit filter"
|
|
21966
22949
|
},
|
|
21967
22950
|
ja: {
|
|
21968
22951
|
worktreeLabel: "未コミット変更 (Working tree)",
|
|
21969
22952
|
bodyExpandClose: "閉じる",
|
|
21970
|
-
bodyExpandMore: (n2) => `もっと見る (${n2} 行)
|
|
22953
|
+
bodyExpandMore: (n2) => `もっと見る (${n2} 行)`,
|
|
22954
|
+
refreshLabel: "更新",
|
|
22955
|
+
refreshLabelPending: "更新あり",
|
|
22956
|
+
refreshTitle: "コミット履歴を更新",
|
|
22957
|
+
refreshTitlePending: "新しい履歴がある可能性があります。更新",
|
|
22958
|
+
refreshPendingStatus: "新しい履歴がある可能性があります",
|
|
22959
|
+
refreshResultUpdated: (sha) => `更新: ${sha} が最新です`,
|
|
22960
|
+
refreshResultUnchanged: "新しいコミットはありません",
|
|
22961
|
+
refreshResultUnchangedInView: "この表示では新しいコミットはありません",
|
|
22962
|
+
filterClearLabel: "解除",
|
|
22963
|
+
filterClearTitle: "コミットフィルタを解除"
|
|
21971
22964
|
}
|
|
21972
22965
|
};
|
|
22966
|
+
function historyText(lang) {
|
|
22967
|
+
return HISTORY_TEXT[lang];
|
|
22968
|
+
}
|
|
21973
22969
|
function historyWorktreeLabel(lang) {
|
|
21974
22970
|
return HISTORY_TEXT[lang].worktreeLabel;
|
|
21975
22971
|
}
|
|
@@ -21990,6 +22986,20 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21990
22986
|
title.className = "history-title";
|
|
21991
22987
|
title.textContent = "Commits";
|
|
21992
22988
|
panelHead.appendChild(title);
|
|
22989
|
+
const refreshButton = document.createElement("button");
|
|
22990
|
+
refreshButton.type = "button";
|
|
22991
|
+
refreshButton.className = "history-refresh";
|
|
22992
|
+
refreshButton.title = HISTORY_TEXT.en.refreshTitle;
|
|
22993
|
+
refreshButton.setAttribute("aria-label", HISTORY_TEXT.en.refreshTitle);
|
|
22994
|
+
refreshButton.innerHTML = iconSvg("octicon-sync", SYNC_16_PATH);
|
|
22995
|
+
const refreshLabel = document.createElement("span");
|
|
22996
|
+
refreshLabel.className = "history-refresh-label";
|
|
22997
|
+
refreshLabel.textContent = HISTORY_TEXT.en.refreshLabel;
|
|
22998
|
+
refreshButton.appendChild(refreshLabel);
|
|
22999
|
+
const refreshResult = document.createElement("span");
|
|
23000
|
+
refreshResult.className = "db-refresh-result history-refresh-result";
|
|
23001
|
+
refreshResult.setAttribute("aria-live", "polite");
|
|
23002
|
+
refreshResult.hidden = true;
|
|
21993
23003
|
if (page) {
|
|
21994
23004
|
const refMount = document.createElement("span");
|
|
21995
23005
|
refMount.dataset.refSelectorMount = "";
|
|
@@ -21998,6 +23008,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21998
23008
|
refMount.dataset.title = "history ref";
|
|
21999
23009
|
panelHead.appendChild(refMount);
|
|
22000
23010
|
}
|
|
23011
|
+
panelHead.append(refreshButton, refreshResult);
|
|
22001
23012
|
const filterWrap = document.createElement("div");
|
|
22002
23013
|
filterWrap.className = "history-filter-wrap";
|
|
22003
23014
|
const filterInput = document.createElement("input");
|
|
@@ -22008,7 +23019,16 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22008
23019
|
filterInput.type = "search";
|
|
22009
23020
|
filterInput.placeholder = page ? "filter commits… (message, sha, author:name, path:file)" : "filter commits… (message, sha, author:name)";
|
|
22010
23021
|
filterInput.autocomplete = "off";
|
|
22011
|
-
|
|
23022
|
+
const filterClearButton = document.createElement("button");
|
|
23023
|
+
filterClearButton.type = "button";
|
|
23024
|
+
if (page)
|
|
23025
|
+
filterClearButton.id = "history-filter-clear";
|
|
23026
|
+
filterClearButton.className = "history-filter-clear";
|
|
23027
|
+
filterClearButton.hidden = true;
|
|
23028
|
+
filterClearButton.textContent = HISTORY_TEXT.en.filterClearLabel;
|
|
23029
|
+
filterClearButton.title = HISTORY_TEXT.en.filterClearTitle;
|
|
23030
|
+
filterClearButton.setAttribute("aria-label", HISTORY_TEXT.en.filterClearTitle);
|
|
23031
|
+
filterWrap.append(filterInput, filterClearButton);
|
|
22012
23032
|
const banner = document.createElement("div");
|
|
22013
23033
|
if (page)
|
|
22014
23034
|
banner.id = "history-banner";
|
|
@@ -22031,7 +23051,17 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22031
23051
|
status.hidden = true;
|
|
22032
23052
|
status.setAttribute("role", "status");
|
|
22033
23053
|
panel.append(panelHead, filterWrap, banner, list2, sentinel, status);
|
|
22034
|
-
return {
|
|
23054
|
+
return {
|
|
23055
|
+
panel,
|
|
23056
|
+
list: list2,
|
|
23057
|
+
banner,
|
|
23058
|
+
status,
|
|
23059
|
+
sentinel,
|
|
23060
|
+
filterInput,
|
|
23061
|
+
filterClearButton,
|
|
23062
|
+
refreshButton,
|
|
23063
|
+
refreshResult
|
|
23064
|
+
};
|
|
22035
23065
|
}
|
|
22036
23066
|
function buildHistoryCommitInfoDom(options = {}) {
|
|
22037
23067
|
const variant = options.variant || "page";
|
|
@@ -22129,6 +23159,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22129
23159
|
status: deps.$("#history-status"),
|
|
22130
23160
|
sentinel: deps.$("#history-sentinel"),
|
|
22131
23161
|
filterInput: document.querySelector("#history-filter"),
|
|
23162
|
+
filterClearButton: document.querySelector("#history-filter-clear"),
|
|
23163
|
+
refreshButton: document.querySelector(".history-refresh"),
|
|
23164
|
+
refreshResult: document.querySelector(".history-refresh-result"),
|
|
22132
23165
|
commitInfo: document.querySelector("#history-commit-info")
|
|
22133
23166
|
};
|
|
22134
23167
|
let activeMount = defaultMount;
|
|
@@ -22139,6 +23172,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22139
23172
|
let sentinel = defaultMount.sentinel;
|
|
22140
23173
|
let attachedList = null;
|
|
22141
23174
|
let attachedFilterInput = null;
|
|
23175
|
+
let attachedFilterClearButton = null;
|
|
23176
|
+
let attachedRefreshButton = null;
|
|
22142
23177
|
let filterTimer = null;
|
|
22143
23178
|
let observer = null;
|
|
22144
23179
|
let ref = "HEAD";
|
|
@@ -22152,6 +23187,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22152
23187
|
let mode = "history";
|
|
22153
23188
|
let routeRef = "HEAD";
|
|
22154
23189
|
let pathFilter = "";
|
|
23190
|
+
let refreshStatus = { type: "none" };
|
|
23191
|
+
let freshSha = "";
|
|
22155
23192
|
function historyScopeFromRoute(route = deps.getRoute()) {
|
|
22156
23193
|
if (route.screen === "history") {
|
|
22157
23194
|
const nextRef = route.ref || "HEAD";
|
|
@@ -22175,6 +23212,18 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22175
23212
|
}
|
|
22176
23213
|
return null;
|
|
22177
23214
|
}
|
|
23215
|
+
function currentRefreshScopeKey() {
|
|
23216
|
+
const scope = historyScopeFromRoute();
|
|
23217
|
+
if (!scope)
|
|
23218
|
+
return "";
|
|
23219
|
+
return [
|
|
23220
|
+
scope.mode,
|
|
23221
|
+
scope.logRef,
|
|
23222
|
+
scope.routeRef,
|
|
23223
|
+
scope.pathFilter,
|
|
23224
|
+
query
|
|
23225
|
+
].join("\x00");
|
|
23226
|
+
}
|
|
22178
23227
|
function worktreeDiffRange() {
|
|
22179
23228
|
return { from: "HEAD", to: "worktree" };
|
|
22180
23229
|
}
|
|
@@ -22186,6 +23235,39 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22186
23235
|
statusEl.textContent = message;
|
|
22187
23236
|
statusEl.hidden = !message;
|
|
22188
23237
|
}
|
|
23238
|
+
function latestCommitSha() {
|
|
23239
|
+
return commits.find((commit) => commit.sha !== HISTORY_WORKTREE_COMMIT)?.sha || "";
|
|
23240
|
+
}
|
|
23241
|
+
function clearRefreshResult() {
|
|
23242
|
+
refreshStatus = { type: "none" };
|
|
23243
|
+
freshSha = "";
|
|
23244
|
+
syncRefreshResult();
|
|
23245
|
+
}
|
|
23246
|
+
function setRefreshResult(previousTopSha, nextTopSha) {
|
|
23247
|
+
freshSha = previousTopSha && nextTopSha && previousTopSha !== nextTopSha ? nextTopSha : "";
|
|
23248
|
+
refreshStatus = freshSha ? { type: "updated", sha: nextTopSha.slice(0, 7) } : { type: "unchanged", scoped: Boolean(query || pathFilter) };
|
|
23249
|
+
renderList();
|
|
23250
|
+
}
|
|
23251
|
+
function refreshStatusMessage() {
|
|
23252
|
+
const text2 = historyText(deps.getLanguage());
|
|
23253
|
+
switch (refreshStatus.type) {
|
|
23254
|
+
case "pending":
|
|
23255
|
+
return text2.refreshPendingStatus;
|
|
23256
|
+
case "updated":
|
|
23257
|
+
return text2.refreshResultUpdated(refreshStatus.sha);
|
|
23258
|
+
case "unchanged":
|
|
23259
|
+
return refreshStatus.scoped ? text2.refreshResultUnchangedInView : text2.refreshResultUnchanged;
|
|
23260
|
+
case "none":
|
|
23261
|
+
return "";
|
|
23262
|
+
default: {
|
|
23263
|
+
const exhaustive = refreshStatus;
|
|
23264
|
+
return exhaustive;
|
|
23265
|
+
}
|
|
23266
|
+
}
|
|
23267
|
+
}
|
|
23268
|
+
function syncRefreshStatusText() {
|
|
23269
|
+
setStatusText(loading ? "loading..." : refreshStatusMessage() || (commits.length ? "" : "no commits"));
|
|
23270
|
+
}
|
|
22189
23271
|
function commitInfoElement() {
|
|
22190
23272
|
return activeMount.commitInfo || document.querySelector("#history-commit-info");
|
|
22191
23273
|
}
|
|
@@ -22257,13 +23339,16 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22257
23339
|
}
|
|
22258
23340
|
function commitRow(commit) {
|
|
22259
23341
|
const active = commit.sha === selectedSha ? " active" : "";
|
|
22260
|
-
|
|
23342
|
+
const fresh = commit.sha === freshSha ? " history-item-fresh" : "";
|
|
23343
|
+
return `<li class="history-item${active}${fresh}" data-sha="${deps.escapeHtml(commit.sha)}">` + `<span class="subject" title="${deps.escapeHtml(commit.subject)}">${deps.escapeHtml(commit.subject)}</span>` + `<span class="meta2">` + `<span class="sha">${deps.escapeHtml(commit.sha.slice(0, 7))}</span>` + `<span class="author">${deps.escapeHtml(commit.author)}</span>` + `<span class="when">${deps.escapeHtml(displayWhen(commit.when))}</span>` + `</span>` + `</li>`;
|
|
22261
23344
|
}
|
|
22262
23345
|
function worktreeRow() {
|
|
22263
23346
|
const active = selectedSha === HISTORY_WORKTREE_COMMIT ? " active" : "";
|
|
22264
23347
|
return `<li class="history-item history-item-worktree${active}" data-sha="${HISTORY_WORKTREE_COMMIT}">` + `<span class="subject" title="${deps.escapeHtml(historyWorktreeLabel(deps.getLanguage()))}">${deps.escapeHtml(historyWorktreeLabel(deps.getLanguage()))}</span>` + `<span class="meta2">` + `<span class="sha">HEAD..worktree</span>` + `<span class="author">Working tree</span>` + `</span>` + `</li>`;
|
|
22265
23348
|
}
|
|
22266
23349
|
function renderList() {
|
|
23350
|
+
syncRefreshButton(activeMount.refreshButton);
|
|
23351
|
+
syncRefreshResult(activeMount.refreshResult);
|
|
22267
23352
|
const now = new Date;
|
|
22268
23353
|
const html = mode === "history" ? [worktreeRow()] : [];
|
|
22269
23354
|
let lastGroup = "";
|
|
@@ -22280,7 +23365,42 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22280
23365
|
html.push(commitRow(commit));
|
|
22281
23366
|
}
|
|
22282
23367
|
list2.innerHTML = html.join("");
|
|
22283
|
-
|
|
23368
|
+
syncRefreshStatusText();
|
|
23369
|
+
}
|
|
23370
|
+
function syncRefreshButton(button) {
|
|
23371
|
+
if (!button)
|
|
23372
|
+
return;
|
|
23373
|
+
const text2 = historyText(deps.getLanguage());
|
|
23374
|
+
const hasPendingUpdate = refreshStatus.type === "pending";
|
|
23375
|
+
const title = hasPendingUpdate ? text2.refreshTitlePending : text2.refreshTitle;
|
|
23376
|
+
button.title = title;
|
|
23377
|
+
button.setAttribute("aria-label", title);
|
|
23378
|
+
button.classList.toggle("has-update", hasPendingUpdate);
|
|
23379
|
+
const label = button.querySelector(".history-refresh-label");
|
|
23380
|
+
if (label) {
|
|
23381
|
+
label.textContent = hasPendingUpdate ? text2.refreshLabelPending : text2.refreshLabel;
|
|
23382
|
+
}
|
|
23383
|
+
}
|
|
23384
|
+
function syncRefreshResult(result) {
|
|
23385
|
+
const el = result ?? activeMount.refreshResult;
|
|
23386
|
+
if (!el)
|
|
23387
|
+
return;
|
|
23388
|
+
const message = refreshStatus.type === "pending" || refreshStatus.type === "updated" || refreshStatus.type === "unchanged" ? refreshStatusMessage() : "";
|
|
23389
|
+
el.textContent = message;
|
|
23390
|
+
el.hidden = message.length === 0;
|
|
23391
|
+
el.classList.toggle("changed", refreshStatus.type === "updated");
|
|
23392
|
+
el.classList.toggle("pending", refreshStatus.type === "pending");
|
|
23393
|
+
}
|
|
23394
|
+
function syncFilterClearButton(button) {
|
|
23395
|
+
const clearButton = button ?? activeMount.filterClearButton;
|
|
23396
|
+
if (!clearButton)
|
|
23397
|
+
return;
|
|
23398
|
+
const input = activeMount.filterInput ?? null;
|
|
23399
|
+
const text2 = historyText(deps.getLanguage());
|
|
23400
|
+
clearButton.textContent = text2.filterClearLabel;
|
|
23401
|
+
clearButton.title = text2.filterClearTitle;
|
|
23402
|
+
clearButton.setAttribute("aria-label", text2.filterClearTitle);
|
|
23403
|
+
clearButton.hidden = !(input?.value || "");
|
|
22284
23404
|
}
|
|
22285
23405
|
async function updateCommitInfo(commit) {
|
|
22286
23406
|
const info = commitInfoElement();
|
|
@@ -22559,6 +23679,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22559
23679
|
selectionGeneration++;
|
|
22560
23680
|
selectedSha = "";
|
|
22561
23681
|
setBanner("");
|
|
23682
|
+
clearRefreshResult();
|
|
22562
23683
|
await updateCommitInfo(null);
|
|
22563
23684
|
renderList();
|
|
22564
23685
|
await loadNextPage();
|
|
@@ -22629,6 +23750,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22629
23750
|
query = value;
|
|
22630
23751
|
generation++;
|
|
22631
23752
|
selectionGeneration++;
|
|
23753
|
+
clearRefreshResult();
|
|
22632
23754
|
commits = [];
|
|
22633
23755
|
hasMore = false;
|
|
22634
23756
|
loading = false;
|
|
@@ -22648,6 +23770,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22648
23770
|
const input = activeFilterInputFromEvent(event);
|
|
22649
23771
|
if (!input)
|
|
22650
23772
|
return;
|
|
23773
|
+
syncFilterClearButton();
|
|
22651
23774
|
if (filterTimer)
|
|
22652
23775
|
clearTimeout(filterTimer);
|
|
22653
23776
|
filterTimer = setTimeout(() => {
|
|
@@ -22663,13 +23786,54 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22663
23786
|
return;
|
|
22664
23787
|
if (e2.key === "Escape" && input.value) {
|
|
22665
23788
|
input.value = "";
|
|
23789
|
+
syncFilterClearButton();
|
|
22666
23790
|
applyFilter("");
|
|
22667
23791
|
e2.stopPropagation();
|
|
22668
23792
|
}
|
|
22669
23793
|
}
|
|
23794
|
+
function handleFilterClearClick() {
|
|
23795
|
+
const input = attachedFilterInput;
|
|
23796
|
+
if (!input?.value)
|
|
23797
|
+
return;
|
|
23798
|
+
if (filterTimer) {
|
|
23799
|
+
clearTimeout(filterTimer);
|
|
23800
|
+
filterTimer = null;
|
|
23801
|
+
}
|
|
23802
|
+
input.value = "";
|
|
23803
|
+
syncFilterClearButton();
|
|
23804
|
+
applyFilter("");
|
|
23805
|
+
input.focus?.();
|
|
23806
|
+
}
|
|
23807
|
+
async function handleRefreshClick() {
|
|
23808
|
+
const button = attachedRefreshButton;
|
|
23809
|
+
if (button?.disabled)
|
|
23810
|
+
return;
|
|
23811
|
+
const refreshScopeKey = currentRefreshScopeKey();
|
|
23812
|
+
const previousTopSha = latestCommitSha();
|
|
23813
|
+
clearRefreshResult();
|
|
23814
|
+
if (button) {
|
|
23815
|
+
button.disabled = true;
|
|
23816
|
+
button.classList.add("spinning");
|
|
23817
|
+
}
|
|
23818
|
+
try {
|
|
23819
|
+
await enterHistory({ mount: activeMount, force: true });
|
|
23820
|
+
if (!refreshScopeKey || currentRefreshScopeKey() !== refreshScopeKey)
|
|
23821
|
+
return;
|
|
23822
|
+
setRefreshResult(previousTopSha, latestCommitSha());
|
|
23823
|
+
} finally {
|
|
23824
|
+
if (button) {
|
|
23825
|
+
button.classList.remove("spinning");
|
|
23826
|
+
button.disabled = false;
|
|
23827
|
+
}
|
|
23828
|
+
}
|
|
23829
|
+
}
|
|
22670
23830
|
function activateMount(mount) {
|
|
22671
|
-
if (activeMount === mount && attachedList === mount.list)
|
|
23831
|
+
if (activeMount === mount && attachedList === mount.list) {
|
|
23832
|
+
syncRefreshButton(mount.refreshButton);
|
|
23833
|
+
syncRefreshResult(mount.refreshResult);
|
|
23834
|
+
syncFilterClearButton(mount.filterClearButton);
|
|
22672
23835
|
return;
|
|
23836
|
+
}
|
|
22673
23837
|
if (attachedList) {
|
|
22674
23838
|
attachedList.removeEventListener("click", handleListClick);
|
|
22675
23839
|
attachedList = null;
|
|
@@ -22680,6 +23844,14 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22680
23844
|
attachedFilterInput.removeEventListener("keydown", handleFilterKeydown);
|
|
22681
23845
|
attachedFilterInput = null;
|
|
22682
23846
|
}
|
|
23847
|
+
if (attachedFilterClearButton) {
|
|
23848
|
+
attachedFilterClearButton.removeEventListener("click", handleFilterClearClick);
|
|
23849
|
+
attachedFilterClearButton = null;
|
|
23850
|
+
}
|
|
23851
|
+
if (attachedRefreshButton) {
|
|
23852
|
+
attachedRefreshButton.removeEventListener("click", handleRefreshClick);
|
|
23853
|
+
attachedRefreshButton = null;
|
|
23854
|
+
}
|
|
22683
23855
|
if (filterTimer) {
|
|
22684
23856
|
clearTimeout(filterTimer);
|
|
22685
23857
|
filterTimer = null;
|
|
@@ -22701,6 +23873,19 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22701
23873
|
input.addEventListener("keydown", handleFilterKeydown);
|
|
22702
23874
|
attachedFilterInput = input;
|
|
22703
23875
|
}
|
|
23876
|
+
const filterClearButton = mount.filterClearButton ?? null;
|
|
23877
|
+
if (filterClearButton) {
|
|
23878
|
+
syncFilterClearButton(filterClearButton);
|
|
23879
|
+
filterClearButton.addEventListener("click", handleFilterClearClick);
|
|
23880
|
+
attachedFilterClearButton = filterClearButton;
|
|
23881
|
+
}
|
|
23882
|
+
const refreshButton = mount.refreshButton ?? null;
|
|
23883
|
+
if (refreshButton) {
|
|
23884
|
+
syncRefreshButton(refreshButton);
|
|
23885
|
+
syncRefreshResult(mount.refreshResult);
|
|
23886
|
+
refreshButton.addEventListener("click", handleRefreshClick);
|
|
23887
|
+
attachedRefreshButton = refreshButton;
|
|
23888
|
+
}
|
|
22704
23889
|
observer = new IntersectionObserver((entries) => {
|
|
22705
23890
|
if (!entries.some((entry) => entry.isIntersecting))
|
|
22706
23891
|
return;
|
|
@@ -22737,6 +23922,18 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22737
23922
|
enterHistory,
|
|
22738
23923
|
leaveHistory,
|
|
22739
23924
|
onRefPicked,
|
|
23925
|
+
localize: () => {
|
|
23926
|
+
syncRefreshButton(activeMount.refreshButton);
|
|
23927
|
+
syncRefreshResult(activeMount.refreshResult);
|
|
23928
|
+
syncFilterClearButton(activeMount.filterClearButton);
|
|
23929
|
+
renderList();
|
|
23930
|
+
},
|
|
23931
|
+
notePossibleUpdate: () => {
|
|
23932
|
+
refreshStatus = { type: "pending" };
|
|
23933
|
+
syncRefreshButton(activeMount.refreshButton);
|
|
23934
|
+
syncRefreshResult(activeMount.refreshResult);
|
|
23935
|
+
syncRefreshStatusText();
|
|
23936
|
+
},
|
|
22740
23937
|
isWorktreeSelected: () => selectedSha === HISTORY_WORKTREE_COMMIT
|
|
22741
23938
|
};
|
|
22742
23939
|
}
|
|
@@ -22765,15 +23962,16 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22765
23962
|
const diffPane = document.createElement("main");
|
|
22766
23963
|
diffPane.className = "gdp-file-history-diff-pane";
|
|
22767
23964
|
const commitInfo = buildHistoryCommitInfoDom({ variant: "file" });
|
|
23965
|
+
const emptyText = deps.emptyText();
|
|
22768
23966
|
const empty = document.createElement("div");
|
|
22769
23967
|
empty.className = "empty gdp-file-history-empty hidden";
|
|
22770
23968
|
const emptyIcon = document.createElement("div");
|
|
22771
|
-
emptyIcon.className = "
|
|
22772
|
-
emptyIcon.
|
|
23969
|
+
emptyIcon.className = "empty-icon";
|
|
23970
|
+
emptyIcon.innerHTML = iconSvg("octicon-git-branch", GIT_BRANCH_16_PATH);
|
|
22773
23971
|
const emptyTitle = document.createElement("h2");
|
|
22774
|
-
emptyTitle.textContent =
|
|
23972
|
+
emptyTitle.textContent = emptyText.noCommitSelectedTitle;
|
|
22775
23973
|
const emptyBody = document.createElement("p");
|
|
22776
|
-
emptyBody.textContent =
|
|
23974
|
+
emptyBody.textContent = emptyText.noCommitSelectedBody;
|
|
22777
23975
|
empty.append(emptyIcon, emptyTitle, emptyBody);
|
|
22778
23976
|
const diffHost = document.createElement("div");
|
|
22779
23977
|
diffHost.className = "gdp-file-history-diff";
|
|
@@ -22823,8 +24021,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22823
24021
|
{
|
|
22824
24022
|
selectors: [{ action: "open-help" }],
|
|
22825
24023
|
description: {
|
|
22826
|
-
en: "Open
|
|
22827
|
-
ja: "
|
|
24024
|
+
en: "Open quick help",
|
|
24025
|
+
ja: "クイックヘルプを開く"
|
|
22828
24026
|
}
|
|
22829
24027
|
},
|
|
22830
24028
|
{
|
|
@@ -22851,6 +24049,13 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22851
24049
|
ja: "前 / 次の注釈へ移動"
|
|
22852
24050
|
}
|
|
22853
24051
|
},
|
|
24052
|
+
{
|
|
24053
|
+
selectors: [{ action: "next-unviewed-file" }],
|
|
24054
|
+
description: {
|
|
24055
|
+
en: "Jump to the next unviewed file",
|
|
24056
|
+
ja: "次の未確認ファイルへ移動"
|
|
24057
|
+
}
|
|
24058
|
+
},
|
|
22854
24059
|
{
|
|
22855
24060
|
selectors: [{ action: "layout-unified" }, { action: "layout-split" }],
|
|
22856
24061
|
description: {
|
|
@@ -23096,8 +24301,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23096
24301
|
addUnique(labels, item.label);
|
|
23097
24302
|
return [labels.join(" / "), row.description[language]];
|
|
23098
24303
|
}
|
|
23099
|
-
function buildHelpKeybindingGroups(language, bindings = DEFAULT_KEY_BINDINGS) {
|
|
23100
|
-
|
|
24304
|
+
function buildHelpKeybindingGroups(language, bindings = DEFAULT_KEY_BINDINGS, onlyTitlesEn) {
|
|
24305
|
+
const groups = onlyTitlesEn ? HELP_KEYBINDING_GROUPS.filter((group) => onlyTitlesEn.includes(group.title.en)) : HELP_KEYBINDING_GROUPS;
|
|
24306
|
+
return groups.map((group) => ({
|
|
23101
24307
|
title: group.title[language],
|
|
23102
24308
|
rows: group.rows.map((row) => buildRow(row, language, bindings))
|
|
23103
24309
|
}));
|
|
@@ -23202,7 +24408,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23202
24408
|
},
|
|
23203
24409
|
{
|
|
23204
24410
|
kind: "paragraph",
|
|
23205
|
-
text: 'From the terminal — and for AI agents or CI — the same report is available without a browser. `code-viewer doctor` prints a status summary; add `--json` for the full DoctorReport (matches the /_doctor endpoint). Exit code is 1 when worstStatus is "error", so it doubles as a CI gate.'
|
|
24411
|
+
text: 'From the terminal — and for AI agents or CI — the same report is available without a browser. `code-viewer doctor` prints a status summary; add `--json` for the full DoctorReport (matches the /_doctor endpoint). Use `--bin git=/absolute/path` or `--bin docker=/absolute/path` when PATH resolves the wrong tool. Exit code is 1 when worstStatus is "error", so it doubles as a CI gate.'
|
|
23206
24412
|
},
|
|
23207
24413
|
{
|
|
23208
24414
|
kind: "command",
|
|
@@ -23213,7 +24419,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23213
24419
|
kind: "command",
|
|
23214
24420
|
title: "Doctor JSON for agents and CI",
|
|
23215
24421
|
command: `code-viewer doctor --json
|
|
23216
|
-
code-viewer doctor --cwd /path/to/repo --port 64160 --json
|
|
24422
|
+
code-viewer doctor --cwd /path/to/repo --port 64160 --json
|
|
24423
|
+
code-viewer doctor --bin git=/opt/bin/git --bin docker=/opt/bin/docker --json`
|
|
23217
24424
|
}
|
|
23218
24425
|
]
|
|
23219
24426
|
}
|
|
@@ -23469,7 +24676,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
23469
24676
|
],
|
|
23470
24677
|
[
|
|
23471
24678
|
"Data tab",
|
|
23472
|
-
"Paginated grid with sort, filter, cell copy,
|
|
24679
|
+
"Paginated grid with sort, filter, cell copy, CSV/JSON export (capped at 100k rows; export respects the current filter and sort), and a table-only reload action that keeps global search and column filters. Reload results are announced beside the button so row-count changes are visible. Toggle Edit mode in the prefs bar to enable inline editing — double-click a cell to edit, queue insert/delete via row actions, and commit the batch atomically. Edited rows/cells highlight in yellow until committed."
|
|
23473
24680
|
],
|
|
23474
24681
|
[
|
|
23475
24682
|
"Detail footer & related panel",
|
|
@@ -23477,7 +24684,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
23477
24684
|
],
|
|
23478
24685
|
[
|
|
23479
24686
|
"Schema tab",
|
|
23480
|
-
"Column definitions, indexes, foreign keys, triggers, and DDL."
|
|
24687
|
+
"Column definitions, indexes, foreign keys, triggers, and DDL, with an in-tab refresh action for reloading the current table structure."
|
|
23481
24688
|
],
|
|
23482
24689
|
[
|
|
23483
24690
|
"Query editor",
|
|
@@ -23854,7 +25061,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
23854
25061
|
},
|
|
23855
25062
|
{
|
|
23856
25063
|
kind: "paragraph",
|
|
23857
|
-
text: 'ターミナルからは `code-viewer doctor` で同じレポートを取得できます。AI エージェントや CI からは `--json` で /_doctor と同じ DoctorReport を受け取れます。worstStatus が "error" なら exit code 1 を返すので CI ガードに直接使えます。'
|
|
25064
|
+
text: 'ターミナルからは `code-viewer doctor` で同じレポートを取得できます。AI エージェントや CI からは `--json` で /_doctor と同じ DoctorReport を受け取れます。PATH と別の実行ファイルを使いたい場合は `--bin git=/absolute/path` や `--bin docker=/absolute/path` を指定できます。worstStatus が "error" なら exit code 1 を返すので CI ガードに直接使えます。'
|
|
23858
25065
|
},
|
|
23859
25066
|
{
|
|
23860
25067
|
kind: "command",
|
|
@@ -23865,7 +25072,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
23865
25072
|
kind: "command",
|
|
23866
25073
|
title: "AI / CI 用 doctor JSON",
|
|
23867
25074
|
command: `code-viewer doctor --json
|
|
23868
|
-
code-viewer doctor --cwd /path/to/repo --port 64160 --json
|
|
25075
|
+
code-viewer doctor --cwd /path/to/repo --port 64160 --json
|
|
25076
|
+
code-viewer doctor --bin git=/opt/bin/git --bin docker=/opt/bin/docker --json`
|
|
23869
25077
|
}
|
|
23870
25078
|
]
|
|
23871
25079
|
}
|
|
@@ -24121,7 +25329,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
24121
25329
|
],
|
|
24122
25330
|
[
|
|
24123
25331
|
"Data タブ",
|
|
24124
|
-
"ページネーション付きグリッド。ソート、フィルター、セルコピー、CSV/JSON エクスポート(最大10
|
|
25332
|
+
"ページネーション付きグリッド。ソート、フィルター、セルコピー、CSV/JSON エクスポート(最大10万行、現在のフィルター/ソートを反映)、全体検索と列フィルターを保持した表だけの再読み込みに対応。再読み込み結果はボタン横に表示され、行数変化に気づけます。設定バーで Edit モードを ON にするとインライン編集が可能 — セルをダブルクリックで編集、行操作で挿入/削除を予約、コミット単位で一括適用。未コミットの編集行/セルは黄色でハイライト。"
|
|
24125
25333
|
],
|
|
24126
25334
|
[
|
|
24127
25335
|
"詳細フッタ・関連パネル",
|
|
@@ -24129,7 +25337,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
24129
25337
|
],
|
|
24130
25338
|
[
|
|
24131
25339
|
"Schema タブ",
|
|
24132
|
-
"カラム定義、インデックス、外部キー、トリガー、DDL
|
|
25340
|
+
"カラム定義、インデックス、外部キー、トリガー、DDL。現在の表構造だけを再読み込みするタブ内更新にも対応。"
|
|
24133
25341
|
],
|
|
24134
25342
|
[
|
|
24135
25343
|
"クエリエディター",
|
|
@@ -24801,6 +26009,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
24801
26009
|
const button = document.createElement("button");
|
|
24802
26010
|
button.className = "gdp-expand-btn";
|
|
24803
26011
|
button.title = spec.title;
|
|
26012
|
+
button.setAttribute("aria-label", spec.title);
|
|
24804
26013
|
button.innerHTML = '<svg viewBox="0 0 16 16" width="12" height="12" aria-hidden="true">' + '<path fill="currentColor" d="' + EXPAND_ICON_PATHS[spec.direction] + '"/></svg>';
|
|
24805
26014
|
button.addEventListener("click", (e2) => {
|
|
24806
26015
|
e2.stopPropagation();
|
|
@@ -25139,6 +26348,86 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
25139
26348
|
};
|
|
25140
26349
|
}
|
|
25141
26350
|
|
|
26351
|
+
// web-src/views/quick-help.ts
|
|
26352
|
+
var QUICK_HELP_GROUP_TITLES_EN = ["Global", "Main Panel"];
|
|
26353
|
+
function createQuickHelp(deps) {
|
|
26354
|
+
const popover = deps.$("#quick-help-popover");
|
|
26355
|
+
const trigger = deps.$("#quick-help-btn");
|
|
26356
|
+
const titleEl = deps.$("#quick-help-title");
|
|
26357
|
+
const closeBtn = deps.$("#quick-help-close");
|
|
26358
|
+
const groupsHost = deps.$("#quick-help-groups");
|
|
26359
|
+
const fullLink = deps.$("#quick-help-full-link");
|
|
26360
|
+
function isOpen() {
|
|
26361
|
+
return !popover.hidden;
|
|
26362
|
+
}
|
|
26363
|
+
function renderContent() {
|
|
26364
|
+
groupsHost.innerHTML = "";
|
|
26365
|
+
const groups = buildHelpKeybindingGroups(deps.getLanguage(), undefined, QUICK_HELP_GROUP_TITLES_EN);
|
|
26366
|
+
for (const group of groups) {
|
|
26367
|
+
const section = document.createElement("section");
|
|
26368
|
+
section.className = "gdp-help-group";
|
|
26369
|
+
const title = document.createElement("h3");
|
|
26370
|
+
title.textContent = group.title;
|
|
26371
|
+
section.append(title, renderHelpTable(group.rows));
|
|
26372
|
+
groupsHost.appendChild(section);
|
|
26373
|
+
}
|
|
26374
|
+
}
|
|
26375
|
+
function applyText() {
|
|
26376
|
+
const text2 = deps.getText();
|
|
26377
|
+
titleEl.textContent = text2.panelTitle;
|
|
26378
|
+
popover.setAttribute("aria-label", text2.panelTitle);
|
|
26379
|
+
closeBtn.setAttribute("aria-label", text2.close);
|
|
26380
|
+
fullLink.textContent = text2.viewAll;
|
|
26381
|
+
}
|
|
26382
|
+
function open() {
|
|
26383
|
+
applyText();
|
|
26384
|
+
renderContent();
|
|
26385
|
+
popover.hidden = false;
|
|
26386
|
+
closeBtn.focus();
|
|
26387
|
+
}
|
|
26388
|
+
function close() {
|
|
26389
|
+
if (!isOpen())
|
|
26390
|
+
return;
|
|
26391
|
+
popover.hidden = true;
|
|
26392
|
+
}
|
|
26393
|
+
function toggle() {
|
|
26394
|
+
if (isOpen())
|
|
26395
|
+
close();
|
|
26396
|
+
else
|
|
26397
|
+
open();
|
|
26398
|
+
}
|
|
26399
|
+
trigger.addEventListener("click", toggle);
|
|
26400
|
+
closeBtn.addEventListener("click", close);
|
|
26401
|
+
fullLink.addEventListener("click", (e2) => {
|
|
26402
|
+
e2.preventDefault();
|
|
26403
|
+
close();
|
|
26404
|
+
deps.openFullKeybindings();
|
|
26405
|
+
});
|
|
26406
|
+
document.addEventListener("keydown", (e2) => {
|
|
26407
|
+
if (isImeComposing(e2))
|
|
26408
|
+
return;
|
|
26409
|
+
if (e2.key !== "Escape")
|
|
26410
|
+
return;
|
|
26411
|
+
if (!isOpen())
|
|
26412
|
+
return;
|
|
26413
|
+
close();
|
|
26414
|
+
});
|
|
26415
|
+
document.addEventListener("mousedown", (e2) => {
|
|
26416
|
+
if (!isOpen())
|
|
26417
|
+
return;
|
|
26418
|
+
const target = e2.target;
|
|
26419
|
+
if (popover.contains(target) || trigger.contains(target))
|
|
26420
|
+
return;
|
|
26421
|
+
close();
|
|
26422
|
+
});
|
|
26423
|
+
function localize() {
|
|
26424
|
+
applyText();
|
|
26425
|
+
if (isOpen())
|
|
26426
|
+
renderContent();
|
|
26427
|
+
}
|
|
26428
|
+
return { open, close, toggle, isOpen, localize };
|
|
26429
|
+
}
|
|
26430
|
+
|
|
25142
26431
|
// web-src/views/ref-picker.ts
|
|
25143
26432
|
function createRefPicker(deps) {
|
|
25144
26433
|
function wireRefSelectorInput(input, onPick) {
|
|
@@ -25570,7 +26859,11 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
25570
26859
|
trackLoad,
|
|
25571
26860
|
getRepoSidebarRef,
|
|
25572
26861
|
setRepoSidebarRef,
|
|
25573
|
-
isTestPath
|
|
26862
|
+
isTestPath,
|
|
26863
|
+
sidebarToggleTitle,
|
|
26864
|
+
openDirectoryInOsTitle,
|
|
26865
|
+
omittedDirectoryBadge,
|
|
26866
|
+
commitEntryBadge
|
|
25574
26867
|
} = deps;
|
|
25575
26868
|
const VIRTUAL_SIDEBAR_THRESHOLD = 3000;
|
|
25576
26869
|
const VIRTUAL_SIDEBAR_ROW_HEIGHT = 29;
|
|
@@ -25647,8 +26940,9 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
25647
26940
|
button = createSidebarToggleButton();
|
|
25648
26941
|
bindSidebarToggleButton(button);
|
|
25649
26942
|
button.setAttribute("aria-pressed", STATE.sidebarHidden ? "true" : "false");
|
|
25650
|
-
|
|
25651
|
-
button.
|
|
26943
|
+
const toggleTitle = sidebarToggleTitle(STATE.sidebarHidden);
|
|
26944
|
+
button.title = toggleTitle;
|
|
26945
|
+
button.setAttribute("aria-label", toggleTitle);
|
|
25652
26946
|
syncSidebarToggleIcon(button);
|
|
25653
26947
|
return button;
|
|
25654
26948
|
}
|
|
@@ -25813,12 +27107,13 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
25813
27107
|
if (dir.children_omitted) {
|
|
25814
27108
|
const omitted = document.createElement("span");
|
|
25815
27109
|
omitted.className = "dir-omitted " + (dir.children_omitted_reason === "heavy" ? "dir-omitted-heavy" : "dir-omitted-internal");
|
|
25816
|
-
|
|
25817
|
-
omitted.
|
|
27110
|
+
const badge = omittedDirectoryBadge(dir.children_omitted_reason);
|
|
27111
|
+
omitted.textContent = badge.label;
|
|
27112
|
+
omitted.title = badge.title;
|
|
25818
27113
|
label.appendChild(omitted);
|
|
25819
27114
|
}
|
|
25820
27115
|
li.appendChild(label);
|
|
25821
|
-
li.appendChild(createOpenPathButton(dir.path, "directory",
|
|
27116
|
+
li.appendChild(createOpenPathButton(dir.path, "directory", openDirectoryInOsTitle()));
|
|
25822
27117
|
const collapsed = STATE.collapsedDirs.has(dir.path);
|
|
25823
27118
|
if (collapsed)
|
|
25824
27119
|
li.classList.add("collapsed");
|
|
@@ -25866,40 +27161,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
25866
27161
|
ul.appendChild(childUl);
|
|
25867
27162
|
} else {
|
|
25868
27163
|
const f2 = item.file;
|
|
25869
|
-
const li =
|
|
25870
|
-
li.className = "tree-file";
|
|
25871
|
-
li.tabIndex = -1;
|
|
25872
|
-
li.dataset.path = f2.path;
|
|
25873
|
-
li.dataset.type = "blob";
|
|
25874
|
-
li.classList.toggle("viewed", !onFileClick && STATE.viewedFiles.has(f2.path));
|
|
25875
|
-
li.style.setProperty("--lvl-pad", `${12 + depth * 14}px`);
|
|
25876
|
-
const spacer = document.createElement("span");
|
|
25877
|
-
spacer.className = "chev-spacer";
|
|
25878
|
-
li.appendChild(spacer);
|
|
25879
|
-
if (f2.status) {
|
|
25880
|
-
li.appendChild(fileBadge(f2.status));
|
|
25881
|
-
} else {
|
|
25882
|
-
const icon = document.createElement("span");
|
|
25883
|
-
icon.className = "d2h-icon-wrapper";
|
|
25884
|
-
icon.innerHTML = fileEntryIcon();
|
|
25885
|
-
li.appendChild(icon);
|
|
25886
|
-
}
|
|
25887
|
-
const name = document.createElement("span");
|
|
25888
|
-
name.className = "name";
|
|
25889
|
-
name.textContent = f2.path.split("/").pop();
|
|
25890
|
-
name.title = f2.path;
|
|
25891
|
-
li.appendChild(name);
|
|
25892
|
-
li.addEventListener("click", () => {
|
|
25893
|
-
if (onFileClick)
|
|
25894
|
-
onFileClick(f2);
|
|
25895
|
-
else
|
|
25896
|
-
scrollToFile(f2.path);
|
|
25897
|
-
scheduleMainSurfaceFocus();
|
|
25898
|
-
});
|
|
25899
|
-
if (!onFileClick)
|
|
25900
|
-
li.addEventListener("mouseenter", () => prefetchByPath(f2.path), {
|
|
25901
|
-
passive: true
|
|
25902
|
-
});
|
|
27164
|
+
const li = createTreeFileRow(f2, depth, onFileClick);
|
|
25903
27165
|
ul.appendChild(li);
|
|
25904
27166
|
}
|
|
25905
27167
|
}
|
|
@@ -25983,7 +27245,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
25983
27245
|
order: dir.minOrder + (index + 1) / 1e5,
|
|
25984
27246
|
path: entry.path,
|
|
25985
27247
|
display_path: entry.path,
|
|
25986
|
-
type: entry.type,
|
|
27248
|
+
type: meta.ref === "worktree" && entry.type === "commit" && !entry.submodule ? "tree" : entry.type,
|
|
27249
|
+
submodule: entry.submodule,
|
|
25987
27250
|
children_omitted: entry.children_omitted,
|
|
25988
27251
|
children_omitted_reason: entry.children_omitted_reason
|
|
25989
27252
|
}));
|
|
@@ -26033,12 +27296,13 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
26033
27296
|
if (dir.children_omitted) {
|
|
26034
27297
|
const omitted = document.createElement("span");
|
|
26035
27298
|
omitted.className = "dir-omitted " + (dir.children_omitted_reason === "heavy" ? "dir-omitted-heavy" : "dir-omitted-internal");
|
|
26036
|
-
|
|
26037
|
-
omitted.
|
|
27299
|
+
const badge = omittedDirectoryBadge(dir.children_omitted_reason);
|
|
27300
|
+
omitted.textContent = badge.label;
|
|
27301
|
+
omitted.title = badge.title;
|
|
26038
27302
|
label.appendChild(omitted);
|
|
26039
27303
|
}
|
|
26040
27304
|
li.appendChild(label);
|
|
26041
|
-
li.appendChild(createOpenPathButton(dir.path, "directory",
|
|
27305
|
+
li.appendChild(createOpenPathButton(dir.path, "directory", openDirectoryInOsTitle()));
|
|
26042
27306
|
const updateIcon = () => {
|
|
26043
27307
|
setFolderIcon(dirIcon, li.classList.contains("collapsed"));
|
|
26044
27308
|
};
|
|
@@ -26104,12 +27368,37 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
26104
27368
|
}
|
|
26105
27369
|
return li;
|
|
26106
27370
|
}
|
|
27371
|
+
function fileKindTag(f2) {
|
|
27372
|
+
if (f2.type === "commit") {
|
|
27373
|
+
const badge = commitEntryBadge(f2.submodule);
|
|
27374
|
+
const tag2 = document.createElement("span");
|
|
27375
|
+
tag2.className = `kind-tag ${f2.submodule ? "submodule" : "gitlink"}`;
|
|
27376
|
+
tag2.textContent = badge.label;
|
|
27377
|
+
tag2.title = badge.title;
|
|
27378
|
+
return tag2;
|
|
27379
|
+
}
|
|
27380
|
+
const kind = classifyDiffFileKind(f2);
|
|
27381
|
+
if (!kind.heavy && !kind.binary && !kind.media)
|
|
27382
|
+
return null;
|
|
27383
|
+
const tag = document.createElement("span");
|
|
27384
|
+
const isBinaryLike = kind.binary || kind.media;
|
|
27385
|
+
tag.className = `kind-tag ${isBinaryLike ? "binary" : "heavy"}`;
|
|
27386
|
+
tag.textContent = isBinaryLike ? "B" : "!";
|
|
27387
|
+
tag.title = isBinaryLike ? "binary/media file" : "large diff";
|
|
27388
|
+
return tag;
|
|
27389
|
+
}
|
|
27390
|
+
function sidebarEntryIcon(f2) {
|
|
27391
|
+
return f2.type === "commit" ? iconSvg("octicon-git-branch", GIT_BRANCH_16_PATH) : fileEntryIcon();
|
|
27392
|
+
}
|
|
26107
27393
|
function createTreeFileRow(f2, depth, onFileClick) {
|
|
26108
27394
|
const li = document.createElement("li");
|
|
26109
27395
|
li.className = "tree-file";
|
|
26110
27396
|
li.tabIndex = -1;
|
|
26111
27397
|
li.dataset.path = f2.path;
|
|
26112
|
-
li.dataset.type = "blob";
|
|
27398
|
+
li.dataset.type = f2.type || "blob";
|
|
27399
|
+
if (f2.type === "commit") {
|
|
27400
|
+
li.title = commitEntryBadge(f2.submodule).title;
|
|
27401
|
+
}
|
|
26113
27402
|
li.classList.toggle("viewed", !onFileClick && STATE.viewedFiles.has(f2.path));
|
|
26114
27403
|
li.classList.toggle("hidden-by-tests", STATE.hideTests && !isRepositorySidebarMode() && isTestPath(f2.path || ""));
|
|
26115
27404
|
li.style.setProperty("--lvl-pad", `${12 + depth * 14}px`);
|
|
@@ -26121,7 +27410,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
26121
27410
|
} else {
|
|
26122
27411
|
const icon = document.createElement("span");
|
|
26123
27412
|
icon.className = "d2h-icon-wrapper";
|
|
26124
|
-
icon.innerHTML =
|
|
27413
|
+
icon.innerHTML = sidebarEntryIcon(f2);
|
|
26125
27414
|
li.appendChild(icon);
|
|
26126
27415
|
}
|
|
26127
27416
|
const name = document.createElement("span");
|
|
@@ -26129,6 +27418,9 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
26129
27418
|
name.textContent = f2.path.split("/").pop();
|
|
26130
27419
|
name.title = f2.path;
|
|
26131
27420
|
li.appendChild(name);
|
|
27421
|
+
const kindTag = fileKindTag(f2);
|
|
27422
|
+
if (kindTag)
|
|
27423
|
+
li.appendChild(kindTag);
|
|
26132
27424
|
li.addEventListener("click", () => {
|
|
26133
27425
|
if (onFileClick)
|
|
26134
27426
|
onFileClick(f2);
|
|
@@ -26336,13 +27628,17 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
26336
27628
|
li.tabIndex = -1;
|
|
26337
27629
|
li.dataset.index = String(i2);
|
|
26338
27630
|
li.dataset.path = f2.path;
|
|
27631
|
+
li.dataset.type = f2.type || "blob";
|
|
27632
|
+
if (f2.type === "commit") {
|
|
27633
|
+
li.title = commitEntryBadge(f2.submodule).title;
|
|
27634
|
+
}
|
|
26339
27635
|
li.classList.toggle("viewed", !onFileClick && STATE.viewedFiles.has(f2.path));
|
|
26340
27636
|
if (f2.status) {
|
|
26341
27637
|
li.appendChild(fileBadge(f2.status));
|
|
26342
27638
|
} else {
|
|
26343
27639
|
const icon = document.createElement("span");
|
|
26344
27640
|
icon.className = "d2h-icon-wrapper";
|
|
26345
|
-
icon.innerHTML =
|
|
27641
|
+
icon.innerHTML = sidebarEntryIcon(f2);
|
|
26346
27642
|
li.appendChild(icon);
|
|
26347
27643
|
}
|
|
26348
27644
|
const name = document.createElement("span");
|
|
@@ -26350,6 +27646,9 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
26350
27646
|
name.textContent = f2.path;
|
|
26351
27647
|
name.title = f2.path;
|
|
26352
27648
|
li.appendChild(name);
|
|
27649
|
+
const kindTag = fileKindTag(f2);
|
|
27650
|
+
if (kindTag)
|
|
27651
|
+
li.appendChild(kindTag);
|
|
26353
27652
|
li.addEventListener("click", () => {
|
|
26354
27653
|
if (onFileClick)
|
|
26355
27654
|
onFileClick(f2);
|
|
@@ -26517,6 +27816,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
26517
27816
|
}
|
|
26518
27817
|
function applyFilter() {
|
|
26519
27818
|
const input = $("#sb-filter");
|
|
27819
|
+
syncSidebarFilterClearButton();
|
|
26520
27820
|
if ($("#filelist").classList.contains("tree-virtual")) {
|
|
26521
27821
|
rerenderVirtualSidebar();
|
|
26522
27822
|
return;
|
|
@@ -26582,6 +27882,23 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
26582
27882
|
SIDEBAR_FILTER_RAF = 0;
|
|
26583
27883
|
applyFilter();
|
|
26584
27884
|
}
|
|
27885
|
+
function syncSidebarFilterClearButton() {
|
|
27886
|
+
const input = document.querySelector("#sb-filter");
|
|
27887
|
+
const button = document.querySelector("#sb-filter-clear");
|
|
27888
|
+
if (!input || !button)
|
|
27889
|
+
return;
|
|
27890
|
+
button.hidden = input.value.length === 0;
|
|
27891
|
+
}
|
|
27892
|
+
function clearSidebarFilter() {
|
|
27893
|
+
const input = document.querySelector("#sb-filter");
|
|
27894
|
+
if (!input?.value)
|
|
27895
|
+
return;
|
|
27896
|
+
input.value = "";
|
|
27897
|
+
syncSidebarFilterClearButton();
|
|
27898
|
+
flushSidebarFilter();
|
|
27899
|
+
applyFilter();
|
|
27900
|
+
input.focus();
|
|
27901
|
+
}
|
|
26585
27902
|
function applySidebarWidth(w, options = {}) {
|
|
26586
27903
|
const cw = Math.max(180, Math.min(900, w));
|
|
26587
27904
|
document.documentElement.style.setProperty("--sidebar-w", `${cw}px`);
|
|
@@ -26917,6 +28234,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
26917
28234
|
applyFilter,
|
|
26918
28235
|
scheduleApplyFilter,
|
|
26919
28236
|
flushSidebarFilter,
|
|
28237
|
+
syncSidebarFilterClearButton,
|
|
28238
|
+
clearSidebarFilter,
|
|
26920
28239
|
markActive,
|
|
26921
28240
|
rerenderVirtualSidebar,
|
|
26922
28241
|
ensureVirtualSidebarDirLoaded,
|
|
@@ -27002,7 +28321,19 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27002
28321
|
syncHeaderMenu,
|
|
27003
28322
|
getSidebarRowByPath,
|
|
27004
28323
|
getSidebarVirtualActivePath,
|
|
27005
|
-
pushUndo
|
|
28324
|
+
pushUndo,
|
|
28325
|
+
newFolderButtonTitle,
|
|
28326
|
+
openDirectoryInOsTitle,
|
|
28327
|
+
moveFolderToTrashTitle,
|
|
28328
|
+
uploadButtonLabel,
|
|
28329
|
+
dropFilesIntoCopy,
|
|
28330
|
+
uploadFailedMessage,
|
|
28331
|
+
emptyDirectoryLabel,
|
|
28332
|
+
uploadConfirmText,
|
|
28333
|
+
sortColumnLabels,
|
|
28334
|
+
repositoryFallback,
|
|
28335
|
+
repositoryRootFallback,
|
|
28336
|
+
commitEntryMeta
|
|
27006
28337
|
} = deps;
|
|
27007
28338
|
let REPO_SORT = {
|
|
27008
28339
|
key: "name",
|
|
@@ -27045,6 +28376,15 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27045
28376
|
function fileEntryIcon() {
|
|
27046
28377
|
return iconSvg("octicon-file", FILE_16_PATH);
|
|
27047
28378
|
}
|
|
28379
|
+
function commitEntryIcon() {
|
|
28380
|
+
return iconSvg("octicon-git-branch", GIT_BRANCH_16_PATH);
|
|
28381
|
+
}
|
|
28382
|
+
function isWorktreeRef(ref) {
|
|
28383
|
+
return canTrashWorktreeRef(ref);
|
|
28384
|
+
}
|
|
28385
|
+
function canBrowseRepoEntry(entry, ref) {
|
|
28386
|
+
return entry.type === "tree" || entry.type === "commit" && isWorktreeRef(ref) && !entry.submodule;
|
|
28387
|
+
}
|
|
27048
28388
|
function closeRepoContextMenu() {
|
|
27049
28389
|
document.querySelector(".gdp-context-menu")?.remove();
|
|
27050
28390
|
}
|
|
@@ -27223,8 +28563,9 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27223
28563
|
const button = document.createElement("button");
|
|
27224
28564
|
button.type = "button";
|
|
27225
28565
|
button.className = "gdp-file-header-icon gdp-trash-path";
|
|
27226
|
-
|
|
27227
|
-
button.
|
|
28566
|
+
const trashTitle = moveFolderToTrashTitle();
|
|
28567
|
+
button.title = trashTitle;
|
|
28568
|
+
button.setAttribute("aria-label", trashTitle);
|
|
27228
28569
|
button.innerHTML = iconSvg("octicon-trash", TRASH_16_PATH);
|
|
27229
28570
|
button.addEventListener("click", async (event) => {
|
|
27230
28571
|
event.stopPropagation();
|
|
@@ -27236,8 +28577,9 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27236
28577
|
const button = document.createElement("button");
|
|
27237
28578
|
button.type = "button";
|
|
27238
28579
|
button.className = "gdp-file-header-icon gdp-create-dir";
|
|
27239
|
-
|
|
27240
|
-
button.
|
|
28580
|
+
const newFolderTitle = newFolderButtonTitle();
|
|
28581
|
+
button.title = newFolderTitle;
|
|
28582
|
+
button.setAttribute("aria-label", newFolderTitle);
|
|
27241
28583
|
button.innerHTML = iconSvg("octicon-plus", PLUS_16_PATH);
|
|
27242
28584
|
button.addEventListener("click", async (event) => {
|
|
27243
28585
|
event.stopPropagation();
|
|
@@ -27252,7 +28594,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27252
28594
|
dropPanel.className = "gdp-upload-panel";
|
|
27253
28595
|
const copy = document.createElement("div");
|
|
27254
28596
|
copy.className = "gdp-upload-copy";
|
|
27255
|
-
copy.textContent =
|
|
28597
|
+
copy.textContent = dropFilesIntoCopy(path || getProjectName() || repositoryFallback());
|
|
27256
28598
|
const input = document.createElement("input");
|
|
27257
28599
|
input.type = "file";
|
|
27258
28600
|
input.multiple = true;
|
|
@@ -27260,11 +28602,11 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27260
28602
|
const button = document.createElement("button");
|
|
27261
28603
|
button.type = "button";
|
|
27262
28604
|
button.className = "gdp-btn gdp-btn-sm";
|
|
27263
|
-
button.textContent =
|
|
28605
|
+
button.textContent = uploadButtonLabel();
|
|
27264
28606
|
button.addEventListener("click", () => input.click());
|
|
27265
28607
|
const error2 = document.createElement("div");
|
|
27266
28608
|
error2.className = "gdp-upload-error";
|
|
27267
|
-
const fail = (message =
|
|
28609
|
+
const fail = (message = uploadFailedMessage()) => {
|
|
27268
28610
|
error2.textContent = message;
|
|
27269
28611
|
dropPanel.classList.add("failed");
|
|
27270
28612
|
setTimeout(() => dropPanel.classList.remove("failed"), 1600);
|
|
@@ -27275,7 +28617,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27275
28617
|
await uploadFiles(path, input.files);
|
|
27276
28618
|
error2.textContent = "";
|
|
27277
28619
|
} catch (uploadError) {
|
|
27278
|
-
fail(uploadError instanceof Error ? uploadError.message :
|
|
28620
|
+
fail(uploadError instanceof Error ? uploadError.message : uploadFailedMessage());
|
|
27279
28621
|
} finally {
|
|
27280
28622
|
input.value = "";
|
|
27281
28623
|
}
|
|
@@ -27294,7 +28636,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27294
28636
|
await uploadFiles(path, files);
|
|
27295
28637
|
error2.textContent = "";
|
|
27296
28638
|
} catch (uploadError) {
|
|
27297
|
-
fail(uploadError instanceof Error ? uploadError.message :
|
|
28639
|
+
fail(uploadError instanceof Error ? uploadError.message : uploadFailedMessage());
|
|
27298
28640
|
}
|
|
27299
28641
|
});
|
|
27300
28642
|
dropPanel.append(copy, button, input, error2);
|
|
@@ -27314,7 +28656,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27314
28656
|
const root = document.createElement("button");
|
|
27315
28657
|
root.type = "button";
|
|
27316
28658
|
root.className = path ? "gdp-file-breadcrumb-part" : "gdp-file-breadcrumb-current";
|
|
27317
|
-
root.textContent = getProjectName() ||
|
|
28659
|
+
root.textContent = getProjectName() || repositoryFallback();
|
|
27318
28660
|
root.addEventListener("click", () => {
|
|
27319
28661
|
setRoute(repoRoute(target, ""));
|
|
27320
28662
|
loadRepo();
|
|
@@ -27361,7 +28703,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27361
28703
|
pathHeader.appendChild(createRepoBreadcrumb(meta.ref, meta.path || ""));
|
|
27362
28704
|
if (meta.path)
|
|
27363
28705
|
pathHeader.appendChild(createCopyPathButton(meta.path));
|
|
27364
|
-
pathHeader.appendChild(createOpenPathButton(meta.path || "", "directory",
|
|
28706
|
+
pathHeader.appendChild(createOpenPathButton(meta.path || "", "directory", openDirectoryInOsTitle()));
|
|
27365
28707
|
toolbar.appendChild(pathHeader);
|
|
27366
28708
|
if (canTrashWorktreeRef(meta.ref)) {
|
|
27367
28709
|
toolbar.appendChild(createNewFolderButton(meta.path || "", () => loadRepo()));
|
|
@@ -27414,24 +28756,30 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27414
28756
|
});
|
|
27415
28757
|
list2.appendChild(row);
|
|
27416
28758
|
}
|
|
27417
|
-
sortedRepoEntries(meta.entries).forEach((entry) => {
|
|
28759
|
+
sortedRepoEntries(meta.entries, meta.ref).forEach((entry) => {
|
|
28760
|
+
const browsable = canBrowseRepoEntry(entry, meta.ref);
|
|
28761
|
+
const nonBrowsableCommit = entry.type === "commit" && !browsable;
|
|
27418
28762
|
const row = document.createElement("button");
|
|
27419
28763
|
row.type = "button";
|
|
27420
|
-
row.className = `gdp-repo-row ${entry.type}`;
|
|
28764
|
+
row.className = nonBrowsableCommit ? `gdp-repo-row ${entry.type} gdp-repo-row-gitlink` : `gdp-repo-row ${entry.type}`;
|
|
27421
28765
|
const icon = document.createElement("span");
|
|
27422
|
-
icon.className =
|
|
27423
|
-
if (
|
|
28766
|
+
icon.className = browsable ? "dir-icon" : nonBrowsableCommit ? "d2h-icon-wrapper gdp-repo-row-gitlink-icon" : "d2h-icon-wrapper";
|
|
28767
|
+
if (browsable)
|
|
27424
28768
|
setFolderIcon(icon, true);
|
|
27425
28769
|
else
|
|
27426
|
-
icon.innerHTML = fileEntryIcon();
|
|
28770
|
+
icon.innerHTML = entry.type === "commit" ? commitEntryIcon() : fileEntryIcon();
|
|
27427
28771
|
const name = document.createElement("span");
|
|
27428
28772
|
name.className = "name";
|
|
27429
28773
|
name.textContent = entry.name;
|
|
27430
|
-
|
|
28774
|
+
if (nonBrowsableCommit) {
|
|
28775
|
+
row.title = commitEntryMeta(entry.submodule).title;
|
|
28776
|
+
row.setAttribute("aria-disabled", "true");
|
|
28777
|
+
}
|
|
28778
|
+
const metaBlock = createRepoEntryMeta(entry, browsable);
|
|
27431
28779
|
const size = createRepoEntrySize(entry);
|
|
27432
28780
|
row.append(icon, name, metaBlock, size);
|
|
27433
28781
|
row.addEventListener("click", () => {
|
|
27434
|
-
if (
|
|
28782
|
+
if (browsable) {
|
|
27435
28783
|
setRoute(repoRoute(meta.ref, entry.path));
|
|
27436
28784
|
loadRepo();
|
|
27437
28785
|
} else if (entry.type === "blob") {
|
|
@@ -27451,7 +28799,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27451
28799
|
if (!meta.entries.length) {
|
|
27452
28800
|
const empty = document.createElement("div");
|
|
27453
28801
|
empty.className = "gdp-repo-empty";
|
|
27454
|
-
empty.textContent =
|
|
28802
|
+
empty.textContent = emptyDirectoryLabel();
|
|
27455
28803
|
list2.appendChild(empty);
|
|
27456
28804
|
}
|
|
27457
28805
|
};
|
|
@@ -27538,7 +28886,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27538
28886
|
order: index + 1,
|
|
27539
28887
|
path: entry.path,
|
|
27540
28888
|
display_path: entry.path,
|
|
27541
|
-
type: entry.type,
|
|
28889
|
+
type: canBrowseRepoEntry(entry, normalizedRef) ? "tree" : entry.type,
|
|
28890
|
+
submodule: entry.submodule,
|
|
27542
28891
|
children_omitted: entry.children_omitted,
|
|
27543
28892
|
children_omitted_reason: entry.children_omitted_reason
|
|
27544
28893
|
}));
|
|
@@ -27601,12 +28950,19 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27601
28950
|
}
|
|
27602
28951
|
});
|
|
27603
28952
|
}
|
|
27604
|
-
function createRepoEntryMeta(entry) {
|
|
28953
|
+
function createRepoEntryMeta(entry, browsable) {
|
|
27605
28954
|
const meta = document.createElement("span");
|
|
27606
28955
|
meta.className = "meta";
|
|
28956
|
+
if (entry.type === "commit" && !browsable) {
|
|
28957
|
+
meta.classList.add("gdp-repo-row-gitlink-badge");
|
|
28958
|
+
const badge = commitEntryMeta(entry.submodule);
|
|
28959
|
+
meta.textContent = badge.label;
|
|
28960
|
+
meta.title = badge.title;
|
|
28961
|
+
return meta;
|
|
28962
|
+
}
|
|
27607
28963
|
const updated = formatFileDate(entry.updated_at || entry.commit_updated_at);
|
|
27608
28964
|
const created = formatFileDate(entry.created_at);
|
|
27609
|
-
if (
|
|
28965
|
+
if (browsable && updated) {
|
|
27610
28966
|
meta.textContent = updated;
|
|
27611
28967
|
if (created)
|
|
27612
28968
|
meta.title = `Created ${created}`;
|
|
@@ -27634,13 +28990,15 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27634
28990
|
const time = new Date(raw).getTime();
|
|
27635
28991
|
return Number.isNaN(time) ? -1 : time;
|
|
27636
28992
|
}
|
|
27637
|
-
function sortedRepoEntries(entries) {
|
|
28993
|
+
function sortedRepoEntries(entries, ref = "worktree") {
|
|
27638
28994
|
const direction = REPO_SORT.direction === "asc" ? 1 : -1;
|
|
27639
28995
|
return [...entries].sort((a2, b2) => {
|
|
27640
|
-
|
|
27641
|
-
|
|
28996
|
+
const aBrowsable = canBrowseRepoEntry(a2, ref);
|
|
28997
|
+
const bBrowsable = canBrowseRepoEntry(b2, ref);
|
|
28998
|
+
if (REPO_SORT.key === "name" && aBrowsable !== bBrowsable) {
|
|
28999
|
+
if (aBrowsable)
|
|
27642
29000
|
return -1;
|
|
27643
|
-
if (
|
|
29001
|
+
if (bBrowsable)
|
|
27644
29002
|
return 1;
|
|
27645
29003
|
}
|
|
27646
29004
|
let result = 0;
|
|
@@ -27672,10 +29030,11 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27672
29030
|
const spacer = document.createElement("span");
|
|
27673
29031
|
spacer.className = "gdp-repo-sort-spacer";
|
|
27674
29032
|
header.appendChild(spacer);
|
|
29033
|
+
const sortLabels = sortColumnLabels();
|
|
27675
29034
|
const columns = [
|
|
27676
|
-
{ key: "name", label:
|
|
27677
|
-
{ key: "updated", label:
|
|
27678
|
-
{ key: "size", label:
|
|
29035
|
+
{ key: "name", label: sortLabels.name },
|
|
29036
|
+
{ key: "updated", label: sortLabels.updated },
|
|
29037
|
+
{ key: "size", label: sortLabels.size }
|
|
27679
29038
|
];
|
|
27680
29039
|
columns.forEach((column) => {
|
|
27681
29040
|
const button = document.createElement("button");
|
|
@@ -27798,11 +29157,12 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
27798
29157
|
const list2 = Array.from(files);
|
|
27799
29158
|
if (!list2.length)
|
|
27800
29159
|
return;
|
|
27801
|
-
const label = path || getProjectName() ||
|
|
29160
|
+
const label = path || getProjectName() || repositoryRootFallback();
|
|
29161
|
+
const confirmText = uploadConfirmText(list2.length, label);
|
|
27802
29162
|
const ok = await showConfirmDialog({
|
|
27803
|
-
title:
|
|
27804
|
-
body:
|
|
27805
|
-
confirmLabel:
|
|
29163
|
+
title: confirmText.title,
|
|
29164
|
+
body: confirmText.body,
|
|
29165
|
+
confirmLabel: confirmText.confirmLabel
|
|
27806
29166
|
});
|
|
27807
29167
|
if (!ok)
|
|
27808
29168
|
return;
|
|
@@ -30176,13 +31536,20 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30176
31536
|
const loadBar = document.querySelector("#load-bar");
|
|
30177
31537
|
if (loadBar)
|
|
30178
31538
|
loadBar.classList.toggle("active", state.inFlight > 0);
|
|
31539
|
+
const text2 = uiText().global;
|
|
31540
|
+
const statusEl = document.querySelector("#status");
|
|
31541
|
+
if (statusEl) {
|
|
31542
|
+
statusEl.title = state.inFlight > 0 ? text2.statusInFlightTitle(state.inFlight, state.cancellable) : statusEl.querySelector(".status-label")?.textContent ?? "";
|
|
31543
|
+
}
|
|
30179
31544
|
const cancelButton = document.querySelector("#cancel-requests");
|
|
30180
31545
|
if (!cancelButton)
|
|
30181
31546
|
return;
|
|
30182
31547
|
const cancellable = state.cancellable > 0;
|
|
30183
31548
|
cancelButton.disabled = !cancellable;
|
|
30184
31549
|
cancelButton.classList.toggle("active", cancellable);
|
|
30185
|
-
|
|
31550
|
+
const cancelTitle = cancellable ? text2.cancelRequestsActiveTitle(state.cancellable) : text2.cancelRequestsInactiveTitle;
|
|
31551
|
+
cancelButton.title = cancelTitle;
|
|
31552
|
+
cancelButton.setAttribute("aria-label", cancelTitle);
|
|
30186
31553
|
}
|
|
30187
31554
|
function cancelInFlightRequests() {
|
|
30188
31555
|
NETWORK_ACTIVITY.cancelAll();
|
|
@@ -30695,13 +32062,31 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30695
32062
|
setRepoSidebarRef: (ref) => {
|
|
30696
32063
|
REPO_SIDEBAR_REF = ref;
|
|
30697
32064
|
},
|
|
30698
|
-
isTestPath: (path) => TEST_RE.test(path)
|
|
32065
|
+
isTestPath: (path) => TEST_RE.test(path),
|
|
32066
|
+
sidebarToggleTitle: (hidden) => hidden ? uiText().sidebar.show : uiText().sidebar.hide,
|
|
32067
|
+
openDirectoryInOsTitle: () => uiText().sidebar.openDirectoryInOs,
|
|
32068
|
+
omittedDirectoryBadge: (reason) => {
|
|
32069
|
+
const text2 = uiText().sidebar;
|
|
32070
|
+
return reason === "heavy" ? { label: text2.omittedHeavyLabel, title: text2.omittedHeavyTitle } : { label: text2.omittedPrivateLabel, title: text2.omittedPrivateTitle };
|
|
32071
|
+
},
|
|
32072
|
+
commitEntryBadge: (submodule) => {
|
|
32073
|
+
const text2 = uiText().sidebar;
|
|
32074
|
+
return submodule ? {
|
|
32075
|
+
label: text2.commitEntrySubmoduleLabel,
|
|
32076
|
+
title: text2.commitEntrySubmoduleTitle
|
|
32077
|
+
} : {
|
|
32078
|
+
label: text2.commitEntryGitlinkLabel,
|
|
32079
|
+
title: text2.commitEntryGitlinkTitle
|
|
32080
|
+
};
|
|
32081
|
+
}
|
|
30699
32082
|
});
|
|
30700
32083
|
const {
|
|
30701
32084
|
renderSidebar,
|
|
30702
32085
|
applyFilter,
|
|
30703
32086
|
scheduleApplyFilter,
|
|
30704
32087
|
flushSidebarFilter,
|
|
32088
|
+
syncSidebarFilterClearButton,
|
|
32089
|
+
clearSidebarFilter,
|
|
30705
32090
|
markActive,
|
|
30706
32091
|
rerenderVirtualSidebar,
|
|
30707
32092
|
ensureVirtualSidebarDirLoaded,
|
|
@@ -30838,6 +32223,35 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30838
32223
|
getSidebarVirtualActivePath,
|
|
30839
32224
|
pushUndo: (undo) => {
|
|
30840
32225
|
UNDO_STACK.unshift(undo);
|
|
32226
|
+
},
|
|
32227
|
+
newFolderButtonTitle: () => uiText().repo.newFolder,
|
|
32228
|
+
openDirectoryInOsTitle: () => uiText().sidebar.openDirectoryInOs,
|
|
32229
|
+
moveFolderToTrashTitle: () => uiText().repo.moveFolderToTrash,
|
|
32230
|
+
uploadButtonLabel: () => uiText().repo.uploadButton,
|
|
32231
|
+
dropFilesIntoCopy: (target) => uiText().repo.dropFilesInto(target),
|
|
32232
|
+
uploadFailedMessage: () => uiText().repo.uploadFailed,
|
|
32233
|
+
emptyDirectoryLabel: () => uiText().repo.emptyDirectory,
|
|
32234
|
+
uploadConfirmText: (count, target) => {
|
|
32235
|
+
const text2 = uiText().repo;
|
|
32236
|
+
return {
|
|
32237
|
+
title: text2.uploadConfirmTitle,
|
|
32238
|
+
body: text2.uploadConfirmBody(count, target),
|
|
32239
|
+
confirmLabel: text2.uploadConfirmLabel
|
|
32240
|
+
};
|
|
32241
|
+
},
|
|
32242
|
+
sortColumnLabels: () => {
|
|
32243
|
+
const text2 = uiText().repo;
|
|
32244
|
+
return {
|
|
32245
|
+
name: text2.sortName,
|
|
32246
|
+
updated: text2.sortUpdated,
|
|
32247
|
+
size: text2.sortSize
|
|
32248
|
+
};
|
|
32249
|
+
},
|
|
32250
|
+
repositoryFallback: () => uiText().repo.repositoryFallback,
|
|
32251
|
+
repositoryRootFallback: () => uiText().repo.repositoryRootFallback,
|
|
32252
|
+
commitEntryMeta: (submodule) => {
|
|
32253
|
+
const text2 = uiText().repo;
|
|
32254
|
+
return submodule ? { label: text2.submoduleLabel, title: text2.submoduleTitle } : { label: text2.gitlinkLabel, title: text2.gitlinkTitle };
|
|
30841
32255
|
}
|
|
30842
32256
|
});
|
|
30843
32257
|
const {
|
|
@@ -30880,10 +32294,20 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30880
32294
|
theme: "toggle theme",
|
|
30881
32295
|
product: "code viewer",
|
|
30882
32296
|
copyAiContext: "Copy AI context (Shift+Click to include code)",
|
|
32297
|
+
copyAiContextLabel: "AI context",
|
|
30883
32298
|
copyAiContextCopied: "Copied AI context",
|
|
30884
32299
|
copyAiContextCopiedWithCode: (lines) => `Copied AI context + code (${lines} line${lines === 1 ? "" : "s"})`,
|
|
30885
32300
|
copyAiContextFailed: "Copy failed",
|
|
30886
|
-
copyAiContextEmpty: "Nothing to copy here"
|
|
32301
|
+
copyAiContextEmpty: "Nothing to copy here",
|
|
32302
|
+
statusLive: "Live",
|
|
32303
|
+
statusLoading: "Loading",
|
|
32304
|
+
statusError: "Error",
|
|
32305
|
+
statusIdle: "Idle",
|
|
32306
|
+
statusInFlightTitle: (count, cancellable) => `${count} request${count === 1 ? "" : "s"} in flight${cancellable > 0 ? " (cancellable)" : ""}`,
|
|
32307
|
+
cancelRequestsActiveTitle: (count) => `cancel ${count} in-flight request${count === 1 ? "" : "s"}`,
|
|
32308
|
+
cancelRequestsInactiveTitle: "no in-flight requests",
|
|
32309
|
+
brandHome: "Repository home",
|
|
32310
|
+
menuViews: "Views"
|
|
30887
32311
|
},
|
|
30888
32312
|
topbar: {
|
|
30889
32313
|
resetRange: "reset to HEAD .. worktree",
|
|
@@ -30892,6 +32316,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30892
32316
|
unified: "unified",
|
|
30893
32317
|
split: "split",
|
|
30894
32318
|
ignoreWs: "ignore whitespace changes (-w)",
|
|
32319
|
+
ignoreWsLabel: "ws",
|
|
30895
32320
|
syntaxLoading: "loading...",
|
|
30896
32321
|
syntaxOn: "syntax on",
|
|
30897
32322
|
syntaxOff: "syntax off",
|
|
@@ -30900,10 +32325,38 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30900
32325
|
syntaxErrorTitle: "failed to load syntax highlighter",
|
|
30901
32326
|
syntaxOffTitle: "syntax highlighting off",
|
|
30902
32327
|
hideTests: "hide test files (test|spec)",
|
|
32328
|
+
hideTestsLabel: "no test",
|
|
30903
32329
|
autoUpdate: "auto",
|
|
30904
32330
|
autoUpdateOnTitle: "auto update on file change",
|
|
30905
32331
|
autoUpdateOffTitle: "auto update off — manual reload"
|
|
30906
32332
|
},
|
|
32333
|
+
diff: {
|
|
32334
|
+
files: (count) => `${count} file${count === 1 ? "" : "s"}`,
|
|
32335
|
+
updated: (time) => `updated ${time}`,
|
|
32336
|
+
updatedTitle: "last updated",
|
|
32337
|
+
kindAdded: "added",
|
|
32338
|
+
kindDeleted: "deleted",
|
|
32339
|
+
kindRenamed: "renamed",
|
|
32340
|
+
kindHeavy: "heavy",
|
|
32341
|
+
kindBinary: "binary",
|
|
32342
|
+
kindMedia: "media",
|
|
32343
|
+
viewedProgress: (viewed, total) => `${viewed}/${total} viewed`,
|
|
32344
|
+
viewedProgressTitle: "review progress",
|
|
32345
|
+
nextUnviewed: "next unviewed",
|
|
32346
|
+
nextUnviewedTitle: "Jump to the next unviewed file (n)",
|
|
32347
|
+
allViewed: "all viewed",
|
|
32348
|
+
allViewedTitle: "All visible files are viewed",
|
|
32349
|
+
noChangesTitle: "No changes",
|
|
32350
|
+
noChangesBody: "The working tree is clean against this ref.",
|
|
32351
|
+
noChangesReload: "Reload diff",
|
|
32352
|
+
noChangesReloadTitle: "Reload this diff range",
|
|
32353
|
+
noChangesHistory: "Open history",
|
|
32354
|
+
noChangesHistoryTitle: "Open commit history for this range",
|
|
32355
|
+
emptyDiffTitle: "Empty diff",
|
|
32356
|
+
emptyDiffBody: "This commit has no changes against its first parent.",
|
|
32357
|
+
noCommitSelectedTitle: "No commit selected",
|
|
32358
|
+
noCommitSelectedBody: "Select a commit from the list to see its changes."
|
|
32359
|
+
},
|
|
30907
32360
|
changeBanner: {
|
|
30908
32361
|
text: "Files changed",
|
|
30909
32362
|
reload: "Reload",
|
|
@@ -30923,14 +32376,56 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30923
32376
|
view: "view",
|
|
30924
32377
|
tree: "tree",
|
|
30925
32378
|
flat: "flat",
|
|
32379
|
+
treeTitle: "tree view",
|
|
32380
|
+
flatTitle: "flat list",
|
|
30926
32381
|
filter: "Filter files… / ⌘K",
|
|
30927
32382
|
filterTitle: "Filter files. Use /pattern/ for regex. Press / to focus this field, Cmd/Ctrl+K for the full-file palette, Ctrl+G for grep, ? for help.",
|
|
30928
|
-
|
|
32383
|
+
filterClear: "Clear",
|
|
32384
|
+
filterClearTitle: "Clear file filter",
|
|
32385
|
+
hide: "hide sidebar",
|
|
32386
|
+
show: "show sidebar",
|
|
32387
|
+
repoTarget: "repository target",
|
|
32388
|
+
openDirectoryInOs: "open this folder in OS",
|
|
32389
|
+
omittedHeavyLabel: "skipped",
|
|
32390
|
+
omittedHeavyTitle: "Tree expansion is skipped, but the directory detail can be opened",
|
|
32391
|
+
omittedPrivateLabel: "private",
|
|
32392
|
+
omittedPrivateTitle: "This directory cannot be opened from the browser",
|
|
32393
|
+
commitEntryGitlinkLabel: "GIT",
|
|
32394
|
+
commitEntryGitlinkTitle: "Git commit entry",
|
|
32395
|
+
commitEntrySubmoduleLabel: "SUB",
|
|
32396
|
+
commitEntrySubmoduleTitle: "Git submodule pinned to a commit"
|
|
32397
|
+
},
|
|
32398
|
+
repo: {
|
|
32399
|
+
newFolder: "new folder",
|
|
32400
|
+
moveFolderToTrash: "move folder to Trash",
|
|
32401
|
+
uploadButton: "Upload files",
|
|
32402
|
+
dropFilesInto: (target) => `Drop files into ${target}`,
|
|
32403
|
+
uploadFailed: "Upload failed",
|
|
32404
|
+
emptyDirectory: "No files in this directory.",
|
|
32405
|
+
uploadConfirmTitle: "Upload files?",
|
|
32406
|
+
uploadConfirmBody: (count, target) => `Upload ${count} file${count === 1 ? "" : "s"} into ${target}?`,
|
|
32407
|
+
uploadConfirmLabel: "Upload",
|
|
32408
|
+
sortName: "Name",
|
|
32409
|
+
sortUpdated: "Updated",
|
|
32410
|
+
sortSize: "Size",
|
|
32411
|
+
repositoryFallback: "repository",
|
|
32412
|
+
repositoryRootFallback: "repository root",
|
|
32413
|
+
gitlinkLabel: "gitlink",
|
|
32414
|
+
gitlinkTitle: "Git commit entry is not directly browsable at this ref",
|
|
32415
|
+
submoduleLabel: "submodule",
|
|
32416
|
+
submoduleTitle: "Git submodule pinned to a commit"
|
|
30929
32417
|
},
|
|
30930
32418
|
history: {
|
|
30931
32419
|
title: "Commits",
|
|
30932
32420
|
filter: "Filter commits...",
|
|
30933
|
-
filterTitle: "Filter commits by message, SHA, author:name, or path:file."
|
|
32421
|
+
filterTitle: "Filter commits by message, SHA, author:name, or path:file.",
|
|
32422
|
+
refreshTitle: "Refresh commit history"
|
|
32423
|
+
},
|
|
32424
|
+
quickHelp: {
|
|
32425
|
+
buttonTitle: "quick help (shortcuts)",
|
|
32426
|
+
panelTitle: "Quick Help",
|
|
32427
|
+
close: "close quick help",
|
|
32428
|
+
viewAll: "View all keybindings →"
|
|
30934
32429
|
},
|
|
30935
32430
|
settings: {
|
|
30936
32431
|
title: "Viewer Settings",
|
|
@@ -30991,30 +32486,69 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30991
32486
|
theme: "テーマ切り替え",
|
|
30992
32487
|
product: "code viewer",
|
|
30993
32488
|
copyAiContext: "AI 用コンテキストをコピー(Shift+Click でコードも添付)",
|
|
32489
|
+
copyAiContextLabel: "AI文脈",
|
|
30994
32490
|
copyAiContextCopied: "コピーしました",
|
|
30995
32491
|
copyAiContextCopiedWithCode: (lines) => `コピーしました(コード付き・${lines}行)`,
|
|
30996
32492
|
copyAiContextFailed: "コピーに失敗しました",
|
|
30997
|
-
copyAiContextEmpty: "コピーする内容がありません"
|
|
32493
|
+
copyAiContextEmpty: "コピーする内容がありません",
|
|
32494
|
+
statusLive: "稼働中",
|
|
32495
|
+
statusLoading: "更新中",
|
|
32496
|
+
statusError: "エラー",
|
|
32497
|
+
statusIdle: "待機中",
|
|
32498
|
+
statusInFlightTitle: (count, cancellable) => `${count}件のリクエストを実行中${cancellable > 0 ? "(キャンセル可能)" : ""}`,
|
|
32499
|
+
cancelRequestsActiveTitle: (count) => `実行中のリクエストを${count}件キャンセル`,
|
|
32500
|
+
cancelRequestsInactiveTitle: "実行中のリクエストはありません",
|
|
32501
|
+
brandHome: "リポジトリホーム",
|
|
32502
|
+
menuViews: "ビュー切り替え"
|
|
30998
32503
|
},
|
|
30999
32504
|
topbar: {
|
|
31000
32505
|
resetRange: "HEAD .. worktree に戻す",
|
|
31001
32506
|
reload: "diff を再読み込み (R)",
|
|
31002
32507
|
layout: "レイアウト",
|
|
31003
|
-
unified: "
|
|
31004
|
-
split: "
|
|
32508
|
+
unified: "統合",
|
|
32509
|
+
split: "分割",
|
|
31005
32510
|
ignoreWs: "空白差分を無視 (-w)",
|
|
32511
|
+
ignoreWsLabel: "空白",
|
|
31006
32512
|
syntaxLoading: "読み込み中...",
|
|
31007
|
-
syntaxOn: "
|
|
31008
|
-
syntaxOff: "
|
|
32513
|
+
syntaxOn: "構文あり",
|
|
32514
|
+
syntaxOff: "構文なし",
|
|
31009
32515
|
syntaxOnTitle: "シンタックスハイライト有効",
|
|
31010
32516
|
syntaxLoadingTitle: "シンタックスハイライトを読み込み中",
|
|
31011
32517
|
syntaxErrorTitle: "シンタックスハイライトの読み込みに失敗",
|
|
31012
32518
|
syntaxOffTitle: "シンタックスハイライト無効",
|
|
31013
32519
|
hideTests: "test/spec ファイルを隠す",
|
|
32520
|
+
hideTestsLabel: "テスト非表示",
|
|
31014
32521
|
autoUpdate: "自動",
|
|
31015
32522
|
autoUpdateOnTitle: "ファイル変更時に自動更新",
|
|
31016
32523
|
autoUpdateOffTitle: "自動更新オフ — 手動で再読み込み"
|
|
31017
32524
|
},
|
|
32525
|
+
diff: {
|
|
32526
|
+
files: (count) => `${count}ファイル`,
|
|
32527
|
+
updated: (time) => `更新 ${time}`,
|
|
32528
|
+
updatedTitle: "最終更新",
|
|
32529
|
+
kindAdded: "追加",
|
|
32530
|
+
kindDeleted: "削除",
|
|
32531
|
+
kindRenamed: "名前変更",
|
|
32532
|
+
kindHeavy: "大容量",
|
|
32533
|
+
kindBinary: "バイナリ",
|
|
32534
|
+
kindMedia: "メディア",
|
|
32535
|
+
viewedProgress: (viewed, total) => `${viewed}/${total} 確認済み`,
|
|
32536
|
+
viewedProgressTitle: "確認進捗",
|
|
32537
|
+
nextUnviewed: "次の未確認",
|
|
32538
|
+
nextUnviewedTitle: "次の未確認ファイルへ移動 (n)",
|
|
32539
|
+
allViewed: "すべて確認済み",
|
|
32540
|
+
allViewedTitle: "表示中のファイルはすべて確認済みです",
|
|
32541
|
+
noChangesTitle: "変更はありません",
|
|
32542
|
+
noChangesBody: "この参照との差分はありません。",
|
|
32543
|
+
noChangesReload: "diff を更新",
|
|
32544
|
+
noChangesReloadTitle: "この差分範囲を再読み込み",
|
|
32545
|
+
noChangesHistory: "履歴を開く",
|
|
32546
|
+
noChangesHistoryTitle: "この範囲のコミット履歴を開く",
|
|
32547
|
+
emptyDiffTitle: "空の差分",
|
|
32548
|
+
emptyDiffBody: "このコミットは最初の親との差分がありません。",
|
|
32549
|
+
noCommitSelectedTitle: "コミット未選択",
|
|
32550
|
+
noCommitSelectedBody: "一覧からコミットを選ぶと変更内容を表示します。"
|
|
32551
|
+
},
|
|
31018
32552
|
changeBanner: {
|
|
31019
32553
|
text: "ファイルに変更がありました",
|
|
31020
32554
|
reload: "再読み込みする",
|
|
@@ -31034,14 +32568,56 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31034
32568
|
view: "表示",
|
|
31035
32569
|
tree: "ツリー",
|
|
31036
32570
|
flat: "一覧",
|
|
32571
|
+
treeTitle: "ツリー表示",
|
|
32572
|
+
flatTitle: "一覧表示",
|
|
31037
32573
|
filter: "ファイル絞り込み… / ⌘K",
|
|
31038
32574
|
filterTitle: "ファイルを絞り込みます。/pattern/ は正規表現。/ でこの欄にフォーカス、Cmd/Ctrl+K で全ファイルパレット、Ctrl+G で grep、? でヘルプ。",
|
|
31039
|
-
|
|
32575
|
+
filterClear: "解除",
|
|
32576
|
+
filterClearTitle: "ファイル絞り込みを解除",
|
|
32577
|
+
hide: "サイドバーを隠す",
|
|
32578
|
+
show: "サイドバーを表示",
|
|
32579
|
+
repoTarget: "リポジトリの対象",
|
|
32580
|
+
openDirectoryInOs: "このフォルダをOSで開く",
|
|
32581
|
+
omittedHeavyLabel: "省略",
|
|
32582
|
+
omittedHeavyTitle: "ツリー展開は省略されていますが、詳細パネルでは開けます",
|
|
32583
|
+
omittedPrivateLabel: "非公開",
|
|
32584
|
+
omittedPrivateTitle: "このディレクトリはブラウザから開けません",
|
|
32585
|
+
commitEntryGitlinkLabel: "GIT",
|
|
32586
|
+
commitEntryGitlinkTitle: "Git のコミットに固定された参照です。フォルダではないため直接は開けません。",
|
|
32587
|
+
commitEntrySubmoduleLabel: "SUB",
|
|
32588
|
+
commitEntrySubmoduleTitle: "Git サブモジュール: 特定のコミットに固定されています。フォルダではないため直接は開けません。"
|
|
32589
|
+
},
|
|
32590
|
+
repo: {
|
|
32591
|
+
newFolder: "新規フォルダ",
|
|
32592
|
+
moveFolderToTrash: "フォルダをゴミ箱へ移動",
|
|
32593
|
+
uploadButton: "ファイルをアップロード",
|
|
32594
|
+
dropFilesInto: (target) => `${target} にファイルをドロップ`,
|
|
32595
|
+
uploadFailed: "アップロードに失敗しました",
|
|
32596
|
+
emptyDirectory: "このディレクトリにファイルはありません。",
|
|
32597
|
+
uploadConfirmTitle: "ファイルをアップロードしますか?",
|
|
32598
|
+
uploadConfirmBody: (count, target) => `${target} に ${count} 件のファイルをアップロードしますか?`,
|
|
32599
|
+
uploadConfirmLabel: "アップロード",
|
|
32600
|
+
sortName: "名前",
|
|
32601
|
+
sortUpdated: "更新日時",
|
|
32602
|
+
sortSize: "サイズ",
|
|
32603
|
+
repositoryFallback: "リポジトリ",
|
|
32604
|
+
repositoryRootFallback: "リポジトリのルート",
|
|
32605
|
+
gitlinkLabel: "固定コミット",
|
|
32606
|
+
gitlinkTitle: "特定のコミットに固定された参照です。この ref では直接開けません。",
|
|
32607
|
+
submoduleLabel: "サブモジュール",
|
|
32608
|
+
submoduleTitle: "Git サブモジュール: 特定のコミットに固定されています。直接は開けません。"
|
|
31040
32609
|
},
|
|
31041
32610
|
history: {
|
|
31042
32611
|
title: "コミット",
|
|
31043
32612
|
filter: "コミットを絞り込み...",
|
|
31044
|
-
filterTitle: "メッセージ、SHA、author:name、path:file でコミットを絞り込みます。"
|
|
32613
|
+
filterTitle: "メッセージ、SHA、author:name、path:file でコミットを絞り込みます。",
|
|
32614
|
+
refreshTitle: "コミット履歴を更新"
|
|
32615
|
+
},
|
|
32616
|
+
quickHelp: {
|
|
32617
|
+
buttonTitle: "クイックヘルプ(ショートカット)",
|
|
32618
|
+
panelTitle: "クイックヘルプ",
|
|
32619
|
+
close: "クイックヘルプを閉じる",
|
|
32620
|
+
viewAll: "すべてのキーバインドを見る →"
|
|
31045
32621
|
},
|
|
31046
32622
|
settings: {
|
|
31047
32623
|
title: "ビューア設定",
|
|
@@ -31117,6 +32693,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31117
32693
|
});
|
|
31118
32694
|
setElementText(".global-help-link[data-route='help']", text2.nav.help);
|
|
31119
32695
|
setElementText(".product-label", text2.global.product);
|
|
32696
|
+
document.querySelector(".brand")?.setAttribute("aria-label", text2.global.brandHome);
|
|
32697
|
+
document.querySelector(".app-menu")?.setAttribute("aria-label", text2.global.menuViews);
|
|
31120
32698
|
const annotationsToggle = document.querySelector("#annotations-toggle");
|
|
31121
32699
|
if (annotationsToggle) {
|
|
31122
32700
|
annotationsToggle.title = text2.global.annotations;
|
|
@@ -31132,27 +32710,51 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31132
32710
|
theme.title = text2.global.theme;
|
|
31133
32711
|
theme.setAttribute("aria-label", text2.global.theme);
|
|
31134
32712
|
}
|
|
32713
|
+
const quickHelpBtn = document.querySelector("#quick-help-btn");
|
|
32714
|
+
if (quickHelpBtn) {
|
|
32715
|
+
quickHelpBtn.title = text2.quickHelp.buttonTitle;
|
|
32716
|
+
quickHelpBtn.setAttribute("aria-label", text2.quickHelp.buttonTitle);
|
|
32717
|
+
}
|
|
32718
|
+
QUICK_HELP?.localize();
|
|
32719
|
+
const doctorTitle = doctorText(STATE.language).title;
|
|
32720
|
+
const doctorBtn = document.querySelector("#doctor-btn");
|
|
32721
|
+
if (doctorBtn) {
|
|
32722
|
+
doctorBtn.title = doctorTitle;
|
|
32723
|
+
doctorBtn.setAttribute("aria-label", doctorTitle);
|
|
32724
|
+
}
|
|
32725
|
+
document.querySelector("#doctor-sheet")?.setAttribute("aria-label", doctorTitle);
|
|
31135
32726
|
const copyAiContext = document.querySelector("#copy-ai-context");
|
|
31136
32727
|
if (copyAiContext) {
|
|
31137
32728
|
copyAiContext.title = text2.global.copyAiContext;
|
|
31138
32729
|
copyAiContext.setAttribute("aria-label", text2.global.copyAiContext);
|
|
32730
|
+
const copyAiContextLabel = copyAiContext.querySelector(".ai-context-label");
|
|
32731
|
+
if (copyAiContextLabel)
|
|
32732
|
+
copyAiContextLabel.textContent = text2.global.copyAiContextLabel;
|
|
31139
32733
|
}
|
|
31140
32734
|
const refReset = document.querySelector("#ref-reset");
|
|
31141
|
-
if (refReset)
|
|
32735
|
+
if (refReset) {
|
|
31142
32736
|
refReset.title = text2.topbar.resetRange;
|
|
32737
|
+
refReset.setAttribute("aria-label", text2.topbar.resetRange);
|
|
32738
|
+
}
|
|
31143
32739
|
const reload = document.querySelector("#reload-prom");
|
|
31144
|
-
if (reload)
|
|
32740
|
+
if (reload) {
|
|
31145
32741
|
reload.title = text2.topbar.reload;
|
|
32742
|
+
reload.setAttribute("aria-label", text2.topbar.reload);
|
|
32743
|
+
}
|
|
31146
32744
|
const layoutGroup = document.querySelector("#topbar .seg");
|
|
31147
32745
|
layoutGroup?.setAttribute("aria-label", text2.topbar.layout);
|
|
31148
32746
|
setElementText('#topbar .seg button[data-layout="line-by-line"]', text2.topbar.unified);
|
|
31149
32747
|
setElementText('#topbar .seg button[data-layout="side-by-side"]', text2.topbar.split);
|
|
31150
32748
|
const ignoreWs = document.querySelector("#ignore-ws");
|
|
31151
|
-
if (ignoreWs)
|
|
32749
|
+
if (ignoreWs) {
|
|
31152
32750
|
ignoreWs.title = text2.topbar.ignoreWs;
|
|
32751
|
+
ignoreWs.textContent = text2.topbar.ignoreWsLabel;
|
|
32752
|
+
}
|
|
31153
32753
|
const hideTests = document.querySelector("#hide-tests");
|
|
31154
|
-
if (hideTests)
|
|
32754
|
+
if (hideTests) {
|
|
31155
32755
|
hideTests.title = text2.topbar.hideTests;
|
|
32756
|
+
hideTests.textContent = text2.topbar.hideTestsLabel;
|
|
32757
|
+
}
|
|
31156
32758
|
applyAutoUpdateButton();
|
|
31157
32759
|
setHighlightButton(STATE.syntaxHighlight && getHljs() ? "loaded" : "idle");
|
|
31158
32760
|
setElementText(".sb-title", text2.sidebar.files);
|
|
@@ -31172,15 +32774,33 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31172
32774
|
sbView?.setAttribute("aria-label", text2.sidebar.view);
|
|
31173
32775
|
setElementText('.sb-view-seg button[data-view="tree"]', text2.sidebar.tree);
|
|
31174
32776
|
setElementText('.sb-view-seg button[data-view="flat"]', text2.sidebar.flat);
|
|
32777
|
+
const sbViewTree = document.querySelector('.sb-view-seg button[data-view="tree"]');
|
|
32778
|
+
if (sbViewTree)
|
|
32779
|
+
sbViewTree.title = text2.sidebar.treeTitle;
|
|
32780
|
+
const sbViewFlat = document.querySelector('.sb-view-seg button[data-view="flat"]');
|
|
32781
|
+
if (sbViewFlat)
|
|
32782
|
+
sbViewFlat.title = text2.sidebar.flatTitle;
|
|
31175
32783
|
const filter = document.querySelector("#sb-filter");
|
|
31176
32784
|
if (filter) {
|
|
31177
32785
|
filter.placeholder = text2.sidebar.filter;
|
|
31178
32786
|
filter.title = text2.sidebar.filterTitle;
|
|
31179
32787
|
}
|
|
32788
|
+
const filterClear = document.querySelector("#sb-filter-clear");
|
|
32789
|
+
if (filterClear) {
|
|
32790
|
+
filterClear.textContent = text2.sidebar.filterClear;
|
|
32791
|
+
filterClear.title = text2.sidebar.filterClearTitle;
|
|
32792
|
+
filterClear.setAttribute("aria-label", text2.sidebar.filterClearTitle);
|
|
32793
|
+
}
|
|
32794
|
+
const repoTarget = document.querySelector("#repo-target");
|
|
32795
|
+
if (repoTarget) {
|
|
32796
|
+
repoTarget.title = text2.sidebar.repoTarget;
|
|
32797
|
+
repoTarget.setAttribute("aria-label", text2.sidebar.repoTarget);
|
|
32798
|
+
}
|
|
31180
32799
|
const sidebarToggle = document.querySelector("#sidebar-toggle");
|
|
31181
32800
|
if (sidebarToggle) {
|
|
31182
|
-
|
|
31183
|
-
sidebarToggle.
|
|
32801
|
+
const sidebarToggleTitle = STATE.sidebarHidden ? text2.sidebar.show : text2.sidebar.hide;
|
|
32802
|
+
sidebarToggle.title = sidebarToggleTitle;
|
|
32803
|
+
sidebarToggle.setAttribute("aria-label", sidebarToggleTitle);
|
|
31184
32804
|
}
|
|
31185
32805
|
setElementText(".sidebar-toggle-label", text2.sidebar.files);
|
|
31186
32806
|
setElementText(".history-title", text2.history.title);
|
|
@@ -31191,6 +32811,11 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31191
32811
|
historyFilter.placeholder = text2.history.filter;
|
|
31192
32812
|
historyFilter.title = text2.history.filterTitle;
|
|
31193
32813
|
}
|
|
32814
|
+
document.querySelectorAll(".history-refresh").forEach((button) => {
|
|
32815
|
+
button.title = text2.history.refreshTitle;
|
|
32816
|
+
button.setAttribute("aria-label", text2.history.refreshTitle);
|
|
32817
|
+
});
|
|
32818
|
+
relocalizeHistory?.();
|
|
31194
32819
|
setElementText(".scope-settings-head strong", text2.settings.title);
|
|
31195
32820
|
const settingsClose = document.querySelector("#scope-settings-close");
|
|
31196
32821
|
settingsClose?.setAttribute("aria-label", text2.settings.close);
|
|
@@ -31259,7 +32884,9 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31259
32884
|
setButtonLabel(document.querySelector("#query-history-panel-close"), text2.annotations.close);
|
|
31260
32885
|
relocalizeDatabase?.();
|
|
31261
32886
|
}
|
|
32887
|
+
let relocalizeHistory = null;
|
|
31262
32888
|
let relocalizeDatabase = null;
|
|
32889
|
+
let QUICK_HELP = null;
|
|
31263
32890
|
function setViewerLanguage(language, persist = true) {
|
|
31264
32891
|
const next = normalizeViewerLanguage(language);
|
|
31265
32892
|
STATE.language = next;
|
|
@@ -31286,6 +32913,13 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31286
32913
|
el.classList.remove("live", "refreshing", "error");
|
|
31287
32914
|
if (s2)
|
|
31288
32915
|
el.classList.add(s2);
|
|
32916
|
+
const text2 = uiText();
|
|
32917
|
+
const label = s2 === "live" ? text2.global.statusLive : s2 === "refreshing" ? text2.global.statusLoading : s2 === "error" ? text2.global.statusError : text2.global.statusIdle;
|
|
32918
|
+
const labelEl = el.querySelector(".status-label");
|
|
32919
|
+
if (labelEl)
|
|
32920
|
+
labelEl.textContent = label;
|
|
32921
|
+
el.setAttribute("aria-label", label);
|
|
32922
|
+
updateNetworkActivity();
|
|
31289
32923
|
}
|
|
31290
32924
|
function applyTheme() {
|
|
31291
32925
|
document.documentElement.dataset.theme = STATE.theme;
|
|
@@ -31587,8 +33221,10 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31587
33221
|
input.readOnly = true;
|
|
31588
33222
|
input.autocomplete = "off";
|
|
31589
33223
|
input.placeholder = options.placeholder;
|
|
31590
|
-
if (options.title)
|
|
33224
|
+
if (options.title) {
|
|
31591
33225
|
input.title = options.title;
|
|
33226
|
+
input.setAttribute("aria-label", options.title);
|
|
33227
|
+
}
|
|
31592
33228
|
if (options.value != null)
|
|
31593
33229
|
input.value = options.value;
|
|
31594
33230
|
const caret = document.createElement("span");
|
|
@@ -31692,7 +33328,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31692
33328
|
currentRange,
|
|
31693
33329
|
setRoute,
|
|
31694
33330
|
setPreferredSourceTab: (tab) => SOURCE_VIEW.setPreferredSourceTab(tab),
|
|
31695
|
-
createFileBreadcrumb: (path, ref) => DIFF_VIEW.createFileBreadcrumb(path, ref)
|
|
33331
|
+
createFileBreadcrumb: (path, ref) => DIFF_VIEW.createFileBreadcrumb(path, ref),
|
|
33332
|
+
emptyText: () => uiText().diff
|
|
31696
33333
|
}, historyRoute);
|
|
31697
33334
|
activeFileHistoryDiffHost = mount.diffHost;
|
|
31698
33335
|
activeFileHistoryEmptyHost = mount.emptyHost;
|
|
@@ -31705,6 +33342,9 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31705
33342
|
function withAnnotationSessionParam(rawUrl) {
|
|
31706
33343
|
return ANNOTATIONS_UI ? ANNOTATIONS_UI.withSessionParam(rawUrl) : rawUrl;
|
|
31707
33344
|
}
|
|
33345
|
+
function urlForRoute(route) {
|
|
33346
|
+
return withDoctorOverlay(withAnnotationSessionParam(buildRoute(route)), parseDoctorOverlay(window.location.pathname, window.location.search));
|
|
33347
|
+
}
|
|
31708
33348
|
function historyStateForRoute(route) {
|
|
31709
33349
|
return route.screen === "file" ? {
|
|
31710
33350
|
screen: "file",
|
|
@@ -31779,7 +33419,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31779
33419
|
if (nextRoute.screen === "repo" || nextRoute.screen === "file" && (nextRoute.view === "blob" || nextRoute.view === "blame" || nextRoute.view === "history")) {
|
|
31780
33420
|
STATE.repoRef = nextRoute.ref || "worktree";
|
|
31781
33421
|
}
|
|
31782
|
-
const url =
|
|
33422
|
+
const url = urlForRoute(nextRoute);
|
|
31783
33423
|
const state = historyStateForRoute(nextRoute);
|
|
31784
33424
|
if (replace2)
|
|
31785
33425
|
history.replaceState(state, "", url);
|
|
@@ -32024,6 +33664,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32024
33664
|
SERVER_GENERATION = generation;
|
|
32025
33665
|
},
|
|
32026
33666
|
invalidateRepoSidebar,
|
|
33667
|
+
diffText: () => uiText().diff,
|
|
32027
33668
|
getDiffRoot: () => activeFileHistoryDiffHost || $("#diff"),
|
|
32028
33669
|
getEmptyPane: () => activeFileHistoryEmptyHost || $("#empty"),
|
|
32029
33670
|
isEmbeddedDiffMode: () => !!activeFileHistoryDiffHost
|
|
@@ -32057,10 +33698,26 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32057
33698
|
if (themeButton) {
|
|
32058
33699
|
themeButton.innerHTML = iconSvg("octicon-moon", MOON_16_PATH);
|
|
32059
33700
|
}
|
|
32060
|
-
const
|
|
32061
|
-
if (
|
|
32062
|
-
|
|
33701
|
+
const copyAiContextIcon = document.querySelector("#copy-ai-context .goi-icon");
|
|
33702
|
+
if (copyAiContextIcon) {
|
|
33703
|
+
copyAiContextIcon.innerHTML = iconSvg("octicon-copy", COPY_16_PATHS);
|
|
32063
33704
|
}
|
|
33705
|
+
const autoUpdateIcon = document.querySelector("#auto-update .goi-icon");
|
|
33706
|
+
if (autoUpdateIcon) {
|
|
33707
|
+
autoUpdateIcon.innerHTML = iconSvg("octicon-sync", SYNC_16_PATH);
|
|
33708
|
+
}
|
|
33709
|
+
const cancelRequestsIcon = document.querySelector("#cancel-requests .goi-icon");
|
|
33710
|
+
if (cancelRequestsIcon) {
|
|
33711
|
+
cancelRequestsIcon.innerHTML = iconSvg("octicon-x", X_16_PATH);
|
|
33712
|
+
}
|
|
33713
|
+
}
|
|
33714
|
+
function setRefActionIcons() {
|
|
33715
|
+
const refReset = document.querySelector("#ref-reset");
|
|
33716
|
+
if (refReset)
|
|
33717
|
+
refReset.innerHTML = iconSvg("octicon-x", X_16_PATH);
|
|
33718
|
+
const reload = document.querySelector("#reload-prom");
|
|
33719
|
+
if (reload)
|
|
33720
|
+
reload.innerHTML = iconSvg("octicon-sync", SYNC_16_PATH);
|
|
32064
33721
|
}
|
|
32065
33722
|
applySidebarFontSize();
|
|
32066
33723
|
applyCodeFontSize();
|
|
@@ -32070,6 +33727,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32070
33727
|
hydrateRefSelectorMounts();
|
|
32071
33728
|
setSidebarTreeActionIcons();
|
|
32072
33729
|
setGlobalHeaderIcons();
|
|
33730
|
+
setRefActionIcons();
|
|
32073
33731
|
$$(".sb-view-seg button").forEach((b2) => {
|
|
32074
33732
|
b2.addEventListener("click", () => {
|
|
32075
33733
|
STATE.sbView = b2.dataset.view || "tree";
|
|
@@ -32100,11 +33758,15 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32100
33758
|
};
|
|
32101
33759
|
}
|
|
32102
33760
|
}
|
|
33761
|
+
const databaseQuerySql = STATE.route.screen === "database" && STATE.route.tab === "query" ? document.querySelector(".db-container:not([hidden]) .db-query-editor:not([hidden]) .db-query-textarea")?.value : undefined;
|
|
32103
33762
|
const text2 = aiContextClipboardText({
|
|
32104
33763
|
route: STATE.route,
|
|
32105
33764
|
diffFrom: STATE.from,
|
|
32106
33765
|
diffTo: STATE.to,
|
|
32107
|
-
selectionCode
|
|
33766
|
+
selectionCode,
|
|
33767
|
+
diffMeta: window._lastMeta ? visibleDiffMetaForBrief(window._lastMeta) : null,
|
|
33768
|
+
viewedFiles: STATE.viewedFiles,
|
|
33769
|
+
databaseQuerySql
|
|
32108
33770
|
});
|
|
32109
33771
|
const finish = (ok, withCode, lineCount, reason) => {
|
|
32110
33772
|
const label = reason === "empty" ? uiText().global.copyAiContextEmpty : ok ? withCode ? uiText().global.copyAiContextCopiedWithCode(lineCount) : uiText().global.copyAiContextCopied : uiText().global.copyAiContextFailed;
|
|
@@ -32336,7 +33998,10 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32336
33998
|
}
|
|
32337
33999
|
const sbFilter = $("#sb-filter");
|
|
32338
34000
|
if (sbFilter) {
|
|
32339
|
-
sbFilter.addEventListener("input", () =>
|
|
34001
|
+
sbFilter.addEventListener("input", () => {
|
|
34002
|
+
syncSidebarFilterClearButton();
|
|
34003
|
+
scheduleApplyFilter();
|
|
34004
|
+
});
|
|
32340
34005
|
sbFilter.addEventListener("keydown", (e2) => {
|
|
32341
34006
|
if (isImeComposing(e2))
|
|
32342
34007
|
return;
|
|
@@ -32351,6 +34016,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32351
34016
|
} else if (e2.key === "Escape") {
|
|
32352
34017
|
if (sbFilter.value) {
|
|
32353
34018
|
sbFilter.value = "";
|
|
34019
|
+
syncSidebarFilterClearButton();
|
|
32354
34020
|
flushSidebarFilter();
|
|
32355
34021
|
applyFilter();
|
|
32356
34022
|
} else {
|
|
@@ -32359,6 +34025,11 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32359
34025
|
}
|
|
32360
34026
|
});
|
|
32361
34027
|
}
|
|
34028
|
+
const sbFilterClear = document.querySelector("#sb-filter-clear");
|
|
34029
|
+
if (sbFilterClear) {
|
|
34030
|
+
syncSidebarFilterClearButton();
|
|
34031
|
+
sbFilterClear.addEventListener("click", clearSidebarFilter);
|
|
34032
|
+
}
|
|
32362
34033
|
function focusFileFilter() {
|
|
32363
34034
|
const input = $("#sb-filter");
|
|
32364
34035
|
input.focus();
|
|
@@ -32510,17 +34181,13 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32510
34181
|
}));
|
|
32511
34182
|
return true;
|
|
32512
34183
|
}
|
|
34184
|
+
if (action === "next-unviewed-file") {
|
|
34185
|
+
if (DIFF_VIEW.scrollToNextUnviewedFile())
|
|
34186
|
+
scheduleMainSurfaceFocus();
|
|
34187
|
+
return true;
|
|
34188
|
+
}
|
|
32513
34189
|
if (action === "open-help") {
|
|
32514
|
-
|
|
32515
|
-
getRoute: () => STATE.route,
|
|
32516
|
-
getLanguage: () => STATE.language,
|
|
32517
|
-
currentRange,
|
|
32518
|
-
setRoute,
|
|
32519
|
-
setPageMode,
|
|
32520
|
-
renderHelpPage,
|
|
32521
|
-
setStatus,
|
|
32522
|
-
cancelActiveSourceLoad
|
|
32523
|
-
});
|
|
34190
|
+
QUICK_HELP?.toggle();
|
|
32524
34191
|
return true;
|
|
32525
34192
|
}
|
|
32526
34193
|
return false;
|
|
@@ -32573,6 +34240,103 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32573
34240
|
if (window.location.pathname === "/") {
|
|
32574
34241
|
setRoute(STATE.route, true);
|
|
32575
34242
|
}
|
|
34243
|
+
function normalizedHistoryRefForEmptyDiff() {
|
|
34244
|
+
const candidate = STATE.to && STATE.to !== "worktree" ? STATE.to : STATE.from || "HEAD";
|
|
34245
|
+
return candidate && candidate !== "worktree" && !candidate.startsWith("--") ? candidate : "HEAD";
|
|
34246
|
+
}
|
|
34247
|
+
function emptyDiffHistoryRoute() {
|
|
34248
|
+
return {
|
|
34249
|
+
screen: "history",
|
|
34250
|
+
ref: normalizedHistoryRefForEmptyDiff(),
|
|
34251
|
+
range: currentRange()
|
|
34252
|
+
};
|
|
34253
|
+
}
|
|
34254
|
+
function setEmptyActionContent(action, iconName, iconPath, label, title) {
|
|
34255
|
+
action.title = title;
|
|
34256
|
+
action.setAttribute("aria-label", title);
|
|
34257
|
+
action.replaceChildren();
|
|
34258
|
+
const icon = document.createElement("span");
|
|
34259
|
+
icon.className = "empty-action-icon";
|
|
34260
|
+
icon.setAttribute("aria-hidden", "true");
|
|
34261
|
+
icon.innerHTML = iconSvg(iconName, iconPath);
|
|
34262
|
+
const text2 = document.createElement("span");
|
|
34263
|
+
text2.className = "empty-action-label";
|
|
34264
|
+
text2.textContent = label;
|
|
34265
|
+
action.append(icon, text2);
|
|
34266
|
+
}
|
|
34267
|
+
function navigateToEmptyDiffHistory(event) {
|
|
34268
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
|
|
34269
|
+
return;
|
|
34270
|
+
event.preventDefault();
|
|
34271
|
+
const route = emptyDiffHistoryRoute();
|
|
34272
|
+
history.pushState(historyStateForRoute(route), "", urlForRoute(route));
|
|
34273
|
+
window.scrollTo(0, 0);
|
|
34274
|
+
applyRouteFromLocation();
|
|
34275
|
+
}
|
|
34276
|
+
function ensureEmptyDiffActions(empty) {
|
|
34277
|
+
let actions = empty.querySelector(".empty-actions");
|
|
34278
|
+
if (actions)
|
|
34279
|
+
return actions;
|
|
34280
|
+
actions = document.createElement("div");
|
|
34281
|
+
actions.className = "empty-actions";
|
|
34282
|
+
actions.hidden = true;
|
|
34283
|
+
const reload = document.createElement("button");
|
|
34284
|
+
reload.type = "button";
|
|
34285
|
+
reload.className = "empty-action empty-action-primary";
|
|
34286
|
+
reload.dataset.emptyAction = "reload";
|
|
34287
|
+
reload.addEventListener("click", () => reloadDiffFromUi(reload));
|
|
34288
|
+
const historyLink = document.createElement("a");
|
|
34289
|
+
historyLink.className = "empty-action";
|
|
34290
|
+
historyLink.dataset.emptyAction = "history";
|
|
34291
|
+
historyLink.addEventListener("click", navigateToEmptyDiffHistory);
|
|
34292
|
+
actions.append(reload, historyLink);
|
|
34293
|
+
empty.appendChild(actions);
|
|
34294
|
+
return actions;
|
|
34295
|
+
}
|
|
34296
|
+
function syncEmptyDiffPane(empty, onHistory) {
|
|
34297
|
+
empty.classList.toggle("empty-with-actions", !onHistory);
|
|
34298
|
+
const text2 = uiText().diff;
|
|
34299
|
+
const h2 = empty.querySelector("h2");
|
|
34300
|
+
if (h2)
|
|
34301
|
+
h2.textContent = onHistory ? text2.emptyDiffTitle : text2.noChangesTitle;
|
|
34302
|
+
const p2 = empty.querySelector("p");
|
|
34303
|
+
if (p2)
|
|
34304
|
+
p2.textContent = onHistory ? text2.emptyDiffBody : text2.noChangesBody;
|
|
34305
|
+
const existingActions = empty.querySelector(".empty-actions");
|
|
34306
|
+
if (onHistory) {
|
|
34307
|
+
if (existingActions)
|
|
34308
|
+
existingActions.hidden = true;
|
|
34309
|
+
return;
|
|
34310
|
+
}
|
|
34311
|
+
const actions = ensureEmptyDiffActions(empty);
|
|
34312
|
+
const reload = actions.querySelector('[data-empty-action="reload"]');
|
|
34313
|
+
const historyLink = actions.querySelector('[data-empty-action="history"]');
|
|
34314
|
+
if (reload)
|
|
34315
|
+
setEmptyActionContent(reload, "octicon-sync", SYNC_16_PATH, text2.noChangesReload, text2.noChangesReloadTitle);
|
|
34316
|
+
if (historyLink) {
|
|
34317
|
+
const route = emptyDiffHistoryRoute();
|
|
34318
|
+
historyLink.href = urlForRoute(route);
|
|
34319
|
+
setEmptyActionContent(historyLink, "octicon-git-branch", GIT_BRANCH_16_PATH, text2.noChangesHistory, text2.noChangesHistoryTitle);
|
|
34320
|
+
}
|
|
34321
|
+
actions.hidden = false;
|
|
34322
|
+
}
|
|
34323
|
+
function reloadDiffFromUi(trigger) {
|
|
34324
|
+
const topbarButton = $("#reload-prom");
|
|
34325
|
+
topbarButton.classList.add("spinning");
|
|
34326
|
+
if (trigger && trigger !== topbarButton) {
|
|
34327
|
+
trigger.classList.add("spinning");
|
|
34328
|
+
trigger.setAttribute("aria-busy", "true");
|
|
34329
|
+
}
|
|
34330
|
+
load().finally(() => {
|
|
34331
|
+
setTimeout(() => {
|
|
34332
|
+
topbarButton.classList.remove("spinning");
|
|
34333
|
+
if (trigger && trigger !== topbarButton) {
|
|
34334
|
+
trigger.classList.remove("spinning");
|
|
34335
|
+
trigger.setAttribute("aria-busy", "false");
|
|
34336
|
+
}
|
|
34337
|
+
}, 200);
|
|
34338
|
+
});
|
|
34339
|
+
}
|
|
32576
34340
|
function load(options = {}) {
|
|
32577
34341
|
if (STATE.route.screen === "help") {
|
|
32578
34342
|
setStatus("live");
|
|
@@ -32598,12 +34362,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32598
34362
|
const empty = activeFileHistoryEmptyHost || $("#empty");
|
|
32599
34363
|
if (empty) {
|
|
32600
34364
|
const onHistory = STATE.route.screen === "history" || isFileHistoryRoute(STATE.route);
|
|
32601
|
-
|
|
32602
|
-
if (h2)
|
|
32603
|
-
h2.textContent = onHistory ? "Empty diff" : "No changes";
|
|
32604
|
-
const p2 = empty.querySelector("p");
|
|
32605
|
-
if (p2)
|
|
32606
|
-
p2.textContent = onHistory ? "This commit has no changes against its first parent." : "The working tree is clean against this ref.";
|
|
34365
|
+
syncEmptyDiffPane(empty, onHistory);
|
|
32607
34366
|
}
|
|
32608
34367
|
}
|
|
32609
34368
|
const routeAtRequest = STATE.route;
|
|
@@ -32629,7 +34388,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32629
34388
|
return null;
|
|
32630
34389
|
const result = renderShell(data, options.changedPaths);
|
|
32631
34390
|
applyHideTestsToMeta();
|
|
32632
|
-
setStatus("live");
|
|
34391
|
+
setStatus(data.error ? "error" : "live");
|
|
32633
34392
|
return result;
|
|
32634
34393
|
}).catch(() => {
|
|
32635
34394
|
if (!isCurrentDiffRequest())
|
|
@@ -32716,12 +34475,13 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32716
34475
|
DIFF_VIEW.clearLoadQueue();
|
|
32717
34476
|
if (activeFileHistoryEmptyHost) {
|
|
32718
34477
|
activeFileHistoryEmptyHost.classList.remove("hidden");
|
|
34478
|
+
const text2 = uiText().diff;
|
|
32719
34479
|
const h2 = activeFileHistoryEmptyHost.querySelector("h2");
|
|
32720
34480
|
if (h2)
|
|
32721
|
-
h2.textContent =
|
|
34481
|
+
h2.textContent = text2.noCommitSelectedTitle;
|
|
32722
34482
|
const p2 = activeFileHistoryEmptyHost.querySelector("p");
|
|
32723
34483
|
if (p2)
|
|
32724
|
-
p2.textContent =
|
|
34484
|
+
p2.textContent = text2.noCommitSelectedBody;
|
|
32725
34485
|
}
|
|
32726
34486
|
setStatus("live");
|
|
32727
34487
|
return;
|
|
@@ -32740,13 +34500,32 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32740
34500
|
invalidateRepoSidebar,
|
|
32741
34501
|
clearLoadQueue: () => DIFF_VIEW.clearLoadQueue(),
|
|
32742
34502
|
placeSidebarToggle,
|
|
32743
|
-
setStatus
|
|
34503
|
+
setStatus,
|
|
34504
|
+
emptyText: () => uiText().diff
|
|
32744
34505
|
});
|
|
32745
34506
|
},
|
|
32746
34507
|
getSyntaxHighlight: () => STATE.syntaxHighlight,
|
|
32747
34508
|
getLanguage: () => STATE.language,
|
|
32748
34509
|
trackLoad
|
|
32749
34510
|
});
|
|
34511
|
+
relocalizeHistory = () => HISTORY_VIEW.localize();
|
|
34512
|
+
QUICK_HELP = createQuickHelp({
|
|
34513
|
+
$,
|
|
34514
|
+
getLanguage: () => STATE.language,
|
|
34515
|
+
getText: () => uiText().quickHelp,
|
|
34516
|
+
openFullKeybindings: () => {
|
|
34517
|
+
openHelpKeybindings({
|
|
34518
|
+
getRoute: () => STATE.route,
|
|
34519
|
+
getLanguage: () => STATE.language,
|
|
34520
|
+
currentRange,
|
|
34521
|
+
setRoute,
|
|
34522
|
+
setPageMode,
|
|
34523
|
+
renderHelpPage,
|
|
34524
|
+
setStatus,
|
|
34525
|
+
cancelActiveSourceLoad
|
|
34526
|
+
});
|
|
34527
|
+
}
|
|
34528
|
+
});
|
|
32750
34529
|
const DOCTOR_VIEW = createDoctorView({
|
|
32751
34530
|
$: (sel) => document.querySelector(sel),
|
|
32752
34531
|
escapeHtml: escapeHtml3,
|
|
@@ -32968,13 +34747,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32968
34747
|
});
|
|
32969
34748
|
if (STATE.syntaxHighlight)
|
|
32970
34749
|
setSyntaxHighlight(true, false);
|
|
32971
|
-
$("#reload-prom").addEventListener("click", () =>
|
|
32972
|
-
const btn = $("#reload-prom");
|
|
32973
|
-
btn.classList.add("spinning");
|
|
32974
|
-
load().finally(() => {
|
|
32975
|
-
setTimeout(() => btn.classList.remove("spinning"), 200);
|
|
32976
|
-
});
|
|
32977
|
-
});
|
|
34750
|
+
$("#reload-prom").addEventListener("click", () => reloadDiffFromUi());
|
|
32978
34751
|
function applyHideTests() {
|
|
32979
34752
|
const btn = $("#hide-tests");
|
|
32980
34753
|
if (btn)
|
|
@@ -32996,26 +34769,34 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32996
34769
|
applyViewedState();
|
|
32997
34770
|
applyHideTestsToMeta();
|
|
32998
34771
|
}
|
|
32999
|
-
function
|
|
33000
|
-
|
|
33001
|
-
|
|
33002
|
-
return;
|
|
34772
|
+
function visibleDiffMetaForBrief(meta) {
|
|
34773
|
+
if (!meta.totals)
|
|
34774
|
+
return meta;
|
|
33003
34775
|
const effective = STATE.hideTests && !isRepositorySidebarMode();
|
|
33004
|
-
if (!effective)
|
|
33005
|
-
|
|
33006
|
-
return;
|
|
33007
|
-
}
|
|
34776
|
+
if (!effective)
|
|
34777
|
+
return meta;
|
|
33008
34778
|
let additions = 0;
|
|
33009
34779
|
let deletions = 0;
|
|
33010
|
-
|
|
33011
|
-
for (const f2 of
|
|
34780
|
+
const visibleFiles = [];
|
|
34781
|
+
for (const f2 of meta.files) {
|
|
33012
34782
|
if (TEST_RE.test(f2.path || ""))
|
|
33013
34783
|
continue;
|
|
33014
34784
|
additions += f2.additions || 0;
|
|
33015
34785
|
deletions += f2.deletions || 0;
|
|
33016
|
-
|
|
34786
|
+
visibleFiles.push(f2);
|
|
33017
34787
|
}
|
|
33018
|
-
|
|
34788
|
+
return {
|
|
34789
|
+
...meta,
|
|
34790
|
+
files: visibleFiles,
|
|
34791
|
+
totals: { files: visibleFiles.length, additions, deletions }
|
|
34792
|
+
};
|
|
34793
|
+
}
|
|
34794
|
+
function applyHideTestsToMeta() {
|
|
34795
|
+
const meta = window._lastMeta;
|
|
34796
|
+
if (!meta?.totals)
|
|
34797
|
+
return;
|
|
34798
|
+
renderMeta(visibleDiffMetaForBrief(meta));
|
|
34799
|
+
applyViewedState();
|
|
33019
34800
|
}
|
|
33020
34801
|
applyHideTests();
|
|
33021
34802
|
$("#hide-tests").addEventListener("click", () => {
|
|
@@ -33154,9 +34935,13 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
33154
34935
|
return;
|
|
33155
34936
|
const text2 = uiText();
|
|
33156
34937
|
btn.classList.toggle("active", STATE.autoUpdate);
|
|
33157
|
-
|
|
33158
|
-
btn.title =
|
|
34938
|
+
const autoUpdateTitle = STATE.autoUpdate ? text2.topbar.autoUpdateOnTitle : text2.topbar.autoUpdateOffTitle;
|
|
34939
|
+
btn.title = autoUpdateTitle;
|
|
34940
|
+
btn.setAttribute("aria-label", autoUpdateTitle);
|
|
33159
34941
|
btn.setAttribute("aria-pressed", STATE.autoUpdate ? "true" : "false");
|
|
34942
|
+
const label = btn.querySelector(".auto-update-label");
|
|
34943
|
+
if (label)
|
|
34944
|
+
label.textContent = text2.topbar.autoUpdate;
|
|
33160
34945
|
}
|
|
33161
34946
|
function setAutoUpdate(on) {
|
|
33162
34947
|
STATE.autoUpdate = on;
|
|
@@ -33359,6 +35144,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
33359
35144
|
paths = parsed.paths;
|
|
33360
35145
|
} catch {}
|
|
33361
35146
|
}
|
|
35147
|
+
if (isHistoryPanelRoute(STATE.route))
|
|
35148
|
+
HISTORY_VIEW.notePossibleUpdate();
|
|
33362
35149
|
scheduleSseLoad(paths);
|
|
33363
35150
|
});
|
|
33364
35151
|
es.addEventListener("watch-limit", (event) => {
|