quota-keepalive 0.1.11 → 0.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quota-keepalive",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Unofficial multi-provider quota inventory, check-in, keepalive scheduling, history, and quota trends for Magpie",
5
5
  "keywords": [
6
6
  "magpie",
package/ui/app.js CHANGED
@@ -434,6 +434,22 @@
434
434
  </div>
435
435
  </div>`
436
436
  }
437
+ if (item.kind === "percent") {
438
+ const progress = Math.max(0, Math.min(100, number(item.progress)))
439
+ const label = `${item.name}已用 ${formatNumber(item.percent)}%`
440
+ return `<div class="quota-window">
441
+ <div class="quota-window-head">
442
+ <span class="quota-window-name">${escapeHtml(item.name)}</span>
443
+ <span class="quota-window-value">已用 ${escapeHtml(formatNumber(item.percent))}%</span>
444
+ </div>
445
+ <div class="quota-meter ${escapeHtml(item.level)}" role="progressbar"
446
+ aria-label="${escapeHtml(label)}" aria-valuemin="0" aria-valuemax="100"
447
+ aria-valuenow="${escapeHtml(formatNumber(progress))}">
448
+ <i style="width:${progress}%"></i>
449
+ </div>
450
+ ${item.detail ? `<div class="quota-window-foot">${escapeHtml(item.detail)}</div>` : ""}
451
+ </div>`
452
+ }
437
453
  const detail = item.kind === "display"
438
454
  ? "供应商原样显示,不推断已用或剩余"
439
455
  : item.detail || ""
@@ -15,6 +15,27 @@
15
15
 
16
16
  const clampPercent = (value) => Math.max(0, Math.min(100, number(value)))
17
17
 
18
+ function displayAmount(value) {
19
+ const match = String(value || "").trim().match(
20
+ /^(\d+(?:\.\d*)?|\.\d+)(e[+-]?\d+)?([kmb])?$/i,
21
+ )
22
+ if (!match) return null
23
+ const scale = { k: 1e3, m: 1e6, b: 1e9 }[String(match[3] || "").toLowerCase()] || 1
24
+ const parsed = Number(`${match[1]}${match[2] || ""}`) * scale
25
+ return Number.isFinite(parsed) ? parsed : null
26
+ }
27
+
28
+ function displayPair(display) {
29
+ const pair = String(display || "").split("·", 1)[0].match(
30
+ /^\s*([0-9.,]+(?:e[+-]?\d+)?[kmb]?)\s*\/\s*([0-9.,]+(?:e[+-]?\d+)?[kmb]?)(?:\s+([a-zA-Z]+))?\s*$/i,
31
+ )
32
+ if (!pair) return null
33
+ const first = displayAmount(pair[1].replace(/,/g, ""))
34
+ const total = displayAmount(pair[2].replace(/,/g, ""))
35
+ if (first === null || total === null || total <= 0) return null
36
+ return { first, total, unit: pair[3] || "" }
37
+ }
38
+
18
39
  function quotaLevel(percent) {
19
40
  if (percent >= 100) return "exhausted"
20
41
  if (percent >= 85) return "warning"
@@ -66,6 +87,22 @@
66
87
  return meterItem(name, unit, (limit * Math.max(0, usedPercent)) / 100, limit, usedPercent)
67
88
  }
68
89
  }
90
+ const pair = limit === null && usedPercent !== null ? displayPair(display) : null
91
+ if (pair) {
92
+ const usedShare = (pair.first / pair.total) * 100
93
+ const usedMatches = Math.abs(usedShare - usedPercent) < 0.75
94
+ const remainingMatches = Math.abs(100 - usedShare - usedPercent) < 0.75
95
+ if (usedMatches || !remainingMatches) {
96
+ return meterItem(name, unit || pair.unit, pair.first, pair.total, usedPercent)
97
+ }
98
+ return meterItem(
99
+ name,
100
+ unit || pair.unit,
101
+ pair.total - pair.first,
102
+ pair.total,
103
+ usedPercent,
104
+ )
105
+ }
69
106
  const balance = number(window?.balance)
70
107
  if (balance !== null) {
71
108
  return {
@@ -75,11 +112,15 @@
75
112
  }
76
113
  }
77
114
  if (usedPercent !== null) {
115
+ const percent = clampPercent(usedPercent)
78
116
  return {
79
117
  kind: "percent",
80
118
  name,
81
119
  text: `已用 ${formatNumber(usedPercent)}%`,
82
120
  detail: display ? `供应商显示 ${display}` : "",
121
+ percent,
122
+ progress: percent,
123
+ level: quotaLevel(percent),
83
124
  }
84
125
  }
85
126
  if (display) {