prreviewbuddy 0.82.1 → 0.83.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/CHANGELOG.md +58 -0
- package/dist/server.js +180 -65
- package/package.json +1 -1
- package/static/{chunk-CxFmUaBj.js → chunk-B2vcrGTe.js} +1 -1
- package/static/{chunk-CWRKWlhO.js → chunk-BL6xJoZm.js} +1 -1
- package/static/chunk-DWTt0jUK.js +1 -0
- package/static/chunk-DwdwtB9r.js +1 -0
- package/static/help.js +1 -1
- package/static/notifications.js +1 -1
- package/static/reviews.js +1 -1
- package/static/runs.js +1 -1
- package/static/settings.js +1 -1
- package/static/shell.css +172 -44
- package/static/workspace.js +58 -58
- package/static/chunk-CQNkZ9TG.js +0 -1
- package/static/chunk-h55PfL_M.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.83.3
|
|
4
|
+
|
|
5
|
+
**Peek at a collapsed sidebar.** Rest the pointer on the collapsed sidebar, or tab into it, and it
|
|
6
|
+
slides out to full width over the page, with every name and section, until you move away. The page
|
|
7
|
+
underneath stays where it was, and the sidebar stays collapsed.
|
|
8
|
+
|
|
9
|
+
## 0.83.2
|
|
10
|
+
|
|
11
|
+
**Send feedback is only in the sidebar.** A narrow window no longer draws a Send feedback link in
|
|
12
|
+
the top toolbar; it is in the sidebar, expanded or collapsed, and nowhere else.
|
|
13
|
+
|
|
14
|
+
## 0.83.1
|
|
15
|
+
|
|
16
|
+
**New review is the sidebar's one purple button, and Collapse sidebar moves to the sidebar's foot.**
|
|
17
|
+
New review is filled in purple wherever it is: the full-width button, the square + of the collapsed
|
|
18
|
+
sidebar, and the + in the top toolbar. Collapse sidebar is now the last row of the sidebar, below
|
|
19
|
+
Send feedback, and expands it again from the same place. While the sidebar is hidden, Show sidebar
|
|
20
|
+
in the top toolbar brings it back, and Send feedback is hidden with it.
|
|
21
|
+
|
|
22
|
+
## 0.83.0
|
|
23
|
+
|
|
24
|
+
**Start a review from New review in the sidebar, and collapse the sidebar to icons.** A New review
|
|
25
|
+
button, with its shortcut beside it, sits above Reviews in the sidebar on every workspace page. It
|
|
26
|
+
opens the same panel as ⌘P (Ctrl+P on other platforms), which works as before; that panel is now
|
|
27
|
+
called New review too. The button at the far left of the top toolbar collapses the sidebar to a
|
|
28
|
+
column of icons, with New review as a + and each name shown on hover, and expands it again. ⌘K H
|
|
29
|
+
hides the sidebar completely; the same toolbar button then brings it back, and a + in the toolbar
|
|
30
|
+
starts a review while it is hidden. Your choice is remembered.
|
|
31
|
+
|
|
32
|
+
## 0.82.5
|
|
33
|
+
|
|
34
|
+
**Help explains Collections more plainly.** The Collections topic in Workspace Help now says what
|
|
35
|
+
collections are for, how to add reviews, what happens when one is marked Done, and that collapsing
|
|
36
|
+
helps you stay focused. The note on how long reviews in a collection are kept is unchanged.
|
|
37
|
+
|
|
38
|
+
## 0.82.4
|
|
39
|
+
|
|
40
|
+
**⌘K L C lists your collections, to expand or collapse one.** Each row shows the collection's
|
|
41
|
+
name, its count and whether it is expanded. Move with J and K or the arrows and press Enter, or
|
|
42
|
+
press a row's number. Expanding a collection from here also lets J and K walk into its reviews.
|
|
43
|
+
New collection moves to ⌘K L N.
|
|
44
|
+
|
|
45
|
+
## 0.82.3
|
|
46
|
+
|
|
47
|
+
**⌘K L C makes a new collection.** It opens the same New collection dialog as the button beside
|
|
48
|
+
Select. After you create or rename a collection, its heading takes focus without the keyboard ring
|
|
49
|
+
the name field had; Tab brings the ring back. While a new collection is being made, its name is
|
|
50
|
+
locked and the dialog cannot be opened again, so a slow answer can never close or change the next
|
|
51
|
+
one you start.
|
|
52
|
+
|
|
53
|
+
## 0.82.2
|
|
54
|
+
|
|
55
|
+
**Collections sit in the list like any other section.** Each collection is now a section between
|
|
56
|
+
Pinned and Active, with no Collections heading above them, and nothing is drawn for collections
|
|
57
|
+
until you make one. New collection moves up beside Select and opens a small dialog that says what a
|
|
58
|
+
collection is for, with Cancel and Create. A collection whose reviews are all Done now says "No
|
|
59
|
+
active reviews".
|
|
60
|
+
|
|
3
61
|
## 0.82.1
|
|
4
62
|
|
|
5
63
|
**Back no longer draws a focus ring you never had.** Going Back or Forward puts focus where you
|
package/dist/server.js
CHANGED
|
@@ -376,7 +376,7 @@ function collectionEmptyText(counts, filtered) {
|
|
|
376
376
|
if (filtered) return "Nothing in this collection matches the filters.";
|
|
377
377
|
if (counts.members === 0) return "Nothing here yet. Add reviews from a card’s menu, or select several and choose Manage collections.";
|
|
378
378
|
if (counts.pinned > 0 && counts.completed === 0) return "Its reviews are pinned, so they are listed under Pinned.";
|
|
379
|
-
return "
|
|
379
|
+
return "No active reviews";
|
|
380
380
|
}
|
|
381
381
|
/** Said under a collection whose oldest members are not drawn, so it never looks smaller than it is. */
|
|
382
382
|
function omittedText(omitted) {
|
|
@@ -803,7 +803,10 @@ var PATHS = {
|
|
|
803
803
|
closed: "<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"m5.6 5.6 12.8 12.8\"/>",
|
|
804
804
|
reopened: "<circle cx=\"12\" cy=\"12\" r=\"9\"/><circle cx=\"12\" cy=\"12\" r=\"2\"/>",
|
|
805
805
|
warning: "<path d=\"M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z\"/><path d=\"M12 9v4M12 17h.01\"/>",
|
|
806
|
-
forward: "<path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/>"
|
|
806
|
+
forward: "<path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/>",
|
|
807
|
+
plus: "<path d=\"M12 5v14M5 12h14\"/>",
|
|
808
|
+
"sidebar-collapse": "<rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\"/><path d=\"M9 4v16\"/><path d=\"m16 9-3 3 3 3\"/>",
|
|
809
|
+
"sidebar-expand": "<rect x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2\"/><path d=\"M9 4v16\"/><path d=\"m13 9 3 3-3 3\"/>"
|
|
807
810
|
};
|
|
808
811
|
/** The icon slot for one rail row. Hidden from assistive technology: the label beside it says it. */
|
|
809
812
|
function railIcon(icon) {
|
|
@@ -863,6 +866,18 @@ function serverStatusLabel(status) {
|
|
|
863
866
|
return "Workspace server running";
|
|
864
867
|
}
|
|
865
868
|
//#endregion
|
|
869
|
+
//#region ../../packages/review-harness/src/workspace/sidebar_state.ts
|
|
870
|
+
/**
|
|
871
|
+
* What the sidebar's own toggle, at its foot, will do when pressed, which is what it is called.
|
|
872
|
+
* Only Expanded and Compact: while the sidebar is hidden that toggle is not drawn, and the strip's
|
|
873
|
+
* restore control, which only ever says Show sidebar, stands in for it.
|
|
874
|
+
*/
|
|
875
|
+
function sidebarToggleLabel(sidebar) {
|
|
876
|
+
return sidebar?.compact ? "Expand sidebar" : "Collapse sidebar";
|
|
877
|
+
}
|
|
878
|
+
/** The strip's restore control, drawn only while the sidebar is hidden. */
|
|
879
|
+
var SHOW_SIDEBAR = "Show sidebar";
|
|
880
|
+
//#endregion
|
|
866
881
|
//#region ../../packages/review-harness/src/workspace/workspace_nav.ts
|
|
867
882
|
/**
|
|
868
883
|
* The workspace's own places, and the one model every page draws them from.
|
|
@@ -905,6 +920,13 @@ var WORKSPACE_PLACES = [
|
|
|
905
920
|
}
|
|
906
921
|
];
|
|
907
922
|
/**
|
|
923
|
+
* The sidebar's state, on `<html>` beside the theme, so the page is drawn that way from its first
|
|
924
|
+
* paint. The stylesheet reads it; `client/sidebar.ts` changes it.
|
|
925
|
+
*/
|
|
926
|
+
function sidebarAttributes(sidebar) {
|
|
927
|
+
return `${sidebar?.compact ? " data-sidebar-compact" : ""}${sidebar?.hidden ? " data-sidebar-hidden" : ""}`;
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
908
930
|
* The count beside Notifications. Always rendered, hidden at zero, so the page can reveal it when
|
|
909
931
|
* `/revision` or Mark all read reports a new number. See `client/unread_counts.ts`.
|
|
910
932
|
*/
|
|
@@ -934,7 +956,8 @@ function renderGlobalBar(options) {
|
|
|
934
956
|
const live = options.live ?? true;
|
|
935
957
|
return `<header class="prb-strip">
|
|
936
958
|
<span class="prb-wordmark"><b>pr</b>review<b>buddy</b></span>
|
|
937
|
-
${live ?
|
|
959
|
+
${live ? renderSidebarRestore() : ""}
|
|
960
|
+
${live ? renderNewReview() : ""}
|
|
938
961
|
${live ? renderHistoryControls() : ""}
|
|
939
962
|
${live ? renderStripReviews(options) : ""}
|
|
940
963
|
${live ? renderStripRuns(options) : ""}
|
|
@@ -980,6 +1003,37 @@ function renderNotificationsBell(options) {
|
|
|
980
1003
|
</a>`;
|
|
981
1004
|
}
|
|
982
1005
|
/**
|
|
1006
|
+
* Show sidebar: the way back from Hidden, and drawn only then (see `shell.css`). Among the strip's
|
|
1007
|
+
* controls rather than beside the wordmark, so it reads as a control and not as part of the brand.
|
|
1008
|
+
* Named in words and in the strip's own tooltip, never a `title`.
|
|
1009
|
+
*/
|
|
1010
|
+
function renderSidebarRestore() {
|
|
1011
|
+
return `<button type="button" class="prb-strip-action prb-sidebar-restore" data-sidebar-toggle="strip" aria-label="${SHOW_SIDEBAR}" data-tip="${SHOW_SIDEBAR}">${iconSvg("sidebar-expand")}</button>`;
|
|
1012
|
+
}
|
|
1013
|
+
/**
|
|
1014
|
+
* The sidebar's own toggle, the last row of its foot: Expanded and Compact, back and forth.
|
|
1015
|
+
*
|
|
1016
|
+
* In the same place in both, so it never moves under the pointer that pressed it. Hidden is not a
|
|
1017
|
+
* third press: it is its own act (⌘K H), and the strip's Show sidebar brings it back at the width it
|
|
1018
|
+
* had. The row's words say what pressing it will do, and in Compact they are its tooltip, as every
|
|
1019
|
+
* row's are. Both drawings are rendered and the stylesheet shows the one for the state, so nothing
|
|
1020
|
+
* needs repainting but the words. `client/sidebar.ts` keeps those true.
|
|
1021
|
+
*/
|
|
1022
|
+
function renderSidebarToggle(sidebar) {
|
|
1023
|
+
return `<button type="button" class="prb-rail-item prb-rail-link prb-sidebar-toggle" data-sidebar-toggle="rail" aria-expanded="${!sidebar?.compact}">
|
|
1024
|
+
<span class="prb-rail-icon" aria-hidden="true"><span class="prb-sidebar-collapse-icon">${iconSvg("sidebar-collapse")}</span><span class="prb-sidebar-expand-icon">${iconSvg("sidebar-expand")}</span></span>
|
|
1025
|
+
<span class="prb-rail-label"><span class="prb-rail-title">${sidebarToggleLabel(sidebar)}</span></span>
|
|
1026
|
+
</button>`;
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* New review, in the strip: the square stand-in for the rail's labelled button, shown only while
|
|
1030
|
+
* the rail is hidden (a narrow window, a review's focus mode). See `renderNewReviewButton`, and
|
|
1031
|
+
* `shell.css` for the one rule that decides which of the two is showing.
|
|
1032
|
+
*/
|
|
1033
|
+
function renderNewReview() {
|
|
1034
|
+
return `<button type="button" class="prb-strip-action prb-strip-new-review" aria-label="New review" data-new-review="strip">${iconSvg("plus")}</button>`;
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
983
1037
|
* Back and Forward through this tab's workspace history, ahead of the places.
|
|
984
1038
|
*
|
|
985
1039
|
* Workspace-wide, so here in the strip rather than in a review's own bar: they move between views,
|
|
@@ -1058,9 +1112,20 @@ function renderServerStatus() {
|
|
|
1058
1112
|
<span class="prb-visually-hidden" data-server-status-label>${escapeHtml$1(serverStatusLabel("running"))}</span>
|
|
1059
1113
|
</span>`;
|
|
1060
1114
|
}
|
|
1061
|
-
/**
|
|
1115
|
+
/**
|
|
1116
|
+
* New review, at the head of the workspace rows: starting a review is the product's primary action,
|
|
1117
|
+
* so it is a labelled button rather than an icon to interpret, set apart from the places below it.
|
|
1118
|
+
*
|
|
1119
|
+
* What it does is wired by the command layer (`client/command_layer.ts`), which runs the very
|
|
1120
|
+
* command ⌘P runs, so the two cannot open different things. The shortcut beside the label is
|
|
1121
|
+
* painted there too, because only the browser knows the platform.
|
|
1122
|
+
*/
|
|
1123
|
+
function renderNewReviewButton() {
|
|
1124
|
+
return `<div class="prb-rail-new"><button type="button" class="prb-new-review" data-new-review="rail">${iconSvg("plus")}<span class="prb-new-review-label">New review</span><kbd class="prb-new-review-key" data-new-review-key aria-hidden="true"></kbd></button></div>`;
|
|
1125
|
+
}
|
|
1126
|
+
/** New review, then the workspace rows, for a rail group. */
|
|
1062
1127
|
function renderWorkspaceNav(options) {
|
|
1063
|
-
return WORKSPACE_PLACES.map((item) => `<a class="prb-rail-item prb-rail-link" href="${item.href}"${item.place === options.current ? " aria-current=\"true\"" : ""}>
|
|
1128
|
+
return renderNewReviewButton() + WORKSPACE_PLACES.map((item) => `<a class="prb-rail-item prb-rail-link" href="${item.href}"${item.place === options.current ? " aria-current=\"true\"" : ""}>
|
|
1064
1129
|
${railIcon(item.icon)}
|
|
1065
1130
|
<span class="prb-rail-label"><span class="prb-rail-title">${escapeHtml$1(item.label)}</span></span>
|
|
1066
1131
|
${item.place === "notifications" ? unreadCount(options.unread, "rail") : ""}
|
|
@@ -1097,20 +1162,9 @@ function renderSendFeedback() {
|
|
|
1097
1162
|
function renderWorkspaceRail(options) {
|
|
1098
1163
|
return `<nav class="prb-rail" aria-label="Workspace">
|
|
1099
1164
|
<div class="prb-rail-group">${renderWorkspaceNav(options)}</div>
|
|
1100
|
-
<div class="prb-rail-group prb-rail-foot">${renderSendFeedback()}</div>
|
|
1165
|
+
<div class="prb-rail-group prb-rail-foot">${renderSendFeedback()}${renderSidebarToggle(options.sidebar)}</div>
|
|
1101
1166
|
</nav>`;
|
|
1102
1167
|
}
|
|
1103
|
-
/**
|
|
1104
|
-
* What the rail carries that the strip does not, shown only while a narrow window hides the rail.
|
|
1105
|
-
*
|
|
1106
|
-
* Which is now the feedback form alone. Every workspace place is an icon in this same strip at
|
|
1107
|
-
* every width, so a text link beside one of them would be the same destination twice; before the
|
|
1108
|
-
* Reviews icon existed this is where Reviews had to go, and the filter that put it here is gone
|
|
1109
|
-
* with the reason for it.
|
|
1110
|
-
*/
|
|
1111
|
-
function renderHeaderNav(_options) {
|
|
1112
|
-
return `<nav class="prb-header-nav" aria-label="Workspace"><a class="prb-feedback" href="${escapeHtml$1(feedbackUrl())}" target="_blank" rel="noopener noreferrer"><span class="prb-feedback-icon" aria-hidden="true">${iconSvg("feedback")}</span><span class="prb-feedback-label">Send feedback</span></a></nav>`;
|
|
1113
|
-
}
|
|
1114
1168
|
//#endregion
|
|
1115
1169
|
//#region ../../packages/review-harness/src/domain/utils/file_path.ts
|
|
1116
1170
|
/**
|
|
@@ -6088,7 +6142,7 @@ function renderWorkspace(view) {
|
|
|
6088
6142
|
*/
|
|
6089
6143
|
const freshness = result ? view.freshness : void 0;
|
|
6090
6144
|
return `<!doctype html>
|
|
6091
|
-
<html lang="en"${themeAttribute(view.theme)}>
|
|
6145
|
+
<html lang="en"${themeAttribute(view.theme)}${sidebarAttributes(view.sidebar)}>
|
|
6092
6146
|
<head>
|
|
6093
6147
|
<meta charset="utf-8">
|
|
6094
6148
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
@@ -6681,6 +6735,7 @@ function renderRailFoot(view) {
|
|
|
6681
6735
|
return `<div class="prb-rail-group prb-rail-foot">
|
|
6682
6736
|
${view.token ? renderWorkspaceNav({ unread: view.unreadNotifications ?? 0 }) : ""}
|
|
6683
6737
|
${renderSendFeedback()}
|
|
6738
|
+
${view.token ? renderSidebarToggle(view.sidebar) : ""}
|
|
6684
6739
|
</div>`;
|
|
6685
6740
|
}
|
|
6686
6741
|
/**
|
|
@@ -9676,7 +9731,7 @@ function renderReviewsPage(view) {
|
|
|
9676
9731
|
const storedReviews = view.groups.reduce((total, group) => total + group.history.length, 0);
|
|
9677
9732
|
const renderSectionAt = (section) => renderSection(section, sections[section], (groups) => renderCards(groups, "home", (group) => collectedHome.has(group)), sectionOpen(section, view.sectionsCollapsed), sections[section].filter((group) => !inProgressOnly.has(group.latest.id) && !collectedHome.has(group)).length);
|
|
9678
9733
|
return `<!doctype html>
|
|
9679
|
-
<html lang="en"${themeAttribute(view.theme)}>
|
|
9734
|
+
<html lang="en"${themeAttribute(view.theme)}${sidebarAttributes(view.sidebar)}>
|
|
9680
9735
|
<head>
|
|
9681
9736
|
<meta charset="utf-8">
|
|
9682
9737
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
@@ -9699,12 +9754,16 @@ ${renderContextBar("Reviews", ordered.length === 0 ? "" : renderControls$1(queue
|
|
|
9699
9754
|
<div class="prb-shell">
|
|
9700
9755
|
${renderWorkspaceRail({
|
|
9701
9756
|
current: "reviews",
|
|
9702
|
-
unread: view.unreadNotifications ?? 0
|
|
9757
|
+
unread: view.unreadNotifications ?? 0,
|
|
9758
|
+
sidebar: view.sidebar
|
|
9703
9759
|
})}
|
|
9704
9760
|
<main class="prb-index">
|
|
9705
9761
|
${ordered.length === 0 ? "" : `<div class="prb-index-summary">
|
|
9706
9762
|
<p class="prb-index-count" data-count>${escapeHtml$1(countLabel(storedReviews, ordered.length))}</p>
|
|
9707
|
-
<
|
|
9763
|
+
<div class="prb-index-summary-actions">
|
|
9764
|
+
<button type="button" class="prb-index-select" data-collection-new><span aria-hidden="true">+</span> New collection</button>
|
|
9765
|
+
<button type="button" class="prb-index-select" data-select-mode aria-pressed="false">Select</button>
|
|
9766
|
+
</div>
|
|
9708
9767
|
</div>`}
|
|
9709
9768
|
${renderInProgress$1(operations, ordered, positions, view.prStates, now, sectionOpen("in-progress", view.sectionsCollapsed), memberOf)}
|
|
9710
9769
|
${renderSectionAt("pinned")}
|
|
@@ -9713,6 +9772,7 @@ ${renderWorkspaceRail({
|
|
|
9713
9772
|
${ordered.length === 0 ? `<p class="prb-index-empty">No reviews stored yet. Ask Claude Code to review a change and one will appear here.</p>` : `<p class="prb-index-none" data-no-matches hidden>Nothing matches that.</p>`}
|
|
9714
9773
|
${ordered.length === 0 ? "" : renderBulkBar()}
|
|
9715
9774
|
${ordered.length === 0 ? "" : renderCollectionsDialog()}
|
|
9775
|
+
${ordered.length === 0 ? "" : renderNewCollectionDialog()}
|
|
9716
9776
|
<p class="prb-index-note">Reviews are kept for thirty days, on this machine only. Pinned, Done and queued reviews, and reviews in a collection, are kept for ninety days instead, counting from the last time you opened or marked them. Every review has a fixed address, so a link to one is worth keeping and still opens after a restart. Stopping the server deletes nothing; it only stops anything being served until the next review starts it again.</p>
|
|
9717
9777
|
</main>
|
|
9718
9778
|
</div>
|
|
@@ -9849,14 +9909,9 @@ function collectionsArea(context, collapsed) {
|
|
|
9849
9909
|
completed: renderCards(completed, { collection: collection.id })
|
|
9850
9910
|
});
|
|
9851
9911
|
});
|
|
9852
|
-
return `<section class="prb-collections" data-collections-area aria-label="Collections">
|
|
9912
|
+
return `<section class="prb-collections" data-collections-area aria-label="Collections"${collections.length === 0 ? " hidden" : ""}>
|
|
9853
9913
|
<script type="application/json" data-collections-registry>${registry}<\/script>
|
|
9854
|
-
<div class="prb-collections-head">
|
|
9855
|
-
<h2 class="prb-collections-title">Collections</h2>
|
|
9856
|
-
${collections.length === 0 ? "<p class=\"prb-collections-hint\">Group reviews that belong together, such as one refactor or one release.</p>" : ""}
|
|
9857
|
-
</div>
|
|
9858
9914
|
${blocks.join("\n ")}
|
|
9859
|
-
${renderNewCollection()}
|
|
9860
9915
|
</section>`;
|
|
9861
9916
|
}
|
|
9862
9917
|
function renderCollection(collection, counts, omitted, collapsed, cards) {
|
|
@@ -9918,17 +9973,25 @@ function renderCollectionMenu(collection) {
|
|
|
9918
9973
|
</div>
|
|
9919
9974
|
</div>`;
|
|
9920
9975
|
}
|
|
9921
|
-
/**
|
|
9922
|
-
|
|
9923
|
-
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
|
|
9927
|
-
|
|
9928
|
-
|
|
9929
|
-
|
|
9930
|
-
|
|
9931
|
-
|
|
9976
|
+
/**
|
|
9977
|
+
* New collection, opened from beside Select. The description lives here, where somebody is deciding
|
|
9978
|
+
* what to make, rather than on the list for good.
|
|
9979
|
+
*/
|
|
9980
|
+
function renderNewCollectionDialog() {
|
|
9981
|
+
return `<dialog class="prb-dialog prb-collection-new-dialog" data-collection-new-dialog aria-labelledby="prb-collection-new-title">
|
|
9982
|
+
<form method="dialog" data-collection-new-form>
|
|
9983
|
+
<h2 id="prb-collection-new-title">New collection</h2>
|
|
9984
|
+
<p>Group reviews that belong together, such as one refactor or one release.</p>
|
|
9985
|
+
<label class="prb-field"><span>Collection name</span>
|
|
9986
|
+
<input type="text" data-collection-name-input placeholder="e.g. Refactor" maxlength="60" autocomplete="off" spellcheck="false" required>
|
|
9987
|
+
</label>
|
|
9988
|
+
<p class="prb-collection-error" data-collection-error hidden role="alert"></p>
|
|
9989
|
+
<div class="prb-dialog-actions">
|
|
9990
|
+
<button type="button" data-collection-cancel>Cancel</button>
|
|
9991
|
+
<button type="submit" class="prb-dialog-primary" data-collection-create disabled>Create</button>
|
|
9992
|
+
</div>
|
|
9993
|
+
</form>
|
|
9994
|
+
</dialog>`;
|
|
9932
9995
|
}
|
|
9933
9996
|
/**
|
|
9934
9997
|
* Manage collections, for one card or for a selection. Built once; the browser fills the list from
|
|
@@ -10610,7 +10673,7 @@ function readPreferences() {
|
|
|
10610
10673
|
try {
|
|
10611
10674
|
const parsed = JSON.parse(readFileSync(PREFERENCES_PATH, "utf8"));
|
|
10612
10675
|
if (!parsed || typeof parsed !== "object") return {};
|
|
10613
|
-
const { askWidth, dismissedNotices, promptsCollapsed, changeMapRegister, theme, reviewSections, runsSections, reviewLayout } = parsed;
|
|
10676
|
+
const { askWidth, dismissedNotices, promptsCollapsed, changeMapRegister, theme, reviewSections, runsSections, reviewLayout, sidebar } = parsed;
|
|
10614
10677
|
return {
|
|
10615
10678
|
...typeof askWidth === "number" && Number.isFinite(askWidth) ? { askWidth: clampAskWidth(askWidth) } : {},
|
|
10616
10679
|
...Array.isArray(dismissedNotices) ? { dismissedNotices: dismissedNotices.filter((key) => typeof key === "string" && NOTICE_KEY.test(key)) } : {},
|
|
@@ -10619,7 +10682,8 @@ function readPreferences() {
|
|
|
10619
10682
|
...isTheme(theme) ? { theme } : {},
|
|
10620
10683
|
...readReviewSections(reviewSections),
|
|
10621
10684
|
...readRunsSections(runsSections),
|
|
10622
|
-
...readLayout(reviewLayout)
|
|
10685
|
+
...readLayout(reviewLayout),
|
|
10686
|
+
...readSidebar(sidebar)
|
|
10623
10687
|
};
|
|
10624
10688
|
} catch {
|
|
10625
10689
|
return {};
|
|
@@ -10652,6 +10716,35 @@ function writeReviewLayout(patch) {
|
|
|
10652
10716
|
writeFileSync(PREFERENCES_PATH, `${JSON.stringify(next, null, 2)}\n`);
|
|
10653
10717
|
} catch {}
|
|
10654
10718
|
}
|
|
10719
|
+
/** Only the two booleans, and only when one is set; an empty object is no preference. */
|
|
10720
|
+
function readSidebar(value) {
|
|
10721
|
+
if (!value || typeof value !== "object") return {};
|
|
10722
|
+
const { compact, hidden } = value;
|
|
10723
|
+
const sidebar = {
|
|
10724
|
+
...typeof compact === "boolean" ? { compact } : {},
|
|
10725
|
+
...typeof hidden === "boolean" ? { hidden } : {}
|
|
10726
|
+
};
|
|
10727
|
+
return Object.keys(sidebar).length === 0 ? {} : { sidebar };
|
|
10728
|
+
}
|
|
10729
|
+
/** The sidebar fields a request may set: a boolean or nothing, each. */
|
|
10730
|
+
function readSidebarPatch(value) {
|
|
10731
|
+
const { sidebar } = readSidebar(value);
|
|
10732
|
+
return sidebar ?? null;
|
|
10733
|
+
}
|
|
10734
|
+
/** Remember a change to the sidebar, merged into what is stored. Read-modify-write, like every other field here. */
|
|
10735
|
+
function writeSidebar(patch) {
|
|
10736
|
+
try {
|
|
10737
|
+
mkdirSync(STORE_ROOT, { recursive: true });
|
|
10738
|
+
const current = readPreferences();
|
|
10739
|
+
writeFileSync(PREFERENCES_PATH, `${JSON.stringify({
|
|
10740
|
+
...current,
|
|
10741
|
+
sidebar: {
|
|
10742
|
+
...current.sidebar,
|
|
10743
|
+
...patch
|
|
10744
|
+
}
|
|
10745
|
+
}, null, 2)}\n`);
|
|
10746
|
+
} catch {}
|
|
10747
|
+
}
|
|
10655
10748
|
/** Remember whether "Your prompts" is folded. Read-modify-write, like every other field here. */
|
|
10656
10749
|
function writePromptsCollapsed(collapsed) {
|
|
10657
10750
|
try {
|
|
@@ -10872,7 +10965,7 @@ function renderSettingsPage(view) {
|
|
|
10872
10965
|
const { settings } = view;
|
|
10873
10966
|
const address = `http://localhost:${settings.port.configured}`;
|
|
10874
10967
|
return `<!doctype html>
|
|
10875
|
-
<html lang="en"${themeAttribute(settings.theme)}>
|
|
10968
|
+
<html lang="en"${themeAttribute(settings.theme)}${sidebarAttributes(view.sidebar)}>
|
|
10876
10969
|
<head>
|
|
10877
10970
|
<meta charset="utf-8">
|
|
10878
10971
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
@@ -10891,7 +10984,8 @@ ${renderContextBar("Settings", renderBack())}
|
|
|
10891
10984
|
<div class="prb-shell">
|
|
10892
10985
|
${renderWorkspaceRail({
|
|
10893
10986
|
current: "settings",
|
|
10894
|
-
unread: view.unreadNotifications ?? 0
|
|
10987
|
+
unread: view.unreadNotifications ?? 0,
|
|
10988
|
+
sidebar: view.sidebar
|
|
10895
10989
|
})}
|
|
10896
10990
|
<main class="prb-index prb-settings">
|
|
10897
10991
|
<div class="prb-page-panel">
|
|
@@ -11392,8 +11486,10 @@ var TOPICS = [
|
|
|
11392
11486
|
<li><code>prreviewbuddy review --pr <url></code> for a pull request</li>
|
|
11393
11487
|
<li><code>prreviewbuddy open</code> to list the reviews you have and open this workspace</li>
|
|
11394
11488
|
</ul>
|
|
11395
|
-
<p>Or
|
|
11396
|
-
|
|
11489
|
+
<p>Or click <b>New review</b> at the top of the sidebar, or press <kbd class="prb-kbd">⌘P</kbd>
|
|
11490
|
+
(<kbd class="prb-kbd">Ctrl+P</kbd> on other platforms), to start a review from anywhere in the
|
|
11491
|
+
workspace. With the sidebar collapsed, New review is the <b>+</b> at its top, and with the
|
|
11492
|
+
sidebar hidden, the <b>+</b> in the top toolbar. The panel follows the reviews it started while it stays open, and closing it
|
|
11397
11493
|
stops nothing. <code>prreviewbuddy help</code> lists every command, and
|
|
11398
11494
|
<code>prreviewbuddy review --help</code> every option a review takes.</p>
|
|
11399
11495
|
<p>There is no account and no API key. PR Review Buddy uses the coding agent installed on your
|
|
@@ -11491,18 +11587,13 @@ feature: E</pre>
|
|
|
11491
11587
|
{
|
|
11492
11588
|
id: "collections",
|
|
11493
11589
|
title: "Collections",
|
|
11494
|
-
body: `<p>
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
<
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
leaves their other collections alone.</p>
|
|
11502
|
-
<p>Each collection lists its reviews that are not Done. Marking one Done moves it under Show
|
|
11503
|
-
completed, in every collection it is in, and Move to active brings it back. A review in a
|
|
11504
|
-
collection is listed there rather than under Active, Waiting or Done. A pinned review stays under
|
|
11505
|
-
Pinned. The Collections filter shows chosen collections, or Uncollected for reviews in none.</p>
|
|
11590
|
+
body: `<p>Collections help you organise related reviews, such as a refactor, release or feature.</p>
|
|
11591
|
+
<p>Create a collection from the Reviews page, then add reviews individually or select several and
|
|
11592
|
+
use <b>Manage collections</b>. A review can belong to multiple collections.</p>
|
|
11593
|
+
<p>Collections show reviews that still need attention. When you mark a review <b>Done</b>, it moves
|
|
11594
|
+
under <b>Show completed</b> within its collection, without losing its membership.</p>
|
|
11595
|
+
<p>You can collapse collections to stay focused, and expand them when you're ready to continue.
|
|
11596
|
+
Removing a review from all collections returns it to the normal review sections.</p>
|
|
11506
11597
|
<p>Reviews in a collection are kept for ninety days, like pinned and Done reviews, counted from
|
|
11507
11598
|
when you last opened or marked them. Adding one to a collection doesn't restart that count.
|
|
11508
11599
|
Deleting a collection keeps its reviews.</p>`
|
|
@@ -11592,7 +11683,7 @@ function renderContents() {
|
|
|
11592
11683
|
}
|
|
11593
11684
|
function renderHelpPage(view) {
|
|
11594
11685
|
return `<!doctype html>
|
|
11595
|
-
<html lang="en"${themeAttribute(view.theme)}>
|
|
11686
|
+
<html lang="en"${themeAttribute(view.theme)}${sidebarAttributes(view.sidebar)}>
|
|
11596
11687
|
<head>
|
|
11597
11688
|
<meta charset="utf-8">
|
|
11598
11689
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
@@ -11611,7 +11702,8 @@ ${renderContextBar("Help", "")}
|
|
|
11611
11702
|
<div class="prb-shell">
|
|
11612
11703
|
${renderWorkspaceRail({
|
|
11613
11704
|
current: "help",
|
|
11614
|
-
unread: view.unreadNotifications ?? 0
|
|
11705
|
+
unread: view.unreadNotifications ?? 0,
|
|
11706
|
+
sidebar: view.sidebar
|
|
11615
11707
|
})}
|
|
11616
11708
|
<main class="prb-index prb-help">
|
|
11617
11709
|
<div class="prb-page-panel">
|
|
@@ -11633,7 +11725,7 @@ ${renderWorkspaceRail({
|
|
|
11633
11725
|
function renderNotificationsPage(view) {
|
|
11634
11726
|
const unread = view.notifications.filter((notification) => notification.readAt === void 0).length;
|
|
11635
11727
|
return `<!doctype html>
|
|
11636
|
-
<html lang="en"${themeAttribute(view.theme)}>
|
|
11728
|
+
<html lang="en"${themeAttribute(view.theme)}${sidebarAttributes(view.sidebar)}>
|
|
11637
11729
|
<head>
|
|
11638
11730
|
<meta charset="utf-8">
|
|
11639
11731
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
@@ -11652,7 +11744,8 @@ ${renderContextBar("Activity", view.notifications.length === 0 ? "" : renderRead
|
|
|
11652
11744
|
<div class="prb-shell">
|
|
11653
11745
|
${renderWorkspaceRail({
|
|
11654
11746
|
current: "notifications",
|
|
11655
|
-
unread: view.unreadNotifications ?? 0
|
|
11747
|
+
unread: view.unreadNotifications ?? 0,
|
|
11748
|
+
sidebar: view.sidebar
|
|
11656
11749
|
})}
|
|
11657
11750
|
<main class="prb-index prb-notifications-page">
|
|
11658
11751
|
${view.notifications.length === 0 ? `<p class="prb-index-empty" data-notifications-empty>Nothing yet. When a review finishes or fails, or a branch or pull request moves, it appears here.</p>` : `<ol class="prb-notifications" data-notifications>
|
|
@@ -13037,7 +13130,7 @@ function renderRunsPage(view) {
|
|
|
13037
13130
|
const nothing = inProgress.length === 0 && recent.length === 0;
|
|
13038
13131
|
const notResponding = recent.some((entry) => entry.status === "not-responding");
|
|
13039
13132
|
return `<!doctype html>
|
|
13040
|
-
<html lang="en"${themeAttribute(view.theme)}>
|
|
13133
|
+
<html lang="en"${themeAttribute(view.theme)}${sidebarAttributes(view.sidebar)}>
|
|
13041
13134
|
<head>
|
|
13042
13135
|
<meta charset="utf-8">
|
|
13043
13136
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
@@ -13056,7 +13149,8 @@ ${renderContextBar("Runs", nothing ? "" : renderControls(notResponding))}
|
|
|
13056
13149
|
<div class="prb-shell">
|
|
13057
13150
|
${renderWorkspaceRail({
|
|
13058
13151
|
current: "runs",
|
|
13059
|
-
unread: view.unreadNotifications ?? 0
|
|
13152
|
+
unread: view.unreadNotifications ?? 0,
|
|
13153
|
+
sidebar: view.sidebar
|
|
13060
13154
|
})}
|
|
13061
13155
|
<main class="prb-index prb-runs">
|
|
13062
13156
|
<p class="prb-runs-lede">Monitor review executions and recent activity.</p>
|
|
@@ -14992,6 +15086,7 @@ async function handle(req, res, options) {
|
|
|
14992
15086
|
if (url.pathname === "/notifications/live") return handleLiveNotifications(req, res, url.searchParams, options.indexToken);
|
|
14993
15087
|
if (url.pathname === "/pin") return handlePin(req, res, options.indexToken);
|
|
14994
15088
|
if (url.pathname === "/sections") return handleSections(req, res, options.indexToken);
|
|
15089
|
+
if (url.pathname === "/sidebar") return handleSidebar(req, res, options.indexToken);
|
|
14995
15090
|
if (url.pathname === "/queue") return handleQueue(req, res, options.indexToken);
|
|
14996
15091
|
if (url.pathname === "/collections") return handleCollections(req, res, options.indexToken);
|
|
14997
15092
|
if (url.pathname === "/collections/members") return handleCollectionMembers(req, res, options.indexToken);
|
|
@@ -15141,6 +15236,7 @@ function indexView() {
|
|
|
15141
15236
|
unreadNotifications: unreadCount$1(),
|
|
15142
15237
|
driving: isDriving(),
|
|
15143
15238
|
theme: readPreferences().theme,
|
|
15239
|
+
sidebar: readPreferences().sidebar,
|
|
15144
15240
|
sectionsCollapsed: readPreferences().reviewSections
|
|
15145
15241
|
};
|
|
15146
15242
|
}
|
|
@@ -15231,7 +15327,8 @@ async function handleSettings(req, res, params, indexToken) {
|
|
|
15231
15327
|
sendHtml(res, 200, renderSettingsPage({
|
|
15232
15328
|
settings: readSettings(),
|
|
15233
15329
|
unreadNotifications: unreadCount$1(),
|
|
15234
|
-
driving: isDriving()
|
|
15330
|
+
driving: isDriving(),
|
|
15331
|
+
sidebar: readPreferences().sidebar
|
|
15235
15332
|
}), indexCookieHeader(indexToken));
|
|
15236
15333
|
}
|
|
15237
15334
|
/**
|
|
@@ -15243,7 +15340,8 @@ function handleHelp(req, res, params, indexToken) {
|
|
|
15243
15340
|
sendHtml(res, 200, renderHelpPage({
|
|
15244
15341
|
unreadNotifications: unreadCount$1(),
|
|
15245
15342
|
driving: isDriving(),
|
|
15246
|
-
theme: readPreferences().theme
|
|
15343
|
+
theme: readPreferences().theme,
|
|
15344
|
+
sidebar: readPreferences().sidebar
|
|
15247
15345
|
}), indexCookieHeader(indexToken));
|
|
15248
15346
|
}
|
|
15249
15347
|
/**
|
|
@@ -15358,7 +15456,8 @@ async function handleNotifications(req, res, params, indexToken) {
|
|
|
15358
15456
|
gone: new Set(notifications.filter((entry) => !loadWorkspace(entry.reviewId)).map((entry) => entry.id)),
|
|
15359
15457
|
unreadNotifications: unreadCount$1(),
|
|
15360
15458
|
driving: isDriving(),
|
|
15361
|
-
theme: readPreferences().theme
|
|
15459
|
+
theme: readPreferences().theme,
|
|
15460
|
+
sidebar: readPreferences().sidebar
|
|
15362
15461
|
}), indexCookieHeader(indexToken));
|
|
15363
15462
|
}
|
|
15364
15463
|
/**
|
|
@@ -15379,6 +15478,7 @@ function handleRuns(req, res, params, indexToken) {
|
|
|
15379
15478
|
unreadNotifications: unreadCount$1(),
|
|
15380
15479
|
driving: isDriving(),
|
|
15381
15480
|
theme: preferences.theme,
|
|
15481
|
+
sidebar: preferences.sidebar,
|
|
15382
15482
|
sectionsCollapsed: preferences.runsSections
|
|
15383
15483
|
}), indexCookieHeader(indexToken));
|
|
15384
15484
|
}
|
|
@@ -15792,6 +15892,18 @@ async function handleRunsSections(req, res, indexToken) {
|
|
|
15792
15892
|
writeRunsSectionCollapsed(body.section, body.collapsed);
|
|
15793
15893
|
send(res, 200, { ok: true });
|
|
15794
15894
|
}
|
|
15895
|
+
/**
|
|
15896
|
+
* The sidebar, from a workspace page that is not a review, with the same credential as `/sections`.
|
|
15897
|
+
* A review page sends the same field to its own `/prefs`, since it may hold no index cookie.
|
|
15898
|
+
*/
|
|
15899
|
+
async function handleSidebar(req, res, indexToken) {
|
|
15900
|
+
if (req.method !== "POST") return send(res, 405, { error: "Use POST." });
|
|
15901
|
+
if (!indexToken || !secretMatches(indexToken, indexCookie(req))) return send(res, 403, { error: "Not authorised." });
|
|
15902
|
+
const sidebar = readSidebarPatch((await readJson(req))?.sidebar);
|
|
15903
|
+
if (!sidebar) return send(res, 400, { error: "Not a sidebar setting." });
|
|
15904
|
+
writeSidebar(sidebar);
|
|
15905
|
+
send(res, 200, { ok: true });
|
|
15906
|
+
}
|
|
15795
15907
|
async function handleSections(req, res, indexToken) {
|
|
15796
15908
|
if (req.method !== "POST") return send(res, 405, { error: "Use POST." });
|
|
15797
15909
|
if (!indexToken || !secretMatches(indexToken, indexCookie(req))) return send(res, 403, { error: "Not authorised." });
|
|
@@ -16198,6 +16310,7 @@ async function sendWorkspacePage(res, workspace) {
|
|
|
16198
16310
|
repoPath: workspace.repoPath,
|
|
16199
16311
|
askWidth: readPreferences().askWidth,
|
|
16200
16312
|
theme: readPreferences().theme,
|
|
16313
|
+
sidebar: readPreferences().sidebar,
|
|
16201
16314
|
dismissedNotices: readPreferences().dismissedNotices,
|
|
16202
16315
|
promptsCollapsed: readPreferences().promptsCollapsed === true,
|
|
16203
16316
|
reviewLayout: readPreferences().reviewLayout ?? {},
|
|
@@ -17001,6 +17114,8 @@ async function handlePrefs(req, res) {
|
|
|
17001
17114
|
if (typeof askWidth === "number") writeAskWidth(askWidth);
|
|
17002
17115
|
else if (askWidth === null) clearAskWidth();
|
|
17003
17116
|
if (typeof body?.promptsCollapsed === "boolean") writePromptsCollapsed(body.promptsCollapsed);
|
|
17117
|
+
const sidebar = readSidebarPatch(body?.sidebar);
|
|
17118
|
+
if (sidebar) writeSidebar(sidebar);
|
|
17004
17119
|
const layout = readReviewLayoutPatch(body?.reviewLayout);
|
|
17005
17120
|
if (layout) writeReviewLayout(layout);
|
|
17006
17121
|
if (body?.changeMapRegister === "simple" || body?.changeMapRegister === "technical") writeChangeMapRegister(body.changeMapRegister);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prreviewbuddy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.83.3",
|
|
4
4
|
"description": "Understand code changes before you approve them. Local branch and pull request reviews with Claude Code or Codex.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://prreviewbuddy.com",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dt as e}from"./chunk-
|
|
1
|
+
import{dt as e}from"./chunk-DwdwtB9r.js";var t=`button:not([disabled])`;function n(e){return e.querySelector(`[data-menu-panel]`)}function r(e){return e.querySelector(`[data-menu-trigger]`)}function i(e){let t=n(e);return t?[...t.querySelectorAll(`input:not([disabled]), textarea:not([disabled]), button:not([disabled])`)].filter(e=>!e.closest(`[hidden]`)):[]}function a(e){let r=n(e);return r?[...r.querySelectorAll(t)].filter(e=>!e.closest(`[hidden]`)):[]}var o=`data-menu-placement`;function s(e){let t=e.ownerDocument.defaultView,n=0,r=t?.innerHeight??1/0;for(let i=e.parentElement;i&&t;i=i.parentElement){let e=t.getComputedStyle(i).overflowY;if(e===`visible`||e===``)continue;let a=i.getBoundingClientRect();n=Math.max(n,a.top),r=Math.min(r,a.bottom)}return{top:n,bottom:r}}var c=8,l=120;function u(e){let t=n(e),i=r(e);if(!t||!i)return;t.removeAttribute(o),t.style.removeProperty(`max-height`),t.style.removeProperty(`overflow-y`),t.style.removeProperty(`box-sizing`),t.scrollTop=0;let a=t.getBoundingClientRect(),u=i.getBoundingClientRect(),d=s(e),f=Math.max(0,a.top-u.bottom),p=d.bottom-u.bottom-f-c,m=u.top-d.top-f-c,h=a.height,g=h<=p?`below`:h<=m||m>p?`above`:`below`;g===`above`&&t.setAttribute(o,`above`);let _=g===`above`?m:p;h<=_||(t.style.boxSizing=`border-box`,t.style.maxHeight=`${Math.max(Math.floor(_),l)}px`,t.style.overflowY=`auto`)}function d(e){return!e.metaKey&&!e.ctrlKey&&!e.altKey&&!e.shiftKey?e.key===`j`?`ArrowDown`:e.key===`k`?`ArrowUp`:e.key:e.key}function f(t,o={}){let s=null,c=null,l=o.within?`${o.within} [data-menu]`:`[data-menu]`,f=e=>e&&(!o.within||e.closest(o.within))?e:null,p=(e,t={})=>{let i=n(e);if(!i||i.hidden)return;i.hidden=!0;let a=r(e);a?.setAttribute(`aria-expanded`,`false`);let l=s===e?c:null;s===e&&(s=null,c=null),o.onClose?.(e),t.returnFocus&&(l??(()=>a?.focus()))()},m=()=>{for(let e of t.querySelectorAll(l))p(e)},h=(e,t,i=null)=>{let l=n(e);l&&(m(),c=i,o.onOpen?.(e),l.hidden=!1,u(e),r(e)?.setAttribute(`aria-expanded`,`true`),s=e,t&&a(e)[0]?.focus())};return t.addEventListener(`click`,e=>{let t=e.target,r=f(t?.closest?.(`[data-menu]`)??null);if(!r){m();return}if(t?.closest(`[data-menu-trigger]`)){let t=e.detail===0;n(r)?.hidden?h(r,t):p(r);return}s&&s!==r&&p(s)}),t.addEventListener(`keydown`,t=>{if(s&&!s.isConnected&&(s=null),!s)return;let n=s;if(t.key===`Escape`){t.preventDefault(),p(n,{returnFocus:!0});return}if(!n.contains(t.target))return;if(t.key===`Tab`){if(n.hasAttribute(`data-menu-form`)){let e=i(n),r=e.indexOf(t.target);if(e.length>0){t.preventDefault(),e[(r+(t.shiftKey?-1:1)+e.length)%e.length].focus();return}}p(n);return}if(e(t.target))return;let r=a(n);if(r.length===0)return;let o=r.indexOf(t.target),c=d(t),l=c===`ArrowDown`?r[(o+1)%r.length]:c===`ArrowUp`?r[(o-1+r.length)%r.length]:c===`Home`?r[0]:c===`End`?r[r.length-1]:null;l&&(t.preventDefault(),l.focus(),l.scrollIntoView({block:`nearest`}))}),{open:(e,t={})=>h(e,t.focusFirst===!0,t.returnFocus??null),close:p,closeAll:m}}function p(e){return e<3e4?1e3:e<12e4?3e3:e<6e5?8e3:15e3}export{f as n,p as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{F as e}from"./chunk-
|
|
1
|
+
import{F as e}from"./chunk-DwdwtB9r.js";function t(e=document){for(let t of e.querySelectorAll(`.prb-index-status`))t.addEventListener(`click`,e=>{let n=t.querySelector(`select`);if(!(!n||e.target instanceof Node&&n.contains(e.target))){e.preventDefault(),n.focus();try{n.showPicker()}catch{}}})}function n(t,n){r(t,t=>e(t.dataset.section)?t.dataset.section:void 0,n)}function r(e,t,n){let r=Promise.resolve();for(let i of e){let e=t(i);if(e===void 0)continue;let a=i.open;i.addEventListener(`toggle`,()=>{if(i.open===a)return;a=i.open;let t=!i.open;r=r.then(()=>n(e,t)).catch(()=>{})})}}export{n,t as r,r as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
async function e(e,t){try{await navigator.clipboard.writeText(t);let n=e.textContent;e.textContent=`Copied`,window.setTimeout(()=>{e.textContent=n},1200)}catch{let n=document.createElement(`input`);n.type=`text`,n.readOnly=!0,n.value=t,n.className=`prb-menu-id`,n.setAttribute(`data-id-field`,``),e.after(n),n.select()}}function t(e,t){let n=t.toLowerCase().split(/\s+/).filter(Boolean);return n.length===0?[...e]:e.filter(e=>{let t=`${e.name}\n${e.prompt}`.toLowerCase();return n.every(e=>t.includes(e))})}function n(e){return e<0||e>=10?null:e===9?`0`:String(e+1)}function r(e){return/^[0-9]$/.test(e)?e===`0`?9:Number(e)-1:null}function i(e){return{title:`Choose a prompt`,mount(i,a){let o=i.ownerDocument,s=e.prompts(),c=o.createElement(`input`);c.type=`search`,c.className=`prb-palette-input`,c.placeholder=`Filter prompts`,c.setAttribute(`aria-label`,`Filter prompts`),c.spellcheck=!1;let l=o.createElement(`p`);l.className=`prb-palette-summary`,l.setAttribute(`aria-live`,`polite`);let u=o.createElement(`div`);u.className=`prb-palette-results`,u.setAttribute(`role`,`group`),u.setAttribute(`aria-label`,`Prompts`);let d=[],f=()=>[...u.querySelectorAll(`[data-prompt-choice]`)],p=()=>{let e=o.activeElement===c;for(let[t,n]of f().entries())n.toggleAttribute(`data-enter-target`,e&&t===0)},m=()=>{d=t(s,c.value),u.replaceChildren(...d.map((e,t)=>{let r=o.createElement(`button`);r.type=`button`,r.className=`prb-palette-result prb-palette-prompt`,r.dataset.promptChoice=e.id;let i=o.createElement(`kbd`);i.className=`prb-kbd prb-palette-num`;let a=n(t);a?i.textContent=a:i.setAttribute(`aria-hidden`,`true`);let s=o.createElement(`span`);s.className=`prb-palette-prompt-text`;let c=o.createElement(`span`);c.className=`prb-palette-result-title`,c.textContent=e.name;let l=o.createElement(`span`);return l.className=`prb-palette-prompt-said`,l.textContent=e.prompt,s.append(c,l),r.append(i,s),r})),l.textContent=s.length===0?`No saved prompts yet. Add one under Your prompts in Buddy AI.`:d.length===0?`No prompts match.`:d.length===s.length?`${s.length} ${s.length===1?`prompt`:`prompts`}`:`${d.length} of ${s.length} prompts`,p()},h=t=>{!t||!d.some(e=>e.id===t)||(a(),e.choose(t))},g=e=>{c.value=e===`Backspace`?c.value.slice(0,-1):c.value+e,c.focus(),c.dispatchEvent(new Event(`input`,{bubbles:!0}))};c.addEventListener(`input`,m),c.addEventListener(`focus`,p),c.addEventListener(`blur`,p),u.addEventListener(`click`,e=>{h(e.target.closest(`[data-prompt-choice]`)?.dataset.promptChoice)}),i.addEventListener(`keydown`,e=>{if(e.isComposing||e.metaKey||e.ctrlKey||e.altKey)return;let t=f(),n=e.target===c,i=t.indexOf(e.target),a=r(e.key);if(a!==null)return e.preventDefault(),h(t[a]?.dataset.promptChoice);if(e.key===`Enter`)return e.preventDefault(),h((n?t[0]:t[i])?.dataset.promptChoice);let o=e.key===`ArrowDown`||!n&&e.key===`j`,s=e.key===`ArrowUp`||!n&&e.key===`k`;if(o||s){let n=o?i<0?t[0]:t[i+1]:i<=0?c:t[i-1];e.preventDefault(),n?.focus();return}!n&&(e.key.length===1||e.key===`Backspace`)&&(e.preventDefault(),g(e.key))}),i.append(c,l,u),m(),c.focus()}}}var a=`Fetch selected`;function o(e){return`${e} ${e===1?`repository`:`repositories`}`}function s(e){return`Fetching ${o(e)}…`}function c(e){return e.fetched===0?`Could not fetch ${o(e.repositories)}`:e.fetched===e.repositories?`Fetched ${o(e.repositories)}`:`Fetched ${e.fetched} of ${o(e.repositories)}`}function l(e,t){let n=new Set,r=new Set;for(let i of e)for(let e of i.lineage){let i=t[e];i!==void 0&&(n.add(e),r.add(i))}return{ids:[...n],repositories:r.size}}function u(e,t){return l(t,e).repositories>0}export{s as a,n as c,c as i,e as l,u as n,i as o,l as r,r as s,a as t};
|