@linxin666/dsh-usage 0.4.11 → 0.4.12
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.
|
@@ -88,9 +88,13 @@ export interface PluginSettingsCardProps<TKey extends string = string> {
|
|
|
88
88
|
* is reachable without opening the card and matches a plugin card's shape.
|
|
89
89
|
*/
|
|
90
90
|
headerAction?: ReactNode;
|
|
91
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* Render children even when the settings namespace is not exposed by the
|
|
93
|
+
* host. The 'not exposed' notice still explains the card above them; a card
|
|
94
|
+
* that wants the rows alone hides it through `hideNotExposedNotice`.
|
|
95
|
+
*/
|
|
92
96
|
renderChildrenWhenNotExposed?: boolean;
|
|
93
|
-
/** Hide the 'not exposed'
|
|
97
|
+
/** Hide the 'not exposed' notice, whichever branch renders the card body. */
|
|
94
98
|
hideNotExposedNotice?: boolean;
|
|
95
99
|
/**
|
|
96
100
|
* Compact chrome for a topic card rendered inside another card's body: a
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linxin666/dsh-usage",
|
|
3
3
|
"description": "Usage statistics plugin for the dsh web GUI: per-provider balance and coding-plan quota detection plus a live token usage ledger, with a compact price glance card above the sidebar's Settings row",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.12",
|
|
5
5
|
"icon": "icon.svg",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
@@ -110,9 +110,13 @@ export interface PluginSettingsCardProps<TKey extends string = string> {
|
|
|
110
110
|
* is reachable without opening the card and matches a plugin card's shape.
|
|
111
111
|
*/
|
|
112
112
|
headerAction?: ReactNode
|
|
113
|
-
/**
|
|
113
|
+
/**
|
|
114
|
+
* Render children even when the settings namespace is not exposed by the
|
|
115
|
+
* host. The 'not exposed' notice still explains the card above them; a card
|
|
116
|
+
* that wants the rows alone hides it through `hideNotExposedNotice`.
|
|
117
|
+
*/
|
|
114
118
|
renderChildrenWhenNotExposed?: boolean
|
|
115
|
-
/** Hide the 'not exposed'
|
|
119
|
+
/** Hide the 'not exposed' notice, whichever branch renders the card body. */
|
|
116
120
|
hideNotExposedNotice?: boolean
|
|
117
121
|
/**
|
|
118
122
|
* Compact chrome for a topic card rendered inside another card's body: a
|
|
@@ -228,13 +232,16 @@ export function PluginSettingsCard<TKey extends string = string>(props: PluginSe
|
|
|
228
232
|
// The namespace exists but the Host does not serve it to this client (the
|
|
229
233
|
// official settings allowlist omits third-party namespaces): show a card
|
|
230
234
|
// that explains the gap instead of vanishing, so a missing card never
|
|
231
|
-
// reads as a missing plugin.
|
|
235
|
+
// reads as a missing plugin. A card that keeps its rows anyway keeps the
|
|
236
|
+
// same explanation above them, unless it hides the notice outright.
|
|
237
|
+
const notExposedNotice = state.exposed || props.hideNotExposedNotice === true
|
|
238
|
+
? null
|
|
239
|
+
: <p className={css.notExposed} role="status">{props.t('settings.notExposed')}</p>
|
|
232
240
|
if (!state.exposed && props.renderChildrenWhenNotExposed !== true) {
|
|
233
|
-
const showNotice = props.hideNotExposedNotice !== true
|
|
234
241
|
return (
|
|
235
242
|
<li className={cardClass}>
|
|
236
243
|
{header}
|
|
237
|
-
{bodyRegion(
|
|
244
|
+
{bodyRegion(notExposedNotice)}
|
|
238
245
|
</li>
|
|
239
246
|
)
|
|
240
247
|
}
|
|
@@ -247,6 +254,7 @@ export function PluginSettingsCard<TKey extends string = string>(props: PluginSe
|
|
|
247
254
|
{bodyVisible
|
|
248
255
|
? bodyRegion(
|
|
249
256
|
<>
|
|
257
|
+
{notExposedNotice}
|
|
250
258
|
{!state.writable ? <p className={css.readOnly} role="status">{props.t('settings.readOnly')}</p> : null}
|
|
251
259
|
<CardApply.Provider value={{ commit: props.onSave, revert: props.onDiscard }}>
|
|
252
260
|
{props.children}
|
|
@@ -315,9 +323,15 @@ export function ValueField(props: FieldProps & {
|
|
|
315
323
|
range?: { min: number, max: number, step: number }
|
|
316
324
|
}) {
|
|
317
325
|
const apply = useContext(CardApply)
|
|
326
|
+
// Enter and Escape settle the draft themselves and then leave the field, so
|
|
327
|
+
// the blur they cause is that same settlement reaching the field's edge, not
|
|
328
|
+
// a second write. Without this an Escape reported a discard and then a save,
|
|
329
|
+
// which reads to a consumer as a write still waiting to happen.
|
|
330
|
+
const settledByKey = useRef(false)
|
|
318
331
|
const onKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
|
|
319
332
|
if (apply === null || (event.key !== 'Enter' && event.key !== 'Escape')) return
|
|
320
333
|
event.preventDefault()
|
|
334
|
+
settledByKey.current = true
|
|
321
335
|
if (event.key === 'Enter') apply.commit()
|
|
322
336
|
else apply.revert()
|
|
323
337
|
event.currentTarget.blur()
|
|
@@ -334,7 +348,14 @@ export function ValueField(props: FieldProps & {
|
|
|
334
348
|
disabled={props.disabled}
|
|
335
349
|
onChange={(event) => { props.onEdit(event.target.value) }}
|
|
336
350
|
onKeyDown={onKeyDown}
|
|
337
|
-
|
|
351
|
+
onFocus={() => { settledByKey.current = false }}
|
|
352
|
+
onBlur={() => {
|
|
353
|
+
if (settledByKey.current) {
|
|
354
|
+
settledByKey.current = false
|
|
355
|
+
return
|
|
356
|
+
}
|
|
357
|
+
apply?.commit()
|
|
358
|
+
}}
|
|
338
359
|
/>
|
|
339
360
|
)
|
|
340
361
|
const { range } = props
|