Skip to content

Commit 10dcf60

Browse files
vveerrggclaude
andcommitted
feat: show queue counter "(X of Y)" in permission UI
When a page fires multiple signing requests, display the current position in the queue so users know how many approvals remain. Counter appears in both the bottom sheet and fallback permission tab, hidden for single requests, and resets when the queue drains. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d755c2a commit 10dcf60

4 files changed

Lines changed: 36 additions & 4 deletions

File tree

src/background.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const storage = {
6060
const log = msg => console.log('Background: ', msg);
6161
const validations = {};
6262
let prompt = { mutex: new Mutex(), release: null, tabId: null };
63+
let pendingQueue = { total: 0, processed: 0 };
6364

6465
/**
6566
* Helper: run an async function and deliver the result via sendResponse.
@@ -1006,6 +1007,10 @@ api.runtime.onMessage.addListener((message, _sender, sendResponse) => {
10061007
case 'nip44.decrypt':
10071008
case 'getRelays':
10081009
validations[uuid] = sendResponse;
1010+
if (Object.keys(validations).length === 1) {
1011+
pendingQueue = { total: 0, processed: 0 };
1012+
}
1013+
pendingQueue.total++;
10091014
ask(uuid, message);
10101015
setTimeout(() => {
10111016
// H4 fix: deny pending request on timeout instead of silently releasing
@@ -1074,6 +1079,10 @@ async function ask(uuid, { kind, host, payload }) {
10741079
await forceRelease(); // Clean up previous tab if it closed without cleaning itself up
10751080
prompt.release = await prompt.mutex.acquire();
10761081

1082+
pendingQueue.processed++;
1083+
const queuePosition = pendingQueue.processed;
1084+
const queueTotal = pendingQueue.total;
1085+
10771086
let mKind = kind === 'signEvent' ? `signEvent:${payload.kind}` : kind;
10781087
let permission = await getPermission(host, mKind);
10791088
if (permission === 'allow') {
@@ -1102,6 +1111,8 @@ async function ask(uuid, { kind, host, payload }) {
11021111
kind: 'showPermissionSheet',
11031112
host,
11041113
permissionKind: kind,
1114+
queuePosition,
1115+
queueTotal,
11051116
});
11061117

11071118
if (result) {
@@ -1137,6 +1148,8 @@ async function ask(uuid, { kind, host, payload }) {
11371148
kind,
11381149
host,
11391150
payload: JSON.stringify(payload || false),
1151+
queuePosition,
1152+
queueTotal,
11401153
});
11411154
let tab = await api.tabs.getCurrent();
11421155
let p = await api.tabs.create({
@@ -1150,6 +1163,9 @@ async function ask(uuid, { kind, host, payload }) {
11501163
function complete({ payload, origKind, event, remember, host }) {
11511164
const sendResponse = validations[payload];
11521165
delete validations[payload];
1166+
if (Object.keys(validations).length === 0) {
1167+
pendingQueue = { total: 0, processed: 0 };
1168+
}
11531169

11541170
if (remember) {
11551171
let mKind =
@@ -1192,6 +1208,9 @@ function complete({ payload, origKind, event, remember, host }) {
11921208
function deny({ origKind, host, payload, remember, event }) {
11931209
const sendResponse = validations[payload];
11941210
delete validations[payload];
1211+
if (Object.keys(validations).length === 0) {
1212+
pendingQueue = { total: 0, processed: 0 };
1213+
}
11951214

11961215
if (remember) {
11971216
let mKind =

src/content.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ function createPermissionSheet() {
143143
<div class="nk-backdrop"></div>
144144
<div class="nk-sheet">
145145
<div class="nk-handle"></div>
146-
<div class="nk-title">Permission Request</div>
146+
<div class="nk-title">Permission Request <span id="nk-queue" style="color: #8f908a; font-size: 14px; font-weight: 400;"></span></div>
147147
<div class="nk-text">
148148
<span class="nk-host" id="nk-host"></span> wants to:
149149
</div>
@@ -196,10 +196,14 @@ function getHumanPermission(kind) {
196196
}
197197
}
198198

199-
function showPermissionSheet(host, kind) {
199+
function showPermissionSheet(host, kind, queuePosition, queueTotal) {
200200
createPermissionSheet();
201201
permissionSheet.querySelector('#nk-host').textContent = host;
202202
permissionSheet.querySelector('#nk-permission').textContent = getHumanPermission(kind);
203+
const queueEl = permissionSheet.querySelector('#nk-queue');
204+
if (queueEl) {
205+
queueEl.textContent = queueTotal > 1 ? `(${queuePosition} of ${queueTotal})` : '';
206+
}
203207
permissionSheet.classList.add('active');
204208

205209
return new Promise(resolve => {
@@ -210,7 +214,7 @@ function showPermissionSheet(host, kind) {
210214
// Listen for permission requests from background
211215
api.runtime.onMessage.addListener((message, sender, sendResponse) => {
212216
if (message.kind === 'showPermissionSheet') {
213-
showPermissionSheet(message.host, message.permissionKind).then(result => {
217+
showPermissionSheet(message.host, message.permissionKind, message.queuePosition, message.queueTotal).then(result => {
214218
sendResponse(result);
215219
});
216220
return true; // Keep channel open for async response

src/permission/permission.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
<body>
9999
<div class="permission-card">
100100
<h1 class="permission-title text-center">
101-
Permission Requested
101+
Permission Requested <span id="perm-queue" style="color: #8f908a; font-size: 14px; font-weight: 400;"></span>
102102
</h1>
103103

104104
<p class="permission-text text-center">

src/permission/permission.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const state = {
88
event: null,
99
remember: false,
1010
profileType: 'local',
11+
queuePosition: 0,
12+
queueTotal: 0,
1113
};
1214

1315
function getHumanPermission(perm) {
@@ -43,6 +45,11 @@ function render() {
4345
if (hostEl) hostEl.textContent = state.host;
4446
if (permEl) permEl.textContent = getHumanPermission(state.permission);
4547

48+
const queueEl = document.getElementById('perm-queue');
49+
if (queueEl) {
50+
queueEl.textContent = state.queueTotal > 1 ? `(${state.queuePosition} of ${state.queueTotal})` : '';
51+
}
52+
4653
if (bunkerNotice) {
4754
bunkerNotice.style.display = state.profileType === 'bunker' ? 'block' : 'none';
4855
}
@@ -117,6 +124,8 @@ async function init() {
117124
state.permission = qs.get('kind');
118125
state.key = qs.get('uuid');
119126
state.event = JSON.parse(qs.get('payload'));
127+
state.queuePosition = parseInt(qs.get('queuePosition')) || 0;
128+
state.queueTotal = parseInt(qs.get('queueTotal')) || 0;
120129

121130
state.profileType = await api.runtime.sendMessage({
122131
kind: 'getProfileType',

0 commit comments

Comments
 (0)