gemstar 1.2 → 1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +4 -2
- data/lib/gemstar/cache_warmer.rb +36 -1
- data/lib/gemstar/cargo_lock_file.rb +138 -0
- data/lib/gemstar/change_log.rb +127 -46
- data/lib/gemstar/cli.rb +8 -2
- data/lib/gemstar/commands/diff.rb +13 -2
- data/lib/gemstar/commands/server.rb +32 -11
- data/lib/gemstar/crates_io_metadata.rb +140 -0
- data/lib/gemstar/data/ruby_gems_metadata.json +10 -0
- data/lib/gemstar/outputs/html.rb +2 -0
- data/lib/gemstar/project.rb +208 -15
- data/lib/gemstar/pypi_metadata.rb +182 -0
- data/lib/gemstar/ruby_gems_metadata.rb +26 -3
- data/lib/gemstar/uv_lock_file.rb +114 -0
- data/lib/gemstar/version.rb +1 -1
- data/lib/gemstar/web/app.rb +452 -49
- data/lib/gemstar/web/templates/app.css +131 -4
- data/lib/gemstar/web/templates/app.js.erb +178 -21
- data/lib/gemstar.rb +4 -0
- metadata +8 -4
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
--line: #ddcfbf;
|
|
9
9
|
--accent: #b44d25;
|
|
10
10
|
--accent-soft: rgba(180, 77, 37, 0.14);
|
|
11
|
+
--focus: #2563c9;
|
|
11
12
|
--green: #2f8f5b;
|
|
12
13
|
--green-soft: rgba(47, 143, 91, 0.12);
|
|
13
14
|
--red: #a9473c;
|
|
@@ -182,6 +183,63 @@
|
|
|
182
183
|
opacity: 0.55;
|
|
183
184
|
cursor: not-allowed;
|
|
184
185
|
}
|
|
186
|
+
.command-dialog-backdrop {
|
|
187
|
+
position: fixed;
|
|
188
|
+
inset: 0;
|
|
189
|
+
z-index: 20;
|
|
190
|
+
display: grid;
|
|
191
|
+
place-items: center;
|
|
192
|
+
padding: 1rem;
|
|
193
|
+
background: rgba(31, 27, 23, 0.42);
|
|
194
|
+
}
|
|
195
|
+
.command-dialog {
|
|
196
|
+
width: min(48rem, 100%);
|
|
197
|
+
max-height: min(42rem, calc(100vh - 2rem));
|
|
198
|
+
display: grid;
|
|
199
|
+
grid-template-rows: auto minmax(10rem, 1fr) auto;
|
|
200
|
+
overflow: hidden;
|
|
201
|
+
border: 1px solid var(--line);
|
|
202
|
+
border-radius: 0.45rem;
|
|
203
|
+
background: #fff;
|
|
204
|
+
box-shadow: 0 1.25rem 3rem rgba(31, 27, 23, 0.24);
|
|
205
|
+
}
|
|
206
|
+
.command-dialog-header {
|
|
207
|
+
display: grid;
|
|
208
|
+
gap: 0.3rem;
|
|
209
|
+
padding: 0.85rem 1rem 0.7rem;
|
|
210
|
+
border-bottom: 1px solid #ece8df;
|
|
211
|
+
}
|
|
212
|
+
.command-dialog-header h2 {
|
|
213
|
+
margin: 0;
|
|
214
|
+
font-size: 1rem;
|
|
215
|
+
line-height: 1.15;
|
|
216
|
+
}
|
|
217
|
+
.command-dialog-command {
|
|
218
|
+
margin: 0;
|
|
219
|
+
color: var(--muted);
|
|
220
|
+
font-family: "SFMono-Regular", "Cascadia Code", monospace;
|
|
221
|
+
font-size: 0.78rem;
|
|
222
|
+
overflow-wrap: anywhere;
|
|
223
|
+
}
|
|
224
|
+
.command-dialog-output {
|
|
225
|
+
min-height: 0;
|
|
226
|
+
margin: 0;
|
|
227
|
+
padding: 0.85rem 1rem;
|
|
228
|
+
overflow: auto;
|
|
229
|
+
white-space: pre-wrap;
|
|
230
|
+
background: #181614;
|
|
231
|
+
color: #f8efe4;
|
|
232
|
+
font-size: 0.76rem;
|
|
233
|
+
line-height: 1.45;
|
|
234
|
+
}
|
|
235
|
+
.command-dialog-actions {
|
|
236
|
+
display: flex;
|
|
237
|
+
justify-content: flex-end;
|
|
238
|
+
gap: 0.35rem;
|
|
239
|
+
padding: 0.65rem 0.75rem;
|
|
240
|
+
border-top: 1px solid #ece8df;
|
|
241
|
+
background: #fff;
|
|
242
|
+
}
|
|
185
243
|
.toolbar-meta {
|
|
186
244
|
color: var(--muted);
|
|
187
245
|
display: flex;
|
|
@@ -358,6 +416,11 @@
|
|
|
358
416
|
min-height: 0;
|
|
359
417
|
overflow: auto;
|
|
360
418
|
}
|
|
419
|
+
.detail:focus {
|
|
420
|
+
outline: none;
|
|
421
|
+
border-color: var(--focus);
|
|
422
|
+
box-shadow: 0 0 0 1px var(--focus);
|
|
423
|
+
}
|
|
361
424
|
.detail-hero,
|
|
362
425
|
.panel-heading {
|
|
363
426
|
display: flex;
|
|
@@ -366,6 +429,16 @@
|
|
|
366
429
|
align-items: start;
|
|
367
430
|
flex-wrap: wrap;
|
|
368
431
|
}
|
|
432
|
+
.detail-hero {
|
|
433
|
+
position: sticky;
|
|
434
|
+
top: -0.62rem;
|
|
435
|
+
z-index: 2;
|
|
436
|
+
margin: -0.62rem -0.8rem 0 -0.5rem;
|
|
437
|
+
padding: 0.62rem 0.8rem 0.5rem 0.5rem;
|
|
438
|
+
border-bottom: 1px solid #f0ede6;
|
|
439
|
+
background: rgba(255, 255, 255, 0.96);
|
|
440
|
+
backdrop-filter: blur(0.45rem);
|
|
441
|
+
}
|
|
369
442
|
.detail-hero-copy {
|
|
370
443
|
display: grid;
|
|
371
444
|
gap: 0.2rem;
|
|
@@ -384,6 +457,16 @@
|
|
|
384
457
|
min-width: 0;
|
|
385
458
|
flex: 1 1 auto;
|
|
386
459
|
}
|
|
460
|
+
.detail-heading {
|
|
461
|
+
display: flex;
|
|
462
|
+
align-items: center;
|
|
463
|
+
flex-wrap: wrap;
|
|
464
|
+
gap: 0.5rem;
|
|
465
|
+
min-width: 0;
|
|
466
|
+
}
|
|
467
|
+
.detail-hero-copy .detail-heading h2 {
|
|
468
|
+
flex: 0 1 auto;
|
|
469
|
+
}
|
|
387
470
|
.detail-hero-copy h2 {
|
|
388
471
|
margin: 0;
|
|
389
472
|
font-size: 2.35rem;
|
|
@@ -396,6 +479,32 @@
|
|
|
396
479
|
font-weight: 600;
|
|
397
480
|
color: var(--muted);
|
|
398
481
|
}
|
|
482
|
+
.detail-package-type {
|
|
483
|
+
display: inline-flex;
|
|
484
|
+
align-items: center;
|
|
485
|
+
gap: 0.28rem;
|
|
486
|
+
flex: 0 0 auto;
|
|
487
|
+
border: 1px solid var(--line);
|
|
488
|
+
border-radius: 999px;
|
|
489
|
+
background: #faf8f3;
|
|
490
|
+
color: var(--muted);
|
|
491
|
+
padding: 0.16rem 0.42rem 0.16rem 0.3rem;
|
|
492
|
+
font-size: 0.68rem;
|
|
493
|
+
font-weight: 700;
|
|
494
|
+
line-height: 1;
|
|
495
|
+
letter-spacing: 0.01em;
|
|
496
|
+
}
|
|
497
|
+
.detail-package-type-icon {
|
|
498
|
+
display: inline-flex;
|
|
499
|
+
width: 0.9rem;
|
|
500
|
+
height: 0.9rem;
|
|
501
|
+
color: var(--ink);
|
|
502
|
+
}
|
|
503
|
+
.detail-package-type-icon svg {
|
|
504
|
+
display: block;
|
|
505
|
+
width: 100%;
|
|
506
|
+
height: 100%;
|
|
507
|
+
}
|
|
399
508
|
.detail-title-row .link-strip {
|
|
400
509
|
margin-left: auto;
|
|
401
510
|
align-self: start;
|
|
@@ -528,9 +637,18 @@
|
|
|
528
637
|
overflow: hidden;
|
|
529
638
|
}
|
|
530
639
|
.revision-future {
|
|
531
|
-
|
|
532
|
-
border
|
|
533
|
-
background:
|
|
640
|
+
position: relative;
|
|
641
|
+
border: 2px solid rgba(37, 99, 201, 0.3);
|
|
642
|
+
background:
|
|
643
|
+
repeating-linear-gradient(
|
|
644
|
+
135deg,
|
|
645
|
+
rgba(37, 99, 201, 0.018) 0,
|
|
646
|
+
rgba(37, 99, 201, 0.018) 0.5rem,
|
|
647
|
+
rgba(255, 255, 255, 0) 0.5rem,
|
|
648
|
+
rgba(255, 255, 255, 0) 1.2rem
|
|
649
|
+
),
|
|
650
|
+
#fbfdff;
|
|
651
|
+
box-shadow: inset 0.24rem 0 0 rgba(37, 99, 201, 0.42);
|
|
534
652
|
}
|
|
535
653
|
.revision-current {
|
|
536
654
|
border-color: rgba(47, 143, 91, 0.25);
|
|
@@ -563,7 +681,8 @@
|
|
|
563
681
|
background: rgba(124, 124, 133, 0.09);
|
|
564
682
|
}
|
|
565
683
|
.revision-future .revision-card-titlebar {
|
|
566
|
-
background: rgba(
|
|
684
|
+
background: rgba(37, 99, 201, 0.07);
|
|
685
|
+
border-bottom-color: rgba(37, 99, 201, 0.14);
|
|
567
686
|
}
|
|
568
687
|
.revision-card-actions {
|
|
569
688
|
display: inline-flex;
|
|
@@ -643,4 +762,12 @@
|
|
|
643
762
|
.detail {
|
|
644
763
|
overflow: visible;
|
|
645
764
|
}
|
|
765
|
+
.detail-hero {
|
|
766
|
+
position: static;
|
|
767
|
+
margin: 0;
|
|
768
|
+
padding: 0;
|
|
769
|
+
border-bottom: 0;
|
|
770
|
+
background: transparent;
|
|
771
|
+
backdrop-filter: none;
|
|
772
|
+
}
|
|
646
773
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const projectSelect = document.querySelector("[data-project-select]");
|
|
3
3
|
const fromSelect = document.querySelector("[data-from-select]");
|
|
4
4
|
const toSelect = document.querySelector("[data-to-select]");
|
|
5
|
+
const projectActionButtons = Array.from(document.querySelectorAll("[data-project-action]"));
|
|
5
6
|
const sidebarPanel = document.querySelector("[data-sidebar-panel]");
|
|
6
7
|
const filterButtons = Array.from(document.querySelectorAll("[data-filter-button]"));
|
|
7
8
|
const ecosystemButtons = Array.from(document.querySelectorAll("[data-ecosystem-button]"));
|
|
@@ -34,7 +35,9 @@
|
|
|
34
35
|
});
|
|
35
36
|
};
|
|
36
37
|
const packageNameParam = (url) => url.searchParams.get("package") || url.searchParams.get("gem");
|
|
38
|
+
const packageIdParam = (url) => url.searchParams.get("package_id");
|
|
37
39
|
const requestedGemName = () => packageNameParam(new URL(window.location.href));
|
|
40
|
+
const requestedPackageId = () => packageIdParam(new URL(window.location.href));
|
|
38
41
|
const currentDetailGemName = () => {
|
|
39
42
|
if (!detailPanel || !detailPanel.dataset.detailUrl) return null;
|
|
40
43
|
|
|
@@ -44,6 +47,15 @@
|
|
|
44
47
|
return null;
|
|
45
48
|
}
|
|
46
49
|
};
|
|
50
|
+
const currentDetailPackageId = () => {
|
|
51
|
+
if (!detailPanel || !detailPanel.dataset.detailUrl) return null;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
return packageIdParam(new URL(detailPanel.dataset.detailUrl, window.location.origin));
|
|
55
|
+
} catch (_error) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
47
59
|
const detailNeedsInitialFetch = () => detailPanel && detailPanel.dataset.detailDeferred === "true" && !!detailPanel.dataset.detailUrl;
|
|
48
60
|
const isSidebarFocused = () => document.activeElement === sidebarPanel;
|
|
49
61
|
const isDetailFocused = () => detailPanel && document.activeElement === detailPanel;
|
|
@@ -53,6 +65,73 @@
|
|
|
53
65
|
const focusDetail = () => {
|
|
54
66
|
if (detailPanel) detailPanel.focus({ preventScroll: true });
|
|
55
67
|
};
|
|
68
|
+
const closeCommandErrorDialog = () => {
|
|
69
|
+
const overlay = document.querySelector("[data-command-error-dialog]");
|
|
70
|
+
if (overlay) overlay.remove();
|
|
71
|
+
};
|
|
72
|
+
const showCommandErrorDialog = (command, output) => {
|
|
73
|
+
closeCommandErrorDialog();
|
|
74
|
+
|
|
75
|
+
const overlay = document.createElement("div");
|
|
76
|
+
overlay.className = "command-dialog-backdrop";
|
|
77
|
+
overlay.dataset.commandErrorDialog = "true";
|
|
78
|
+
|
|
79
|
+
const dialog = document.createElement("section");
|
|
80
|
+
dialog.className = "command-dialog";
|
|
81
|
+
dialog.setAttribute("role", "alertdialog");
|
|
82
|
+
dialog.setAttribute("aria-modal", "true");
|
|
83
|
+
dialog.setAttribute("aria-labelledby", "command-dialog-title");
|
|
84
|
+
|
|
85
|
+
const header = document.createElement("header");
|
|
86
|
+
header.className = "command-dialog-header";
|
|
87
|
+
|
|
88
|
+
const title = document.createElement("h2");
|
|
89
|
+
title.id = "command-dialog-title";
|
|
90
|
+
title.textContent = "Command failed";
|
|
91
|
+
|
|
92
|
+
const commandLine = document.createElement("p");
|
|
93
|
+
commandLine.className = "command-dialog-command";
|
|
94
|
+
commandLine.textContent = command;
|
|
95
|
+
|
|
96
|
+
header.append(title, commandLine);
|
|
97
|
+
|
|
98
|
+
const outputField = document.createElement("pre");
|
|
99
|
+
outputField.className = "command-dialog-output";
|
|
100
|
+
outputField.tabIndex = 0;
|
|
101
|
+
outputField.textContent = output || "No output captured.";
|
|
102
|
+
|
|
103
|
+
const actions = document.createElement("div");
|
|
104
|
+
actions.className = "command-dialog-actions";
|
|
105
|
+
|
|
106
|
+
const copyButton = document.createElement("button");
|
|
107
|
+
copyButton.type = "button";
|
|
108
|
+
copyButton.className = "action";
|
|
109
|
+
copyButton.textContent = "Copy";
|
|
110
|
+
copyButton.addEventListener("click", () => {
|
|
111
|
+
navigator.clipboard.writeText(`Command failed: ${command}\n\n${output || ""}`)
|
|
112
|
+
.then(() => {
|
|
113
|
+
copyButton.textContent = "Copied";
|
|
114
|
+
setTimeout(() => {
|
|
115
|
+
copyButton.textContent = "Copy";
|
|
116
|
+
}, 1400);
|
|
117
|
+
})
|
|
118
|
+
.catch(() => {
|
|
119
|
+
outputField.focus();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const closeButton = document.createElement("button");
|
|
124
|
+
closeButton.type = "button";
|
|
125
|
+
closeButton.className = "action action-primary";
|
|
126
|
+
closeButton.textContent = "Close";
|
|
127
|
+
closeButton.addEventListener("click", closeCommandErrorDialog);
|
|
128
|
+
|
|
129
|
+
actions.append(copyButton, closeButton);
|
|
130
|
+
dialog.append(header, outputField, actions);
|
|
131
|
+
overlay.append(dialog);
|
|
132
|
+
document.body.append(overlay);
|
|
133
|
+
closeButton.focus({ preventScroll: true });
|
|
134
|
+
};
|
|
56
135
|
const storedDetailDisclosureOpen = () => {
|
|
57
136
|
try {
|
|
58
137
|
return window.localStorage.getItem(detailDisclosureStorageKey) === "true";
|
|
@@ -82,6 +161,7 @@
|
|
|
82
161
|
const applyGemFilter = (filter) => {
|
|
83
162
|
currentFilter = filter;
|
|
84
163
|
const pinnedGemName = requestedGemName();
|
|
164
|
+
const pinnedPackageId = requestedPackageId();
|
|
85
165
|
const searchTerm = currentSearch.trim().toLowerCase();
|
|
86
166
|
|
|
87
167
|
filterButtons.forEach((button) => {
|
|
@@ -94,7 +174,7 @@
|
|
|
94
174
|
|
|
95
175
|
gemLinks.forEach((link) => {
|
|
96
176
|
const updated = link.dataset.gemUpdated === "true";
|
|
97
|
-
const pinned = pinnedGemName && link.dataset.gemName === pinnedGemName;
|
|
177
|
+
const pinned = pinnedPackageId ? link.dataset.packageId === pinnedPackageId : pinnedGemName && link.dataset.gemName === pinnedGemName;
|
|
98
178
|
const matchesScope = currentPackageScope === "all" || link.dataset.packageScope === currentPackageScope;
|
|
99
179
|
const matchesSearch = searchTerm === "" || link.dataset.gemName.toLowerCase().includes(searchTerm);
|
|
100
180
|
link.hidden = (!matchesScope || (filter === "updated" && !updated && !pinned) || !matchesSearch);
|
|
@@ -115,16 +195,34 @@
|
|
|
115
195
|
}
|
|
116
196
|
};
|
|
117
197
|
|
|
118
|
-
const
|
|
198
|
+
const keepSidebarLinkVisible = (link) => {
|
|
199
|
+
if (!sidebarPanel || !link) return;
|
|
200
|
+
|
|
201
|
+
const panelBounds = sidebarPanel.getBoundingClientRect();
|
|
202
|
+
const stickyHeader = sidebarPanel.querySelector(".sidebar-header");
|
|
203
|
+
const headerBounds = stickyHeader && stickyHeader.getBoundingClientRect();
|
|
204
|
+
const linkBounds = link.getBoundingClientRect();
|
|
205
|
+
const visibleTop = headerBounds ? Math.max(panelBounds.top, headerBounds.bottom) : panelBounds.top;
|
|
206
|
+
|
|
207
|
+
if (linkBounds.top < visibleTop) {
|
|
208
|
+
sidebarPanel.scrollTop -= visibleTop - linkBounds.top;
|
|
209
|
+
} else if (linkBounds.bottom > panelBounds.bottom) {
|
|
210
|
+
sidebarPanel.scrollTop += linkBounds.bottom - panelBounds.bottom;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const syncSidebarSelection = (packageId = null, gemName = null, keepVisible = false) => {
|
|
215
|
+
const effectivePackageId = packageId || requestedPackageId();
|
|
119
216
|
const effectiveGemName = gemName || requestedGemName();
|
|
120
|
-
if (!effectiveGemName) {
|
|
217
|
+
if (!effectivePackageId && !effectiveGemName) {
|
|
121
218
|
clearSidebarSelection();
|
|
122
219
|
return;
|
|
123
220
|
}
|
|
124
221
|
|
|
125
222
|
let selectedLink = null;
|
|
126
223
|
gemLinks.forEach((link) => {
|
|
127
|
-
const
|
|
224
|
+
const identityMatches = effectivePackageId ? link.dataset.packageId === effectivePackageId : link.dataset.gemName === effectiveGemName;
|
|
225
|
+
const matches = !link.hidden && identityMatches;
|
|
128
226
|
link.classList.toggle("is-selected", matches);
|
|
129
227
|
if (matches) {
|
|
130
228
|
selectedLink = link;
|
|
@@ -132,7 +230,7 @@
|
|
|
132
230
|
});
|
|
133
231
|
|
|
134
232
|
if (keepVisible && sidebarPanel && selectedLink) {
|
|
135
|
-
selectedLink
|
|
233
|
+
keepSidebarLinkVisible(selectedLink);
|
|
136
234
|
}
|
|
137
235
|
};
|
|
138
236
|
|
|
@@ -211,7 +309,7 @@
|
|
|
211
309
|
window.history[historyMethod]({}, "", pageUrl);
|
|
212
310
|
}
|
|
213
311
|
const detailUrl = new URL(url, window.location.origin);
|
|
214
|
-
syncSidebarSelection(packageNameParam(detailUrl));
|
|
312
|
+
syncSidebarSelection(packageIdParam(detailUrl), packageNameParam(detailUrl));
|
|
215
313
|
})
|
|
216
314
|
.catch(() => {
|
|
217
315
|
stopDetailLoading();
|
|
@@ -223,7 +321,7 @@
|
|
|
223
321
|
|
|
224
322
|
stopDetailPoll();
|
|
225
323
|
stopDetailLoading();
|
|
226
|
-
syncSidebarSelection(link.dataset.gemName, keepVisible);
|
|
324
|
+
syncSidebarSelection(link.dataset.packageId, link.dataset.gemName, keepVisible);
|
|
227
325
|
fetchDetail(link.dataset.detailUrl || link.href, historyMode);
|
|
228
326
|
|
|
229
327
|
focusSidebar();
|
|
@@ -231,13 +329,17 @@
|
|
|
231
329
|
|
|
232
330
|
const ensureInitialGemSelection = () => {
|
|
233
331
|
const requested = requestedGemName();
|
|
332
|
+
const requestedId = requestedPackageId();
|
|
234
333
|
|
|
235
334
|
const detailGemName = currentDetailGemName();
|
|
236
|
-
const
|
|
335
|
+
const detailPackageId = currentDetailPackageId();
|
|
336
|
+
const detailLink = detailPackageId ?
|
|
337
|
+
visibleGemLinks().find((link) => link.dataset.packageId === detailPackageId) :
|
|
338
|
+
(detailGemName ? visibleGemLinks().find((link) => link.dataset.gemName === detailGemName) : null);
|
|
237
339
|
|
|
238
340
|
if (detailLink) {
|
|
239
|
-
syncSidebarSelection(
|
|
240
|
-
if (!requested) {
|
|
341
|
+
syncSidebarSelection(detailLink.dataset.packageId, detailLink.dataset.gemName, true);
|
|
342
|
+
if (!requested && !requestedId) {
|
|
241
343
|
const pageUrl = new URL(window.location.href);
|
|
242
344
|
const detailUrl = new URL(detailLink.dataset.detailUrl || detailLink.href, window.location.origin);
|
|
243
345
|
pageUrl.search = detailUrl.search;
|
|
@@ -246,19 +348,19 @@
|
|
|
246
348
|
window.history.replaceState({}, "", pageUrl);
|
|
247
349
|
}
|
|
248
350
|
if (detailNeedsInitialFetch()) {
|
|
249
|
-
fetchDetail(detailLink.dataset.detailUrl || detailLink.href, requested ? "none" : "replace", { refresh: pendingManualDetailRefresh });
|
|
351
|
+
fetchDetail(detailLink.dataset.detailUrl || detailLink.href, requested || requestedId ? "none" : "replace", { refresh: pendingManualDetailRefresh });
|
|
250
352
|
pendingManualDetailRefresh = false;
|
|
251
353
|
}
|
|
252
354
|
return;
|
|
253
355
|
}
|
|
254
356
|
|
|
255
|
-
if (requested) return;
|
|
357
|
+
if (requested || requestedId) return;
|
|
256
358
|
|
|
257
359
|
const firstVisibleLink = visibleGemLinks()[0];
|
|
258
360
|
if (firstVisibleLink) {
|
|
259
361
|
const refresh = pendingManualDetailRefresh;
|
|
260
362
|
pendingManualDetailRefresh = false;
|
|
261
|
-
syncSidebarSelection(firstVisibleLink.dataset.gemName, true);
|
|
363
|
+
syncSidebarSelection(firstVisibleLink.dataset.packageId, firstVisibleLink.dataset.gemName, true);
|
|
262
364
|
fetchDetail(firstVisibleLink.dataset.detailUrl || firstVisibleLink.href, "replace", { refresh });
|
|
263
365
|
focusSidebar();
|
|
264
366
|
}
|
|
@@ -279,7 +381,7 @@
|
|
|
279
381
|
scheduleDetailPoll();
|
|
280
382
|
}
|
|
281
383
|
|
|
282
|
-
syncSidebarSelection(null, true);
|
|
384
|
+
syncSidebarSelection(null, null, true);
|
|
283
385
|
applyGemFilter(currentFilter);
|
|
284
386
|
ensureInitialGemSelection();
|
|
285
387
|
|
|
@@ -299,7 +401,7 @@
|
|
|
299
401
|
const url = new URL(window.location.href);
|
|
300
402
|
url.searchParams.set("filter", currentFilter);
|
|
301
403
|
window.history.replaceState({}, "", url);
|
|
302
|
-
syncSidebarSelection(null, true);
|
|
404
|
+
syncSidebarSelection(null, null, true);
|
|
303
405
|
});
|
|
304
406
|
});
|
|
305
407
|
|
|
@@ -313,7 +415,7 @@
|
|
|
313
415
|
const url = new URL(window.location.href);
|
|
314
416
|
url.searchParams.set("scope", currentPackageScope);
|
|
315
417
|
window.history.replaceState({}, "", url);
|
|
316
|
-
syncSidebarSelection(null, true);
|
|
418
|
+
syncSidebarSelection(null, null, true);
|
|
317
419
|
});
|
|
318
420
|
});
|
|
319
421
|
|
|
@@ -324,7 +426,7 @@
|
|
|
324
426
|
if (sidebarPanel) {
|
|
325
427
|
sidebarPanel.scrollTop = 0;
|
|
326
428
|
}
|
|
327
|
-
syncSidebarSelection(null, true);
|
|
429
|
+
syncSidebarSelection(null, null, true);
|
|
328
430
|
});
|
|
329
431
|
}
|
|
330
432
|
|
|
@@ -338,6 +440,55 @@
|
|
|
338
440
|
fetchDetail(detailPanel.dataset.detailUrl, "none", { refresh: true, useGh: true });
|
|
339
441
|
});
|
|
340
442
|
|
|
443
|
+
projectActionButtons.forEach((button) => {
|
|
444
|
+
button.addEventListener("click", () => {
|
|
445
|
+
const actionId = button.dataset.projectAction;
|
|
446
|
+
const command = button.dataset.projectActionCommand || actionId;
|
|
447
|
+
if (!actionId) return;
|
|
448
|
+
if (!window.confirm(`Run ${command}?`)) return;
|
|
449
|
+
|
|
450
|
+
const originalText = button.textContent;
|
|
451
|
+
projectActionButtons.forEach((actionButton) => {
|
|
452
|
+
actionButton.disabled = true;
|
|
453
|
+
});
|
|
454
|
+
button.textContent = "Running...";
|
|
455
|
+
|
|
456
|
+
const params = new URLSearchParams();
|
|
457
|
+
params.set("project", "<%= selected_project_index %>");
|
|
458
|
+
|
|
459
|
+
fetch(`/actions/${encodeURIComponent(actionId)}`, {
|
|
460
|
+
method: "POST",
|
|
461
|
+
headers: {
|
|
462
|
+
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
463
|
+
"X-Requested-With": "gemstar-action"
|
|
464
|
+
},
|
|
465
|
+
body: params.toString()
|
|
466
|
+
})
|
|
467
|
+
.then((response) => response.json().then((payload) => ({ response, payload })))
|
|
468
|
+
.then(({ response, payload }) => {
|
|
469
|
+
if (!response.ok || !payload.ok) {
|
|
470
|
+
const output = payload && payload.output ? payload.output : "";
|
|
471
|
+
const failedCommand = payload && payload.command ? payload.command : command;
|
|
472
|
+
showCommandErrorDialog(failedCommand, output);
|
|
473
|
+
button.textContent = originalText;
|
|
474
|
+
projectActionButtons.forEach((actionButton) => {
|
|
475
|
+
actionButton.disabled = false;
|
|
476
|
+
});
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
window.location.reload();
|
|
481
|
+
})
|
|
482
|
+
.catch((error) => {
|
|
483
|
+
showCommandErrorDialog(command, error.message);
|
|
484
|
+
button.textContent = originalText;
|
|
485
|
+
projectActionButtons.forEach((actionButton) => {
|
|
486
|
+
actionButton.disabled = false;
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
|
|
341
492
|
const navigate = (params) => {
|
|
342
493
|
const url = new URL(window.location.href);
|
|
343
494
|
Object.entries(params).forEach(([key, value]) => {
|
|
@@ -357,23 +508,29 @@
|
|
|
357
508
|
event.target.value = "<%= selected_project_index %>";
|
|
358
509
|
return;
|
|
359
510
|
}
|
|
360
|
-
navigate({ project: event.target.value, from: null, to: "worktree", filter: currentFilter, scope: currentPackageScope, package: null, gem: null });
|
|
511
|
+
navigate({ project: event.target.value, from: null, to: "worktree", filter: currentFilter, scope: currentPackageScope, package: null, package_id: null, gem: null });
|
|
361
512
|
});
|
|
362
513
|
}
|
|
363
514
|
|
|
364
515
|
if (fromSelect) {
|
|
365
516
|
fromSelect.addEventListener("change", (event) => {
|
|
366
|
-
navigate({ from: event.target.value, filter: currentFilter, scope: currentPackageScope, package: null, gem: null });
|
|
517
|
+
navigate({ from: event.target.value, filter: currentFilter, scope: currentPackageScope, package: null, package_id: null, gem: null });
|
|
367
518
|
});
|
|
368
519
|
}
|
|
369
520
|
|
|
370
521
|
if (toSelect) {
|
|
371
522
|
toSelect.addEventListener("change", (event) => {
|
|
372
|
-
navigate({ to: event.target.value, filter: currentFilter, scope: currentPackageScope, package: null, gem: null });
|
|
523
|
+
navigate({ to: event.target.value, filter: currentFilter, scope: currentPackageScope, package: null, package_id: null, gem: null });
|
|
373
524
|
});
|
|
374
525
|
}
|
|
375
526
|
|
|
376
527
|
document.addEventListener("keydown", (event) => {
|
|
528
|
+
if (event.key === "Escape" && document.querySelector("[data-command-error-dialog]")) {
|
|
529
|
+
event.preventDefault();
|
|
530
|
+
closeCommandErrorDialog();
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
|
|
377
534
|
const tagName = document.activeElement && document.activeElement.tagName;
|
|
378
535
|
if (tagName === "INPUT" || tagName === "TEXTAREA" || tagName === "SELECT") return;
|
|
379
536
|
|
|
@@ -421,7 +578,7 @@
|
|
|
421
578
|
if (!links.length) return;
|
|
422
579
|
|
|
423
580
|
const selectedGem = currentSelectedIndex();
|
|
424
|
-
const currentIndex = selectedGem >= 0 ? selectedGem :
|
|
581
|
+
const currentIndex = selectedGem >= 0 ? selectedGem : (event.key === "ArrowUp" ? links.length : -1);
|
|
425
582
|
let nextIndex = null;
|
|
426
583
|
|
|
427
584
|
if (event.key === "ArrowDown") nextIndex = Math.min(currentIndex + 1, links.length - 1);
|
data/lib/gemstar.rb
CHANGED
|
@@ -9,6 +9,8 @@ require "gemstar/commands/cache"
|
|
|
9
9
|
require "gemstar/commands/diff"
|
|
10
10
|
require "gemstar/commands/server"
|
|
11
11
|
require "gemstar/config"
|
|
12
|
+
require "gemstar/cargo_lock_file"
|
|
13
|
+
require "gemstar/crates_io_metadata"
|
|
12
14
|
require "gemstar/outputs/basic"
|
|
13
15
|
require "gemstar/outputs/html"
|
|
14
16
|
require "gemstar/outputs/markdown"
|
|
@@ -19,8 +21,10 @@ require "gemstar/importmap_file"
|
|
|
19
21
|
require "gemstar/lock_file"
|
|
20
22
|
require "gemstar/npm_metadata"
|
|
21
23
|
require "gemstar/package_lock_file"
|
|
24
|
+
require "gemstar/pypi_metadata"
|
|
22
25
|
require "gemstar/project"
|
|
23
26
|
require "gemstar/remote_repository"
|
|
24
27
|
require "gemstar/utils"
|
|
25
28
|
require "gemstar/ruby_gems_metadata"
|
|
29
|
+
require "gemstar/uv_lock_file"
|
|
26
30
|
require "gemstar/git_repo"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gemstar
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.3'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Florian Dejako
|
|
@@ -219,8 +219,8 @@ dependencies:
|
|
|
219
219
|
- - "~>"
|
|
220
220
|
- !ruby/object:Gem::Version
|
|
221
221
|
version: '1.9'
|
|
222
|
-
description:
|
|
223
|
-
|
|
222
|
+
description: Browse and compare changelogs for Ruby gems, JavaScript packages, Python
|
|
223
|
+
packages, and Rust crates in your projects.
|
|
224
224
|
email:
|
|
225
225
|
- fdejako@gmail.com
|
|
226
226
|
executables:
|
|
@@ -236,6 +236,7 @@ files:
|
|
|
236
236
|
- lib/gemstar/cache.rb
|
|
237
237
|
- lib/gemstar/cache_cli.rb
|
|
238
238
|
- lib/gemstar/cache_warmer.rb
|
|
239
|
+
- lib/gemstar/cargo_lock_file.rb
|
|
239
240
|
- lib/gemstar/change_log.rb
|
|
240
241
|
- lib/gemstar/cli.rb
|
|
241
242
|
- lib/gemstar/commands/cache.rb
|
|
@@ -243,6 +244,7 @@ files:
|
|
|
243
244
|
- lib/gemstar/commands/diff.rb
|
|
244
245
|
- lib/gemstar/commands/server.rb
|
|
245
246
|
- lib/gemstar/config.rb
|
|
247
|
+
- lib/gemstar/crates_io_metadata.rb
|
|
246
248
|
- lib/gemstar/data/importmap_package_metadata.json
|
|
247
249
|
- lib/gemstar/data/ruby_gems_metadata.json
|
|
248
250
|
- lib/gemstar/git_hub.rb
|
|
@@ -255,10 +257,12 @@ files:
|
|
|
255
257
|
- lib/gemstar/outputs/markdown.rb
|
|
256
258
|
- lib/gemstar/package_lock_file.rb
|
|
257
259
|
- lib/gemstar/project.rb
|
|
260
|
+
- lib/gemstar/pypi_metadata.rb
|
|
258
261
|
- lib/gemstar/remote_repository.rb
|
|
259
262
|
- lib/gemstar/request_logger.rb
|
|
260
263
|
- lib/gemstar/ruby_gems_metadata.rb
|
|
261
264
|
- lib/gemstar/utils.rb
|
|
265
|
+
- lib/gemstar/uv_lock_file.rb
|
|
262
266
|
- lib/gemstar/version.rb
|
|
263
267
|
- lib/gemstar/web/app.rb
|
|
264
268
|
- lib/gemstar/web/templates/app.css
|
|
@@ -288,5 +292,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
288
292
|
requirements: []
|
|
289
293
|
rubygems_version: 3.6.9
|
|
290
294
|
specification_version: 4
|
|
291
|
-
summary:
|
|
295
|
+
summary: Changelog viewer for Ruby, JavaScript, Python, and Rust dependencies.
|
|
292
296
|
test_files: []
|