@moguiyu/dsh-tavily 0.1.4 → 0.1.6
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/lib/client.js +63 -78
- package/package.json +1 -1
- package/src/client.js +63 -78
package/lib/client.js
CHANGED
|
@@ -64,16 +64,15 @@ window.__ModuleLoader__.load({
|
|
|
64
64
|
}, react.createElement('span', { style: { position: 'absolute', top: 2, left: checked === true ? 18 : 2, width: 14, height: 14, borderRadius: 7, background: '#fff', transition: 'left .12s ease' } }))
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
function UsageCircle({ percent, size, label }) {
|
|
67
|
+
function UsageCircle({ percent, size, label, onClick }) {
|
|
68
68
|
const radius = 15
|
|
69
69
|
const circumference = 2 * Math.PI * radius
|
|
70
70
|
const pct = percent != null ? Math.min(100, Math.max(0, percent)) : 0
|
|
71
|
-
const warn = pct > 85
|
|
72
71
|
const dim = size || 44
|
|
73
|
-
return react.createElement('
|
|
72
|
+
return react.createElement('button', { type: 'button', title: 'Reload usage', 'aria-label': 'Reload usage', onClick: onClick, style: { position: 'relative', width: dim, height: dim, border: 'none', background: 'transparent', padding: 0, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' } },
|
|
74
73
|
react.createElement('svg', { width: dim, height: dim, viewBox: '0 0 40 40' },
|
|
75
74
|
react.createElement('circle', { cx: 20, cy: 20, r: radius, fill: 'none', stroke: 'var(--dsw-alias-border-l2)', strokeWidth: 4 }),
|
|
76
|
-
react.createElement('circle', { cx: 20, cy: 20, r: radius, fill: 'none', stroke:
|
|
75
|
+
react.createElement('circle', { cx: 20, cy: 20, r: radius, fill: 'none', stroke: 'var(--dsw-alias-state-success-primary)', strokeWidth: 4, strokeLinecap: 'round', strokeDasharray: circumference, strokeDashoffset: circumference - (pct / 100) * circumference, transform: 'rotate(-90 20 20)' })
|
|
77
76
|
),
|
|
78
77
|
react.createElement('span', { style: { position: 'absolute', fontSize: 11, fontWeight: 600, color: 'var(--dsw-alias-label-primary)' } }, label != null ? label : (percent != null ? percent + '%' : '—'))
|
|
79
78
|
)
|
|
@@ -144,10 +143,6 @@ window.__ModuleLoader__.load({
|
|
|
144
143
|
}
|
|
145
144
|
}
|
|
146
145
|
|
|
147
|
-
const hasPending = Object.values(removing).some(Boolean)
|
|
148
|
-
|| Object.values(replacing).some(Boolean)
|
|
149
|
-
|| adds.some((item) => item.value.trim().length > 0)
|
|
150
|
-
|
|
151
146
|
const saveStrategy = async (next) => {
|
|
152
147
|
setBusy(true)
|
|
153
148
|
setNotice(null)
|
|
@@ -191,29 +186,46 @@ window.__ModuleLoader__.load({
|
|
|
191
186
|
}
|
|
192
187
|
}
|
|
193
188
|
|
|
194
|
-
const
|
|
189
|
+
const saveRemove = async (masked) => {
|
|
195
190
|
setBusy(true)
|
|
196
191
|
setNotice(null)
|
|
197
192
|
try {
|
|
198
|
-
const addValues = adds.map((item) => item.value.trim()).filter((value) => value.length > 0)
|
|
199
|
-
const removeMasked = [
|
|
200
|
-
...Object.keys(removing).filter((masked) => removing[masked] === true),
|
|
201
|
-
...Object.keys(replacing).filter((masked) => replacing[masked] === true)
|
|
202
|
-
]
|
|
203
193
|
const response = await fetch('/api/tavily-manager', {
|
|
204
194
|
method: 'POST',
|
|
205
195
|
headers: { 'content-type': 'application/json' },
|
|
206
|
-
body: JSON.stringify({ add:
|
|
196
|
+
body: JSON.stringify({ add: [], remove: [masked], strategy })
|
|
207
197
|
})
|
|
208
198
|
const data = await response.json()
|
|
209
|
-
if (!data.ok) { setNotice({ error: data.error || '
|
|
210
|
-
setNotice({ ok: '
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
199
|
+
if (!data.ok) { setNotice({ error: data.error || 'Delete failed' }); return }
|
|
200
|
+
setNotice({ ok: 'Key removed.' })
|
|
201
|
+
setConfirm((current) => Object.assign({}, current, { [masked]: false }))
|
|
202
|
+
setRemoving((current) => Object.assign({}, current, { [masked]: false }))
|
|
203
|
+
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
204
|
+
await refresh()
|
|
205
|
+
} catch (error) {
|
|
206
|
+
setNotice({ error: String(error && error.message ? error.message : error) })
|
|
207
|
+
} finally {
|
|
208
|
+
setBusy(false)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const saveReplace = async (masked) => {
|
|
213
|
+
const value = typeof replaceDrafts[masked] === 'string' ? replaceDrafts[masked].trim() : ''
|
|
214
|
+
if (!value) return
|
|
215
|
+
setBusy(true)
|
|
216
|
+
setNotice(null)
|
|
217
|
+
try {
|
|
218
|
+
const response = await fetch('/api/tavily-manager', {
|
|
219
|
+
method: 'POST',
|
|
220
|
+
headers: { 'content-type': 'application/json' },
|
|
221
|
+
body: JSON.stringify({ add: [value], remove: [masked], strategy })
|
|
222
|
+
})
|
|
223
|
+
const data = await response.json()
|
|
224
|
+
if (!data.ok) { setNotice({ error: data.error || 'Update failed' }); return }
|
|
225
|
+
setNotice({ ok: 'Key updated.' })
|
|
226
|
+
setReplacing((current) => Object.assign({}, current, { [masked]: false }))
|
|
227
|
+
setReplaceDrafts((current) => Object.assign({}, current, { [masked]: '' }))
|
|
228
|
+
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
217
229
|
await refresh()
|
|
218
230
|
} catch (error) {
|
|
219
231
|
setNotice({ error: String(error && error.message ? error.message : error) })
|
|
@@ -249,6 +261,7 @@ window.__ModuleLoader__.load({
|
|
|
249
261
|
setConfirm((current) => Object.assign({}, current, { [masked]: false }))
|
|
250
262
|
setRemoving((current) => Object.assign({}, current, { [masked]: true }))
|
|
251
263
|
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
264
|
+
saveRemove(masked)
|
|
252
265
|
}
|
|
253
266
|
|
|
254
267
|
const restore = (masked) => {
|
|
@@ -314,16 +327,21 @@ window.__ModuleLoader__.load({
|
|
|
314
327
|
react.createElement('thead', null,
|
|
315
328
|
react.createElement('tr', null,
|
|
316
329
|
react.createElement('th', { style: headStyle }, 'Key'),
|
|
330
|
+
react.createElement('th', { style: headStyle }, 'Usage'),
|
|
317
331
|
react.createElement('th', { style: headStyle }, 'Saved'),
|
|
318
332
|
react.createElement('th', { style: headStyle }, 'Actions')
|
|
319
333
|
)
|
|
320
334
|
),
|
|
321
335
|
react.createElement('tbody', null,
|
|
322
|
-
(server !== null ? server.keys : []).map((key) => {
|
|
336
|
+
(server !== null ? server.keys : []).map((key, index) => {
|
|
323
337
|
const masked = key.masked
|
|
324
338
|
const isRemoved = removing[masked] === true
|
|
325
339
|
const isReplacing = replacing[masked] === true
|
|
326
340
|
const isRevealed = typeof revealed[masked] === 'string'
|
|
341
|
+
const usageRow = usage !== null && usage.ok === true ? usage.perKey[index] : null
|
|
342
|
+
const pct = usageRow && usageRow.ok && usageRow.planLimit != null && usageRow.planLimit > 0 && usageRow.planUsage != null
|
|
343
|
+
? Math.min(100, Math.round((usageRow.planUsage / usageRow.planLimit) * 100))
|
|
344
|
+
: null
|
|
327
345
|
return react.createElement('tr', { key: masked, style: { borderBottom: '1px solid var(--dsw-alias-border-l2)', opacity: isRemoved ? 0.45 : 1 } },
|
|
328
346
|
react.createElement('td', { style: Object.assign({}, cellStyle, { fontFamily: 'var(--ds-font-family-code, monospace)', fontSize: 12, wordBreak: 'break-all' }) },
|
|
329
347
|
isReplacing
|
|
@@ -342,11 +360,14 @@ window.__ModuleLoader__.load({
|
|
|
342
360
|
})
|
|
343
361
|
)
|
|
344
362
|
),
|
|
363
|
+
react.createElement('td', { style: cellStyle },
|
|
364
|
+
react.createElement(UsageCircle, { percent: pct, label: pct != null ? pct + '%' : (usageRow && usageRow.ok && usageRow.planUsage != null ? String(usageRow.planUsage) : '—'), onClick: refresh })
|
|
365
|
+
),
|
|
345
366
|
react.createElement('td', { style: Object.assign({}, cellStyle, { color: 'var(--dsw-alias-label-tertiary)', whiteSpace: 'nowrap' }) }, formatDate(key.savedAt)),
|
|
346
367
|
react.createElement('td', { style: cellStyle },
|
|
347
368
|
isReplacing
|
|
348
369
|
? react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
349
|
-
react.createElement(IconButton, { icon: 'check', title: '
|
|
370
|
+
react.createElement(IconButton, { icon: 'check', title: 'Save key', onClick: () => saveReplace(masked), disabled: busy || (typeof replaceDrafts[masked] === 'string' ? replaceDrafts[masked].trim().length === 0 : true) }),
|
|
350
371
|
react.createElement(IconButton, { icon: 'close', title: 'Cancel', onClick: () => cancelReplace(masked), disabled: busy })
|
|
351
372
|
)
|
|
352
373
|
: react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
@@ -376,6 +397,7 @@ window.__ModuleLoader__.load({
|
|
|
376
397
|
})
|
|
377
398
|
),
|
|
378
399
|
react.createElement('td', { style: cellStyle }, '—'),
|
|
400
|
+
react.createElement('td', { style: cellStyle }, '—'),
|
|
379
401
|
react.createElement('td', { style: cellStyle },
|
|
380
402
|
react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
381
403
|
react.createElement(IconButton, { icon: 'check', title: 'Save key', onClick: () => saveAdd(item), disabled: busy || item.value.trim().length === 0 }),
|
|
@@ -385,63 +407,26 @@ window.__ModuleLoader__.load({
|
|
|
385
407
|
))
|
|
386
408
|
)
|
|
387
409
|
),
|
|
388
|
-
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center' } },
|
|
389
|
-
react.createElement('button', { type: 'button', style: btn, onClick: () => setAdds((current) => [...current, { id: 'add-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7), value: '' }]), disabled: busy }, '+ Add key')
|
|
410
|
+
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' } },
|
|
411
|
+
react.createElement('button', { type: 'button', style: btn, onClick: () => setAdds((current) => [...current, { id: 'add-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7), value: '' }]), disabled: busy }, '+ Add key'),
|
|
390
412
|
),
|
|
391
|
-
react.createElement('div', { style: {
|
|
392
|
-
react.createElement('
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
)
|
|
402
|
-
),
|
|
403
|
-
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center' } },
|
|
404
|
-
react.createElement('button', { type: 'button', style: Object.assign({}, btn, { height: 32, background: 'var(--dsw-alias-button-primary-fill)', color: 'var(--dsw-alias-label-primary-foreground)' }), onClick: save, disabled: busy || !hasPending }, 'Save key changes'),
|
|
405
|
-
notice !== null && react.createElement('span', { style: { fontSize: 13, color: notice.ok ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)' } }, notice.ok ? notice.ok : String(notice.error))
|
|
406
|
-
),
|
|
407
|
-
react.createElement('div', { style: { border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 12, padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 8 } },
|
|
408
|
-
react.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, justifyContent: 'space-between' } },
|
|
409
|
-
react.createElement('span', { style: { fontWeight: 500, fontSize: 13 } }, 'Tavily Usage'),
|
|
410
|
-
react.createElement('button', { type: 'button', style: btn, onClick: refresh, disabled: busy }, 'Refresh')
|
|
413
|
+
react.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 6 } },
|
|
414
|
+
react.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } },
|
|
415
|
+
react.createElement('label', { style: { fontWeight: 500, fontSize: 13 } }, 'Key usage strategy'),
|
|
416
|
+
react.createElement('select', {
|
|
417
|
+
style: { maxWidth: 280, height: 32, border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8, background: 'var(--dsw-alias-bg-layer-1)', color: 'var(--dsw-alias-label-primary)', padding: '0 10px', fontSize: 13 },
|
|
418
|
+
value: strategy,
|
|
419
|
+
onChange: (event) => saveStrategy(event.target.value),
|
|
420
|
+
disabled: busy
|
|
421
|
+
}, STRATEGIES.map((option) => react.createElement('option', { key: option.id, value: option.id }, option.label))),
|
|
422
|
+
notice !== null && react.createElement('span', { style: { fontSize: 13, color: notice.ok ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)' } }, notice.ok ? notice.ok : String(notice.error))
|
|
411
423
|
),
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
usage !== null && usage.ok === true && react.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8 } },
|
|
415
|
-
react.createElement('div', { style: { fontSize: 13 } },
|
|
416
|
-
usage.totals.keys + ' key(s) (' + usage.totals.okKeys + ' readable)' + (usage.totals.planLimit !== null ? ' · plan usage ' + usage.totals.planUsage + ' / ' + usage.totals.planLimit : '')
|
|
417
|
-
),
|
|
418
|
-
react.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: 13 } },
|
|
419
|
-
react.createElement('thead', null,
|
|
420
|
-
react.createElement('tr', null,
|
|
421
|
-
react.createElement('th', { style: headStyle }, 'API Key'),
|
|
422
|
-
react.createElement('th', { style: headStyle }, 'Usage')
|
|
423
|
-
)
|
|
424
|
-
),
|
|
425
|
-
react.createElement('tbody', null,
|
|
426
|
-
(server !== null ? server.keys : []).map((key, index) => {
|
|
427
|
-
const row = usage.perKey[index]
|
|
428
|
-
const pct = row && row.ok && row.planLimit != null && row.planLimit > 0 && row.planUsage != null
|
|
429
|
-
? Math.min(100, Math.round((row.planUsage / row.planLimit) * 100))
|
|
430
|
-
: null
|
|
431
|
-
return react.createElement('tr', { key: key.masked, style: { borderBottom: '1px solid var(--dsw-alias-border-l2)' } },
|
|
432
|
-
react.createElement('td', { style: Object.assign({}, cellStyle, { fontFamily: 'var(--ds-font-family-code, monospace)', fontSize: 12, wordBreak: 'break-all' }) }, key.masked),
|
|
433
|
-
react.createElement('td', { style: cellStyle },
|
|
434
|
-
react.createElement(UsageCircle, { percent: pct, label: pct != null ? pct + '%' : (row && row.ok && row.planUsage != null ? String(row.planUsage) : '—') })
|
|
435
|
-
)
|
|
436
|
-
)
|
|
437
|
-
})
|
|
438
|
-
)
|
|
439
|
-
)
|
|
424
|
+
react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-label-tertiary)' } },
|
|
425
|
+
(STRATEGIES.find((option) => option.id === strategy) || STRATEGIES[0]).hint + ' Saved immediately when selected; the first key then becomes primary for web_search.'
|
|
440
426
|
)
|
|
441
427
|
),
|
|
442
|
-
react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-
|
|
443
|
-
|
|
444
|
-
)
|
|
428
|
+
usageError !== null && react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-state-error-primary)' } }, String(usageError)),
|
|
429
|
+
usage !== null && usage.ok === false && react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-state-error-primary)' } }, String(usage.error))
|
|
445
430
|
)
|
|
446
431
|
)
|
|
447
432
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moguiyu/dsh-tavily",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Tavily Search for DSH: multiple API keys, rotation/failover, usage gauge, settings card, and web_search toggle in one plugin.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
package/src/client.js
CHANGED
|
@@ -69,16 +69,15 @@ export function factory(require) {
|
|
|
69
69
|
}, react.createElement('span', { style: { position: 'absolute', top: 2, left: checked === true ? 18 : 2, width: 14, height: 14, borderRadius: 7, background: '#fff', transition: 'left .12s ease' } }))
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
function UsageCircle({ percent, size, label }) {
|
|
72
|
+
function UsageCircle({ percent, size, label, onClick }) {
|
|
73
73
|
const radius = 15
|
|
74
74
|
const circumference = 2 * Math.PI * radius
|
|
75
75
|
const pct = percent != null ? Math.min(100, Math.max(0, percent)) : 0
|
|
76
|
-
const warn = pct > 85
|
|
77
76
|
const dim = size || 44
|
|
78
|
-
return react.createElement('
|
|
77
|
+
return react.createElement('button', { type: 'button', title: 'Reload usage', 'aria-label': 'Reload usage', onClick: onClick, style: { position: 'relative', width: dim, height: dim, border: 'none', background: 'transparent', padding: 0, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' } },
|
|
79
78
|
react.createElement('svg', { width: dim, height: dim, viewBox: '0 0 40 40' },
|
|
80
79
|
react.createElement('circle', { cx: 20, cy: 20, r: radius, fill: 'none', stroke: 'var(--dsw-alias-border-l2)', strokeWidth: 4 }),
|
|
81
|
-
react.createElement('circle', { cx: 20, cy: 20, r: radius, fill: 'none', stroke:
|
|
80
|
+
react.createElement('circle', { cx: 20, cy: 20, r: radius, fill: 'none', stroke: 'var(--dsw-alias-state-success-primary)', strokeWidth: 4, strokeLinecap: 'round', strokeDasharray: circumference, strokeDashoffset: circumference - (pct / 100) * circumference, transform: 'rotate(-90 20 20)' })
|
|
82
81
|
),
|
|
83
82
|
react.createElement('span', { style: { position: 'absolute', fontSize: 11, fontWeight: 600, color: 'var(--dsw-alias-label-primary)' } }, label != null ? label : (percent != null ? percent + '%' : '—'))
|
|
84
83
|
)
|
|
@@ -149,10 +148,6 @@ export function factory(require) {
|
|
|
149
148
|
}
|
|
150
149
|
}
|
|
151
150
|
|
|
152
|
-
const hasPending = Object.values(removing).some(Boolean)
|
|
153
|
-
|| Object.values(replacing).some(Boolean)
|
|
154
|
-
|| adds.some((item) => item.value.trim().length > 0)
|
|
155
|
-
|
|
156
151
|
const saveStrategy = async (next) => {
|
|
157
152
|
setBusy(true)
|
|
158
153
|
setNotice(null)
|
|
@@ -196,29 +191,46 @@ export function factory(require) {
|
|
|
196
191
|
}
|
|
197
192
|
}
|
|
198
193
|
|
|
199
|
-
const
|
|
194
|
+
const saveRemove = async (masked) => {
|
|
200
195
|
setBusy(true)
|
|
201
196
|
setNotice(null)
|
|
202
197
|
try {
|
|
203
|
-
const addValues = adds.map((item) => item.value.trim()).filter((value) => value.length > 0)
|
|
204
|
-
const removeMasked = [
|
|
205
|
-
...Object.keys(removing).filter((masked) => removing[masked] === true),
|
|
206
|
-
...Object.keys(replacing).filter((masked) => replacing[masked] === true)
|
|
207
|
-
]
|
|
208
198
|
const response = await fetch('/api/tavily-manager', {
|
|
209
199
|
method: 'POST',
|
|
210
200
|
headers: { 'content-type': 'application/json' },
|
|
211
|
-
body: JSON.stringify({ add:
|
|
201
|
+
body: JSON.stringify({ add: [], remove: [masked], strategy })
|
|
212
202
|
})
|
|
213
203
|
const data = await response.json()
|
|
214
|
-
if (!data.ok) { setNotice({ error: data.error || '
|
|
215
|
-
setNotice({ ok: '
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
204
|
+
if (!data.ok) { setNotice({ error: data.error || 'Delete failed' }); return }
|
|
205
|
+
setNotice({ ok: 'Key removed.' })
|
|
206
|
+
setConfirm((current) => Object.assign({}, current, { [masked]: false }))
|
|
207
|
+
setRemoving((current) => Object.assign({}, current, { [masked]: false }))
|
|
208
|
+
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
209
|
+
await refresh()
|
|
210
|
+
} catch (error) {
|
|
211
|
+
setNotice({ error: String(error && error.message ? error.message : error) })
|
|
212
|
+
} finally {
|
|
213
|
+
setBusy(false)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const saveReplace = async (masked) => {
|
|
218
|
+
const value = typeof replaceDrafts[masked] === 'string' ? replaceDrafts[masked].trim() : ''
|
|
219
|
+
if (!value) return
|
|
220
|
+
setBusy(true)
|
|
221
|
+
setNotice(null)
|
|
222
|
+
try {
|
|
223
|
+
const response = await fetch('/api/tavily-manager', {
|
|
224
|
+
method: 'POST',
|
|
225
|
+
headers: { 'content-type': 'application/json' },
|
|
226
|
+
body: JSON.stringify({ add: [value], remove: [masked], strategy })
|
|
227
|
+
})
|
|
228
|
+
const data = await response.json()
|
|
229
|
+
if (!data.ok) { setNotice({ error: data.error || 'Update failed' }); return }
|
|
230
|
+
setNotice({ ok: 'Key updated.' })
|
|
231
|
+
setReplacing((current) => Object.assign({}, current, { [masked]: false }))
|
|
232
|
+
setReplaceDrafts((current) => Object.assign({}, current, { [masked]: '' }))
|
|
233
|
+
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
222
234
|
await refresh()
|
|
223
235
|
} catch (error) {
|
|
224
236
|
setNotice({ error: String(error && error.message ? error.message : error) })
|
|
@@ -254,6 +266,7 @@ export function factory(require) {
|
|
|
254
266
|
setConfirm((current) => Object.assign({}, current, { [masked]: false }))
|
|
255
267
|
setRemoving((current) => Object.assign({}, current, { [masked]: true }))
|
|
256
268
|
setRevealed((current) => Object.assign({}, current, { [masked]: false }))
|
|
269
|
+
saveRemove(masked)
|
|
257
270
|
}
|
|
258
271
|
|
|
259
272
|
const restore = (masked) => {
|
|
@@ -319,16 +332,21 @@ export function factory(require) {
|
|
|
319
332
|
react.createElement('thead', null,
|
|
320
333
|
react.createElement('tr', null,
|
|
321
334
|
react.createElement('th', { style: headStyle }, 'Key'),
|
|
335
|
+
react.createElement('th', { style: headStyle }, 'Usage'),
|
|
322
336
|
react.createElement('th', { style: headStyle }, 'Saved'),
|
|
323
337
|
react.createElement('th', { style: headStyle }, 'Actions')
|
|
324
338
|
)
|
|
325
339
|
),
|
|
326
340
|
react.createElement('tbody', null,
|
|
327
|
-
(server !== null ? server.keys : []).map((key) => {
|
|
341
|
+
(server !== null ? server.keys : []).map((key, index) => {
|
|
328
342
|
const masked = key.masked
|
|
329
343
|
const isRemoved = removing[masked] === true
|
|
330
344
|
const isReplacing = replacing[masked] === true
|
|
331
345
|
const isRevealed = typeof revealed[masked] === 'string'
|
|
346
|
+
const usageRow = usage !== null && usage.ok === true ? usage.perKey[index] : null
|
|
347
|
+
const pct = usageRow && usageRow.ok && usageRow.planLimit != null && usageRow.planLimit > 0 && usageRow.planUsage != null
|
|
348
|
+
? Math.min(100, Math.round((usageRow.planUsage / usageRow.planLimit) * 100))
|
|
349
|
+
: null
|
|
332
350
|
return react.createElement('tr', { key: masked, style: { borderBottom: '1px solid var(--dsw-alias-border-l2)', opacity: isRemoved ? 0.45 : 1 } },
|
|
333
351
|
react.createElement('td', { style: Object.assign({}, cellStyle, { fontFamily: 'var(--ds-font-family-code, monospace)', fontSize: 12, wordBreak: 'break-all' }) },
|
|
334
352
|
isReplacing
|
|
@@ -347,11 +365,14 @@ export function factory(require) {
|
|
|
347
365
|
})
|
|
348
366
|
)
|
|
349
367
|
),
|
|
368
|
+
react.createElement('td', { style: cellStyle },
|
|
369
|
+
react.createElement(UsageCircle, { percent: pct, label: pct != null ? pct + '%' : (usageRow && usageRow.ok && usageRow.planUsage != null ? String(usageRow.planUsage) : '—'), onClick: refresh })
|
|
370
|
+
),
|
|
350
371
|
react.createElement('td', { style: Object.assign({}, cellStyle, { color: 'var(--dsw-alias-label-tertiary)', whiteSpace: 'nowrap' }) }, formatDate(key.savedAt)),
|
|
351
372
|
react.createElement('td', { style: cellStyle },
|
|
352
373
|
isReplacing
|
|
353
374
|
? react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
354
|
-
react.createElement(IconButton, { icon: 'check', title: '
|
|
375
|
+
react.createElement(IconButton, { icon: 'check', title: 'Save key', onClick: () => saveReplace(masked), disabled: busy || (typeof replaceDrafts[masked] === 'string' ? replaceDrafts[masked].trim().length === 0 : true) }),
|
|
355
376
|
react.createElement(IconButton, { icon: 'close', title: 'Cancel', onClick: () => cancelReplace(masked), disabled: busy })
|
|
356
377
|
)
|
|
357
378
|
: react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
@@ -381,6 +402,7 @@ export function factory(require) {
|
|
|
381
402
|
})
|
|
382
403
|
),
|
|
383
404
|
react.createElement('td', { style: cellStyle }, '—'),
|
|
405
|
+
react.createElement('td', { style: cellStyle }, '—'),
|
|
384
406
|
react.createElement('td', { style: cellStyle },
|
|
385
407
|
react.createElement('span', { style: { display: 'inline-flex', gap: 2 } },
|
|
386
408
|
react.createElement(IconButton, { icon: 'check', title: 'Save key', onClick: () => saveAdd(item), disabled: busy || item.value.trim().length === 0 }),
|
|
@@ -390,63 +412,26 @@ export function factory(require) {
|
|
|
390
412
|
))
|
|
391
413
|
)
|
|
392
414
|
),
|
|
393
|
-
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center' } },
|
|
394
|
-
react.createElement('button', { type: 'button', style: btn, onClick: () => setAdds((current) => [...current, { id: 'add-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7), value: '' }]), disabled: busy }, '+ Add key')
|
|
415
|
+
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' } },
|
|
416
|
+
react.createElement('button', { type: 'button', style: btn, onClick: () => setAdds((current) => [...current, { id: 'add-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7), value: '' }]), disabled: busy }, '+ Add key'),
|
|
395
417
|
),
|
|
396
|
-
react.createElement('div', { style: {
|
|
397
|
-
react.createElement('
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
)
|
|
407
|
-
),
|
|
408
|
-
react.createElement('div', { style: { display: 'flex', gap: 8, alignItems: 'center' } },
|
|
409
|
-
react.createElement('button', { type: 'button', style: Object.assign({}, btn, { height: 32, background: 'var(--dsw-alias-button-primary-fill)', color: 'var(--dsw-alias-label-primary-foreground)' }), onClick: save, disabled: busy || !hasPending }, 'Save key changes'),
|
|
410
|
-
notice !== null && react.createElement('span', { style: { fontSize: 13, color: notice.ok ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)' } }, notice.ok ? notice.ok : String(notice.error))
|
|
411
|
-
),
|
|
412
|
-
react.createElement('div', { style: { border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 12, padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 8 } },
|
|
413
|
-
react.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, justifyContent: 'space-between' } },
|
|
414
|
-
react.createElement('span', { style: { fontWeight: 500, fontSize: 13 } }, 'Tavily Usage'),
|
|
415
|
-
react.createElement('button', { type: 'button', style: btn, onClick: refresh, disabled: busy }, 'Refresh')
|
|
418
|
+
react.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 6 } },
|
|
419
|
+
react.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' } },
|
|
420
|
+
react.createElement('label', { style: { fontWeight: 500, fontSize: 13 } }, 'Key usage strategy'),
|
|
421
|
+
react.createElement('select', {
|
|
422
|
+
style: { maxWidth: 280, height: 32, border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8, background: 'var(--dsw-alias-bg-layer-1)', color: 'var(--dsw-alias-label-primary)', padding: '0 10px', fontSize: 13 },
|
|
423
|
+
value: strategy,
|
|
424
|
+
onChange: (event) => saveStrategy(event.target.value),
|
|
425
|
+
disabled: busy
|
|
426
|
+
}, STRATEGIES.map((option) => react.createElement('option', { key: option.id, value: option.id }, option.label))),
|
|
427
|
+
notice !== null && react.createElement('span', { style: { fontSize: 13, color: notice.ok ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)' } }, notice.ok ? notice.ok : String(notice.error))
|
|
416
428
|
),
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
usage !== null && usage.ok === true && react.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 8 } },
|
|
420
|
-
react.createElement('div', { style: { fontSize: 13 } },
|
|
421
|
-
usage.totals.keys + ' key(s) (' + usage.totals.okKeys + ' readable)' + (usage.totals.planLimit !== null ? ' · plan usage ' + usage.totals.planUsage + ' / ' + usage.totals.planLimit : '')
|
|
422
|
-
),
|
|
423
|
-
react.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: 13 } },
|
|
424
|
-
react.createElement('thead', null,
|
|
425
|
-
react.createElement('tr', null,
|
|
426
|
-
react.createElement('th', { style: headStyle }, 'API Key'),
|
|
427
|
-
react.createElement('th', { style: headStyle }, 'Usage')
|
|
428
|
-
)
|
|
429
|
-
),
|
|
430
|
-
react.createElement('tbody', null,
|
|
431
|
-
(server !== null ? server.keys : []).map((key, index) => {
|
|
432
|
-
const row = usage.perKey[index]
|
|
433
|
-
const pct = row && row.ok && row.planLimit != null && row.planLimit > 0 && row.planUsage != null
|
|
434
|
-
? Math.min(100, Math.round((row.planUsage / row.planLimit) * 100))
|
|
435
|
-
: null
|
|
436
|
-
return react.createElement('tr', { key: key.masked, style: { borderBottom: '1px solid var(--dsw-alias-border-l2)' } },
|
|
437
|
-
react.createElement('td', { style: Object.assign({}, cellStyle, { fontFamily: 'var(--ds-font-family-code, monospace)', fontSize: 12, wordBreak: 'break-all' }) }, key.masked),
|
|
438
|
-
react.createElement('td', { style: cellStyle },
|
|
439
|
-
react.createElement(UsageCircle, { percent: pct, label: pct != null ? pct + '%' : (row && row.ok && row.planUsage != null ? String(row.planUsage) : '—') })
|
|
440
|
-
)
|
|
441
|
-
)
|
|
442
|
-
})
|
|
443
|
-
)
|
|
444
|
-
)
|
|
429
|
+
react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-label-tertiary)' } },
|
|
430
|
+
(STRATEGIES.find((option) => option.id === strategy) || STRATEGIES[0]).hint + ' Saved immediately when selected; the first key then becomes primary for web_search.'
|
|
445
431
|
)
|
|
446
432
|
),
|
|
447
|
-
react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-
|
|
448
|
-
|
|
449
|
-
)
|
|
433
|
+
usageError !== null && react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-state-error-primary)' } }, String(usageError)),
|
|
434
|
+
usage !== null && usage.ok === false && react.createElement('p', { style: { margin: 0, fontSize: 12, color: 'var(--dsw-alias-state-error-primary)' } }, String(usage.error))
|
|
450
435
|
)
|
|
451
436
|
)
|
|
452
437
|
)
|