@rynfar/meridian 1.72.0 → 1.73.0
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/dist/cli-1jstkdj9.js +30 -0
- package/dist/{cli-9e5cxp89.js → cli-2h3w5n6g.js} +163 -65
- package/dist/cli-3zwfvexc.js +56 -0
- package/dist/{cli-hxxy0m1z.js → cli-82e2m44k.js} +2 -1
- package/dist/cli-8sw5wr9j.js +136 -0
- package/dist/{cli-khhjyk04.js → cli-chsp880k.js} +214 -21
- package/dist/cli-dh0a1bw4.js +619 -0
- package/dist/cli-eehk3052.js +57 -0
- package/dist/cli-grfp0s1j.js +330 -0
- package/dist/{cli-ab7zkp1a.js → cli-p5zbk952.js} +2027 -315
- package/dist/{cli-hj61zpt7.js → cli-p9ca4p13.js} +17 -2
- package/dist/cli-qpfky8wy.js +133 -0
- package/dist/cli.js +47 -12
- package/dist/cliDashboard-c0dvkj4y.js +325 -0
- package/dist/configDir.d.ts +30 -0
- package/dist/configDir.d.ts.map +1 -0
- package/dist/organizationName-90f0atkn.js +29 -0
- package/dist/{pluginPage-f5gdmbxc.js → pluginPage-3kxsrdpj.js} +1 -1
- package/dist/{profileCli-1eecbmgk.js → profileCli-1bfgc05h.js} +13 -3
- package/dist/{profilePage-mamej7kp.js → profilePage-etxqg3vn.js} +252 -60
- package/dist/profileRename-4a4km6g8.js +22 -0
- package/dist/{profiles-wch9h234.js → profiles-0mp32ek9.js} +16 -3
- package/dist/proxy/adapterInstances.d.ts +1 -1
- package/dist/proxy/adapterInstances.d.ts.map +1 -1
- package/dist/proxy/adapters/claudecode.d.ts.map +1 -1
- package/dist/proxy/adapters/droid.d.ts.map +1 -1
- package/dist/proxy/authDiscovery.d.ts +52 -0
- package/dist/proxy/authDiscovery.d.ts.map +1 -0
- package/dist/proxy/credentialsMode.d.ts +77 -0
- package/dist/proxy/credentialsMode.d.ts.map +1 -0
- package/dist/proxy/design.d.ts.map +1 -1
- package/dist/proxy/followActive.d.ts +262 -0
- package/dist/proxy/followActive.d.ts.map +1 -0
- package/dist/proxy/limitDetection.d.ts +110 -0
- package/dist/proxy/limitDetection.d.ts.map +1 -0
- package/dist/proxy/models.d.ts.map +1 -1
- package/dist/proxy/oauthPlan.d.ts +63 -0
- package/dist/proxy/oauthPlan.d.ts.map +1 -0
- package/dist/proxy/oauthUsage.d.ts +65 -2
- package/dist/proxy/oauthUsage.d.ts.map +1 -1
- package/dist/proxy/openai.d.ts +4 -2
- package/dist/proxy/openai.d.ts.map +1 -1
- package/dist/proxy/organizationName.d.ts +71 -0
- package/dist/proxy/organizationName.d.ts.map +1 -0
- package/dist/proxy/passthroughEarlyStop.d.ts +10 -0
- package/dist/proxy/passthroughEarlyStop.d.ts.map +1 -1
- package/dist/proxy/planAllowance.d.ts +75 -0
- package/dist/proxy/planAllowance.d.ts.map +1 -0
- package/dist/proxy/probes.d.ts +85 -0
- package/dist/proxy/probes.d.ts.map +1 -0
- package/dist/proxy/profileCli.d.ts +53 -1
- package/dist/proxy/profileCli.d.ts.map +1 -1
- package/dist/proxy/profileHealth.d.ts +127 -0
- package/dist/proxy/profileHealth.d.ts.map +1 -0
- package/dist/proxy/profileRename.d.ts +83 -0
- package/dist/proxy/profileRename.d.ts.map +1 -0
- package/dist/proxy/profiles.d.ts +72 -6
- package/dist/proxy/profiles.d.ts.map +1 -1
- package/dist/proxy/query.d.ts +7 -0
- package/dist/proxy/query.d.ts.map +1 -1
- package/dist/proxy/routing.d.ts +59 -1
- package/dist/proxy/routing.d.ts.map +1 -1
- package/dist/proxy/sdkFeatures.d.ts +1 -1
- package/dist/proxy/sdkFeatures.d.ts.map +1 -1
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/session/fingerprint.d.ts +5 -0
- package/dist/proxy/session/fingerprint.d.ts.map +1 -1
- package/dist/proxy/session/lineage.d.ts.map +1 -1
- package/dist/proxy/setup.d.ts.map +1 -1
- package/dist/proxy/supervision.d.ts +41 -0
- package/dist/proxy/supervision.d.ts.map +1 -0
- package/dist/proxy/tokenRefresh.d.ts +38 -4
- package/dist/proxy/tokenRefresh.d.ts.map +1 -1
- package/dist/server.js +11 -7
- package/dist/settings.d.ts +83 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/{setup-ndmjpy23.js → setup-7fr49z92.js} +1 -1
- package/dist/statusProbe-9x9q261e.js +151 -0
- package/dist/telemetry/dashboard.d.ts.map +1 -1
- package/dist/telemetry/index.d.ts +20 -2
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/landing.d.ts +1 -1
- package/dist/telemetry/landing.d.ts.map +1 -1
- package/dist/telemetry/logStore.d.ts +11 -0
- package/dist/telemetry/logStore.d.ts.map +1 -1
- package/dist/telemetry/pricingStore.d.ts +2 -2
- package/dist/telemetry/pricingStore.d.ts.map +1 -1
- package/dist/telemetry/profileBar.d.ts +2 -2
- package/dist/telemetry/profileBar.d.ts.map +1 -1
- package/dist/telemetry/profileFacts.d.ts +17 -0
- package/dist/telemetry/profileFacts.d.ts.map +1 -0
- package/dist/telemetry/profileOrder.d.ts +68 -0
- package/dist/telemetry/profileOrder.d.ts.map +1 -0
- package/dist/telemetry/profilePage.d.ts.map +1 -1
- package/dist/telemetry/profileSort.d.ts +35 -0
- package/dist/telemetry/profileSort.d.ts.map +1 -0
- package/dist/telemetry/profileSpent.d.ts +68 -0
- package/dist/telemetry/profileSpent.d.ts.map +1 -0
- package/dist/telemetry/routeChain.d.ts +32 -0
- package/dist/telemetry/routeChain.d.ts.map +1 -0
- package/dist/telemetry/routes.d.ts.map +1 -1
- package/dist/telemetry/settingsPage.d.ts +1 -1
- package/dist/telemetry/settingsPage.d.ts.map +1 -1
- package/dist/telemetry/sqlite.d.ts.map +1 -1
- package/dist/telemetry/store.d.ts +6 -1
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/types.d.ts +132 -2
- package/dist/telemetry/types.d.ts.map +1 -1
- package/dist/{tokenRefresh-kzz08kea.js → tokenRefresh-eg9h83wd.js} +6 -1
- package/package.json +1 -1
- package/dist/cli-5jxyma6z.js +0 -277
- package/dist/cli-vj9cv18n.js +0 -38
- package/dist/proxy/settings.d.ts +0 -30
- package/dist/proxy/settings.d.ts.map +0 -1
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
// src/telemetry/profileFacts.ts
|
|
2
|
+
var profileFactsJs = `
|
|
3
|
+
function timeAgo(ts) {
|
|
4
|
+
if (!ts) return '\\u2014';
|
|
5
|
+
var s = Math.floor((Date.now() - ts) / 1000);
|
|
6
|
+
if (s < 5) return 'just now';
|
|
7
|
+
if (s < 60) return s + 's ago';
|
|
8
|
+
if (s < 3600) return Math.floor(s / 60) + 'm ago';
|
|
9
|
+
if (s < 86400) return Math.floor(s / 3600) + 'h ago';
|
|
10
|
+
return new Date(ts).toLocaleString();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function profileFacts(p) {
|
|
14
|
+
var facts = [];
|
|
15
|
+
var authStale = p.authProvenance && p.authProvenance !== 'live';
|
|
16
|
+
var statusValue = p.authProvenance === 'never' ? 'never read' : (p.loggedIn ? '\\u2713 Authenticated' : '\\u2717 Not logged in');
|
|
17
|
+
facts.push({
|
|
18
|
+
label: 'Status',
|
|
19
|
+
value: statusValue,
|
|
20
|
+
tone: p.loggedIn ? 'ok' : 'err',
|
|
21
|
+
cached: authStale && p.authProvenance !== 'never'
|
|
22
|
+
});
|
|
23
|
+
if (p.email) facts.push({ label: 'Email', value: p.email, tone: '', cached: authStale });
|
|
24
|
+
if (p.organizationName) facts.push({ label: 'Organization', value: p.organizationName, tone: '' });
|
|
25
|
+
if (p.accountType) facts.push({ label: 'Account', value: p.accountType, tone: '' });
|
|
26
|
+
var plan = p.planName || p.planLabel || p.subscriptionType;
|
|
27
|
+
if (plan) facts.push({ label: 'Plan', value: plan, tone: '', cached: authStale, title: p.seatTier || p.rateLimitTier || '' });
|
|
28
|
+
if (p.allowance) facts.push({ label: 'Allowance', value: p.allowance + ' of a Pro plan\\u2019s Claude Code usage', shortValue: p.allowance, tone: '', title: p.rateLimitTier || '' });
|
|
29
|
+
if (p.aliases && p.aliases.length > 0) facts.push({ label: 'Former names', value: p.aliases.join(', '), tone: '', title: 'Requests naming these are served by this profile, until the name is added again' });
|
|
30
|
+
if (p.lastSuccessAt) facts.push({ label: 'Last Verified', value: timeAgo(p.lastSuccessAt), tone: 'ok' });
|
|
31
|
+
if (p.lastCheckedAt && p.lastCheckedAt !== p.lastSuccessAt) {
|
|
32
|
+
facts.push({ label: 'Last Checked', value: timeAgo(p.lastCheckedAt), tone: '' });
|
|
33
|
+
}
|
|
34
|
+
return facts;
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
// src/telemetry/profileOrder.ts
|
|
39
|
+
var EDGE_ZONE_PX = 96;
|
|
40
|
+
var MAX_SCROLL_PX_PER_FRAME = 20;
|
|
41
|
+
var reorderCss = `
|
|
42
|
+
.profile-card.dragging { opacity: 0.45; border-color: var(--accent); }
|
|
43
|
+
.profile-card.drop-target { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
|
|
44
|
+
.drag-handle {
|
|
45
|
+
background: none; border: 1px solid transparent; border-radius: 6px;
|
|
46
|
+
color: var(--muted); cursor: grab; padding: 2px 6px; font-size: 15px;
|
|
47
|
+
line-height: 1; user-select: none; flex-shrink: 0;
|
|
48
|
+
}
|
|
49
|
+
.drag-handle:hover { color: var(--accent); border-color: var(--border); }
|
|
50
|
+
.drag-handle:focus-visible { outline: none; color: var(--accent); border-color: var(--accent); }
|
|
51
|
+
.drag-handle:active { cursor: grabbing; }
|
|
52
|
+
.order-index {
|
|
53
|
+
font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; font-size: 11px;
|
|
54
|
+
color: var(--muted); min-width: 16px; text-align: right; flex-shrink: 0;
|
|
55
|
+
}
|
|
56
|
+
.order-note { font-size: 12px; color: var(--muted); margin-bottom: 12px; max-width: 620px; }
|
|
57
|
+
.order-note code {
|
|
58
|
+
font-family: 'SF Mono', SFMono-Regular, Consolas, monospace; font-size: 11px;
|
|
59
|
+
background: var(--bg); padding: 1px 5px; border-radius: 4px; color: var(--accent2);
|
|
60
|
+
}
|
|
61
|
+
.order-note.locked { color: var(--yellow); }
|
|
62
|
+
.sr-only {
|
|
63
|
+
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
|
|
64
|
+
overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
67
|
+
var reorderLiveRegionHtml = `<div id="orderStatus" class="sr-only" role="status" aria-live="polite"></div>`;
|
|
68
|
+
var reorderClientJs = `
|
|
69
|
+
window.meridianReorder = (function () {
|
|
70
|
+
function moveInOrder(order, from, to) {
|
|
71
|
+
var next = order.slice();
|
|
72
|
+
if (from < 0 || from >= next.length) return next;
|
|
73
|
+
if (to < 0 || to >= next.length) return next;
|
|
74
|
+
if (from === to) return next;
|
|
75
|
+
var moved = next.splice(from, 1)[0];
|
|
76
|
+
next.splice(to, 0, moved);
|
|
77
|
+
return next;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function sortByOrder(items, order) {
|
|
81
|
+
// Null-prototype: a profile called "constructor" or "toString" would
|
|
82
|
+
// otherwise test true against Object.prototype and rank as position 0.
|
|
83
|
+
var rank = Object.create(null);
|
|
84
|
+
for (var i = 0; i < order.length; i++) {
|
|
85
|
+
if (!(order[i] in rank)) rank[order[i]] = i;
|
|
86
|
+
}
|
|
87
|
+
return items
|
|
88
|
+
.map(function (item, index) { return { item: item, index: index }; })
|
|
89
|
+
.sort(function (a, b) {
|
|
90
|
+
var ra = a.item.id in rank ? rank[a.item.id] : Number.MAX_SAFE_INTEGER;
|
|
91
|
+
var rb = b.item.id in rank ? rank[b.item.id] : Number.MAX_SAFE_INTEGER;
|
|
92
|
+
if (ra !== rb) return ra - rb;
|
|
93
|
+
return a.index - b.index;
|
|
94
|
+
})
|
|
95
|
+
.map(function (entry) { return entry.item; });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Escapes the attribute delimiter too. The profiles page's own esc() goes
|
|
99
|
+
// through textContent, which leaves a double quote intact and would break
|
|
100
|
+
// out of the aria-label this builds.
|
|
101
|
+
function escAttr(s) {
|
|
102
|
+
return String(s == null ? '' : s).replace(/[&<>"']/g, function (ch) {
|
|
103
|
+
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[ch];
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
var EDGE_ZONE_PX = ${EDGE_ZONE_PX};
|
|
108
|
+
var MAX_SCROLL_PX_PER_FRAME = ${MAX_SCROLL_PX_PER_FRAME};
|
|
109
|
+
|
|
110
|
+
// Mirrors edgeScrollVelocity in src/telemetry/profileOrder.ts, unit-tested
|
|
111
|
+
// in profile-order.test.ts.
|
|
112
|
+
function edgeScrollVelocity(clientY, viewportHeight) {
|
|
113
|
+
if (!isFinite(clientY) || !isFinite(viewportHeight) || viewportHeight <= 0) return 0;
|
|
114
|
+
var zone = Math.min(EDGE_ZONE_PX, viewportHeight / 2);
|
|
115
|
+
if (zone <= 0) return 0;
|
|
116
|
+
if (clientY < zone) return -Math.round(MAX_SCROLL_PX_PER_FRAME * Math.min(1, (zone - clientY) / zone));
|
|
117
|
+
var fromBottom = viewportHeight - clientY;
|
|
118
|
+
if (fromBottom < zone) return Math.round(MAX_SCROLL_PX_PER_FRAME * Math.min(1, (zone - fromBottom) / zone));
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
var velocity = 0;
|
|
123
|
+
var frame = null;
|
|
124
|
+
var pointerSeenAt = 0;
|
|
125
|
+
// A drag that leaves the window stops producing dragover events while the
|
|
126
|
+
// last velocity is still in force, which would scroll to the end on its
|
|
127
|
+
// own. dragend covers the ordinary paths; this covers the rest.
|
|
128
|
+
var POINTER_STALE_MS = 700;
|
|
129
|
+
|
|
130
|
+
function step() {
|
|
131
|
+
frame = null;
|
|
132
|
+
if (velocity === 0) return;
|
|
133
|
+
if (Date.now() - pointerSeenAt > POINTER_STALE_MS) { velocity = 0; return; }
|
|
134
|
+
window.scrollBy(0, velocity);
|
|
135
|
+
frame = window.requestAnimationFrame(step);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function trackPointer(e) {
|
|
139
|
+
if (fromIndex === null) return;
|
|
140
|
+
pointerSeenAt = Date.now();
|
|
141
|
+
velocity = edgeScrollVelocity(e.clientY, window.innerHeight);
|
|
142
|
+
if (velocity !== 0 && frame === null) frame = window.requestAnimationFrame(step);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function stopAutoScroll() {
|
|
146
|
+
velocity = 0;
|
|
147
|
+
if (frame !== null) { window.cancelAnimationFrame(frame); frame = null; }
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
var state = { order: [], envPinned: false };
|
|
151
|
+
var fromIndex = null;
|
|
152
|
+
var pendingFocusId = null;
|
|
153
|
+
var onSaved = function () {};
|
|
154
|
+
|
|
155
|
+
function adopt(cfg) {
|
|
156
|
+
if (!cfg) return;
|
|
157
|
+
if (Array.isArray(cfg.profileOrder)) state.order = cfg.profileOrder;
|
|
158
|
+
state.envPinned = !!(cfg.envOverride && cfg.envOverride.profileOrder);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function sortProfiles(items) { return sortByOrder(items || [], state.order || []); }
|
|
162
|
+
|
|
163
|
+
function announce(message) {
|
|
164
|
+
var live = document.getElementById('orderStatus');
|
|
165
|
+
if (live) live.textContent = message;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function noteHtml(reorderable) {
|
|
169
|
+
return reorderable
|
|
170
|
+
? '<div class="order-note">Drag a card by its handle to reorder, or focus a handle and press \\u2191 / \\u2193. '
|
|
171
|
+
+ 'The order is saved, and drives <a href="/settings" style="color:var(--accent)">Priority routing</a> \\u2014 the pool drains from the top.</div>'
|
|
172
|
+
: '<div class="order-note locked">Order is pinned by the <code>MERIDIAN_PROFILE_ORDER</code> environment variable. Unset it to reorder from here.</div>';
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function handleHtml(id, index, total) {
|
|
176
|
+
return '<span class="order-index">' + (index + 1) + '</span>'
|
|
177
|
+
+ '<button type="button" class="drag-handle" draggable="true" data-index="' + index + '"'
|
|
178
|
+
+ ' title="Drag to reorder, or press \\u2191 / \\u2193"'
|
|
179
|
+
+ ' aria-label="Reorder ' + escAttr(id) + ', position ' + (index + 1) + ' of ' + total
|
|
180
|
+
+ '. Press arrow up or arrow down to move.">\\u283f</button>';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// The rendered order is the truth the server must agree with — read it back
|
|
184
|
+
// off the DOM rather than from the cached config, which may list ids the
|
|
185
|
+
// current /profiles/list no longer has (PUT rejects unknown ids outright).
|
|
186
|
+
function currentOrderIds() {
|
|
187
|
+
var ids = [];
|
|
188
|
+
var cards = document.querySelectorAll('.profile-card[data-id]');
|
|
189
|
+
for (var i = 0; i < cards.length; i++) ids.push(cards[i].dataset.id);
|
|
190
|
+
return ids;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function clearMarks() {
|
|
194
|
+
var marked = document.querySelectorAll('.profile-card.dragging, .profile-card.drop-target');
|
|
195
|
+
for (var i = 0; i < marked.length; i++) marked[i].classList.remove('dragging', 'drop-target');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function save(order, message) {
|
|
199
|
+
var previous = state.order;
|
|
200
|
+
state.order = order;
|
|
201
|
+
return fetch('/settings/api/routing', {
|
|
202
|
+
method: 'PUT',
|
|
203
|
+
headers: { 'Content-Type': 'application/json' },
|
|
204
|
+
body: JSON.stringify({ profileOrder: order })
|
|
205
|
+
}).catch(function () { return null; }).then(function (res) {
|
|
206
|
+
if (!res || !res.ok) {
|
|
207
|
+
state.order = previous;
|
|
208
|
+
announce('Could not save the new order.');
|
|
209
|
+
} else if (message) {
|
|
210
|
+
announce(message);
|
|
211
|
+
}
|
|
212
|
+
return onSaved();
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function moveTo(from, to) {
|
|
217
|
+
var order = currentOrderIds();
|
|
218
|
+
if (to < 0 || to >= order.length || from === to) return;
|
|
219
|
+
save(moveInOrder(order, from, to), order[from] + ' moved to position ' + (to + 1) + ' of ' + order.length + '.');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function init(opts) {
|
|
223
|
+
if (opts && opts.onSaved) onSaved = opts.onSaved;
|
|
224
|
+
var content = document.getElementById('content');
|
|
225
|
+
|
|
226
|
+
content.addEventListener('dragstart', function (e) {
|
|
227
|
+
var handle = e.target.closest && e.target.closest('.drag-handle');
|
|
228
|
+
if (!handle) return;
|
|
229
|
+
var card = handle.closest('.profile-card');
|
|
230
|
+
fromIndex = Number(handle.dataset.index);
|
|
231
|
+
pointerSeenAt = Date.now();
|
|
232
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
233
|
+
// Firefox will not start a drag at all unless the payload is set.
|
|
234
|
+
e.dataTransfer.setData('text/plain', card.dataset.id || '');
|
|
235
|
+
if (e.dataTransfer.setDragImage) e.dataTransfer.setDragImage(card, 24, 24);
|
|
236
|
+
card.classList.add('dragging');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
content.addEventListener('dragover', function (e) {
|
|
240
|
+
if (fromIndex === null) return;
|
|
241
|
+
var card = e.target.closest && e.target.closest('.profile-card');
|
|
242
|
+
if (!card) return;
|
|
243
|
+
// preventDefault is what makes an element a drop target at all.
|
|
244
|
+
e.preventDefault();
|
|
245
|
+
e.dataTransfer.dropEffect = 'move';
|
|
246
|
+
var marked = document.querySelectorAll('.profile-card.drop-target');
|
|
247
|
+
for (var i = 0; i < marked.length; i++) marked[i].classList.remove('drop-target');
|
|
248
|
+
if (Number(card.dataset.index) !== fromIndex) card.classList.add('drop-target');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
content.addEventListener('drop', function (e) {
|
|
252
|
+
if (fromIndex === null) return;
|
|
253
|
+
var card = e.target.closest && e.target.closest('.profile-card');
|
|
254
|
+
if (!card) return;
|
|
255
|
+
e.preventDefault();
|
|
256
|
+
var from = fromIndex;
|
|
257
|
+
var to = Number(card.dataset.index);
|
|
258
|
+
fromIndex = null;
|
|
259
|
+
stopAutoScroll();
|
|
260
|
+
clearMarks();
|
|
261
|
+
moveTo(from, to);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
content.addEventListener('keydown', function (e) {
|
|
265
|
+
if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return;
|
|
266
|
+
var handle = e.target.closest && e.target.closest('.drag-handle');
|
|
267
|
+
if (!handle) return;
|
|
268
|
+
e.preventDefault();
|
|
269
|
+
var order = currentOrderIds();
|
|
270
|
+
var from = Number(handle.dataset.index);
|
|
271
|
+
var to = e.key === 'ArrowUp' ? from - 1 : from + 1;
|
|
272
|
+
if (to < 0 || to >= order.length) return;
|
|
273
|
+
pendingFocusId = order[from];
|
|
274
|
+
moveTo(from, to);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// The page scrolls only while the pointer sits near a viewport edge, and
|
|
278
|
+
// the pointer is over the header or the gap between cards as often as it
|
|
279
|
+
// is over one — so this listens on the document, not on #content.
|
|
280
|
+
document.addEventListener('dragover', trackPointer);
|
|
281
|
+
document.addEventListener('dragend', function () {
|
|
282
|
+
fromIndex = null;
|
|
283
|
+
stopAutoScroll();
|
|
284
|
+
clearMarks();
|
|
285
|
+
});
|
|
286
|
+
document.addEventListener('drop', stopAutoScroll);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// A poll landing mid-drag would replace the very cards being dragged.
|
|
290
|
+
function dragging() { return fromIndex !== null; }
|
|
291
|
+
|
|
292
|
+
// A re-render replaces the focused handle; without this the keyboard path
|
|
293
|
+
// loses focus mid-reorder and the next arrow key goes nowhere.
|
|
294
|
+
function focusAnchor() {
|
|
295
|
+
var pending = pendingFocusId;
|
|
296
|
+
pendingFocusId = null;
|
|
297
|
+
if (pending) return pending;
|
|
298
|
+
var active = document.activeElement;
|
|
299
|
+
if (!active || !active.closest || !active.closest('.drag-handle')) return null;
|
|
300
|
+
var card = active.closest('.profile-card');
|
|
301
|
+
return card ? card.dataset.id : null;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function restoreFocus(id) {
|
|
305
|
+
if (!id) return;
|
|
306
|
+
var cards = document.querySelectorAll('.profile-card[data-id]');
|
|
307
|
+
for (var i = 0; i < cards.length; i++) {
|
|
308
|
+
if (cards[i].dataset.id !== id) continue;
|
|
309
|
+
var handle = cards[i].querySelector('.drag-handle');
|
|
310
|
+
if (handle) handle.focus();
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
adopt: adopt,
|
|
317
|
+
sortProfiles: sortProfiles,
|
|
318
|
+
envPinned: function () { return state.envPinned; },
|
|
319
|
+
noteHtml: noteHtml,
|
|
320
|
+
handleHtml: handleHtml,
|
|
321
|
+
init: init,
|
|
322
|
+
dragging: dragging,
|
|
323
|
+
focusAnchor: focusAnchor,
|
|
324
|
+
restoreFocus: restoreFocus,
|
|
325
|
+
announce: announce
|
|
326
|
+
};
|
|
327
|
+
})();
|
|
328
|
+
`;
|
|
329
|
+
|
|
330
|
+
export { profileFactsJs, reorderCss, reorderLiveRegionHtml, reorderClientJs };
|