dsh-workbuddy-connect 0.7.0 → 0.7.2
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/README.en.md +53 -13
- package/README.md +47 -13
- package/lib/bin.js +1 -1
- package/lib/client.js +253 -32
- package/lib/{host-heartbeat-d_lBAk8t.js → host-heartbeat-DJb8l_4O.js} +362 -35
- package/lib/index.d.ts +85 -2
- package/lib/index.js +97 -7
- package/package.json +12 -10
package/lib/client.js
CHANGED
|
@@ -97,7 +97,8 @@ window.__ModuleLoader__.load({
|
|
|
97
97
|
statusPath: WORKBUDDY_STATUS_PATH,
|
|
98
98
|
probePath: WORKBUDDY_PROBE_PATH,
|
|
99
99
|
appName: "WorkBuddy",
|
|
100
|
-
unavailableKey: "assistUnavailableCN"
|
|
100
|
+
unavailableKey: "assistUnavailableCN",
|
|
101
|
+
creditPrefix: "WB."
|
|
101
102
|
};
|
|
102
103
|
/** International WorkBuddy AI. */
|
|
103
104
|
const AI_CARD_VARIANT = {
|
|
@@ -108,7 +109,8 @@ window.__ModuleLoader__.load({
|
|
|
108
109
|
statusPath: WORKBUDDY_AI_STATUS_PATH,
|
|
109
110
|
probePath: WORKBUDDY_AI_PROBE_PATH,
|
|
110
111
|
appName: "WorkBuddy AI",
|
|
111
|
-
unavailableKey: "assistUnavailableAI"
|
|
112
|
+
unavailableKey: "assistUnavailableAI",
|
|
113
|
+
creditPrefix: "WB AI."
|
|
112
114
|
};
|
|
113
115
|
/** Both cards, in display order. */
|
|
114
116
|
const CARD_VARIANTS = [CN_CARD_VARIANT, AI_CARD_VARIANT];
|
|
@@ -304,6 +306,31 @@ window.__ModuleLoader__.load({
|
|
|
304
306
|
...bodyStyle$1,
|
|
305
307
|
color: "var(--dsw-alias-state-error-primary)"
|
|
306
308
|
};
|
|
309
|
+
const noticeStyle = {
|
|
310
|
+
display: "flex",
|
|
311
|
+
flexDirection: "column",
|
|
312
|
+
gap: 2,
|
|
313
|
+
padding: "10px 12px",
|
|
314
|
+
borderRadius: 8,
|
|
315
|
+
border: "1px solid",
|
|
316
|
+
fontSize: 13,
|
|
317
|
+
lineHeight: "18px"
|
|
318
|
+
};
|
|
319
|
+
const noticeDetailStyle = {
|
|
320
|
+
fontSize: 12,
|
|
321
|
+
lineHeight: "16px",
|
|
322
|
+
opacity: .8
|
|
323
|
+
};
|
|
324
|
+
const urgentNoticeStyle = {
|
|
325
|
+
background: "var(--dsw-alias-state-warn-tertiary, #fff4e5)",
|
|
326
|
+
borderColor: "var(--dsw-alias-state-warn-primary, #d97706)",
|
|
327
|
+
color: "var(--dsw-alias-label-primary)"
|
|
328
|
+
};
|
|
329
|
+
const warnNoticeStyle = {
|
|
330
|
+
background: "var(--dsw-alias-bg-l2, #f6f7f9)",
|
|
331
|
+
borderColor: "var(--dsw-alias-border-l2)",
|
|
332
|
+
color: "var(--dsw-alias-label-primary)"
|
|
333
|
+
};
|
|
307
334
|
const quotaListStyle = {
|
|
308
335
|
display: "flex",
|
|
309
336
|
flexDirection: "column",
|
|
@@ -563,6 +590,54 @@ window.__ModuleLoader__.load({
|
|
|
563
590
|
return time;
|
|
564
591
|
}
|
|
565
592
|
/**
|
|
593
|
+
* A warning that credit is about to lapse.
|
|
594
|
+
*
|
|
595
|
+
* The total alone cannot express this: a package expiring in an hour and one
|
|
596
|
+
* expiring next month both render as "500 credit", so a user watching only the
|
|
597
|
+
* total loses the first one silently. The banner names the amount, the package
|
|
598
|
+
* count and the soonest expiry, and escalates 7d → 24h.
|
|
599
|
+
*
|
|
600
|
+
* Only future horizons are covered: the billing query behind this returns
|
|
601
|
+
* `valid` + `usedUp` packages from the current time forward, so an
|
|
602
|
+
* already-lapsed package never reaches here.
|
|
603
|
+
*
|
|
604
|
+
* Renders nothing when the upstream reported no end times at all — absence of
|
|
605
|
+
* expiry data is not evidence that nothing expires, so the component stays
|
|
606
|
+
* silent rather than reassuring.
|
|
607
|
+
*/
|
|
608
|
+
function ExpiryNotice({ expiry, t }) {
|
|
609
|
+
const { within24h, within7d } = expiry;
|
|
610
|
+
let message;
|
|
611
|
+
let soonest;
|
|
612
|
+
let tone;
|
|
613
|
+
if (within24h.packages > 0) {
|
|
614
|
+
message = t("expiryWarningSoon", {
|
|
615
|
+
total: formatNumber(Math.round(within24h.total * 100) / 100),
|
|
616
|
+
packages: String(within24h.packages)
|
|
617
|
+
});
|
|
618
|
+
soonest = within24h.earliestEndTimeMs;
|
|
619
|
+
tone = urgentNoticeStyle;
|
|
620
|
+
} else if (within7d.packages > 0) {
|
|
621
|
+
message = t("expiryWarningWeek", {
|
|
622
|
+
total: formatNumber(Math.round(within7d.total * 100) / 100),
|
|
623
|
+
packages: String(within7d.packages)
|
|
624
|
+
});
|
|
625
|
+
soonest = within7d.earliestEndTimeMs;
|
|
626
|
+
tone = warnNoticeStyle;
|
|
627
|
+
} else return null;
|
|
628
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
629
|
+
style: {
|
|
630
|
+
...noticeStyle,
|
|
631
|
+
...tone
|
|
632
|
+
},
|
|
633
|
+
role: "status",
|
|
634
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: message }), soonest === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
635
|
+
style: noticeDetailStyle,
|
|
636
|
+
children: t("expiryExpiresAt", { time: formatTime(soonest) })
|
|
637
|
+
})]
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
566
641
|
* One billing package as a labeled progress bar.
|
|
567
642
|
*
|
|
568
643
|
* A package whose allowance the upstream never reported (`size` not positive)
|
|
@@ -1288,19 +1363,26 @@ window.__ModuleLoader__.load({
|
|
|
1288
1363
|
children: [
|
|
1289
1364
|
status.credits === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1290
1365
|
style: quotaListStyle,
|
|
1291
|
-
children: [
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
style:
|
|
1298
|
-
children:
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1366
|
+
children: [
|
|
1367
|
+
status.credits.expiry === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ExpiryNotice, {
|
|
1368
|
+
expiry: status.credits.expiry,
|
|
1369
|
+
t
|
|
1370
|
+
}),
|
|
1371
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1372
|
+
style: rowStyle$1,
|
|
1373
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1374
|
+
style: quotaTitleStyle,
|
|
1375
|
+
children: t("creditsHeading")
|
|
1376
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1377
|
+
style: bodyStyle$1,
|
|
1378
|
+
children: status.credits.unlimited === true ? t("creditsTotalUnlimited") : t("creditsTotal", { total: formatNumber(status.credits.total) })
|
|
1379
|
+
})]
|
|
1380
|
+
}),
|
|
1381
|
+
status.credits.cycleResetTime === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1382
|
+
style: descriptionStyle,
|
|
1383
|
+
children: t("cycleResetAt", { time: formatCycleReset(status.credits.cycleResetTime) })
|
|
1384
|
+
})
|
|
1385
|
+
]
|
|
1304
1386
|
}),
|
|
1305
1387
|
status.creditsError === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1306
1388
|
style: errorStyle,
|
|
@@ -1410,6 +1492,19 @@ window.__ModuleLoader__.load({
|
|
|
1410
1492
|
* `window.confirm`. Probing spends real credit, so a confirmation stays — but
|
|
1411
1493
|
* it belongs next to the thing it acts on, sized to one line plus two small
|
|
1412
1494
|
* buttons.
|
|
1495
|
+
* - a **credit badge** (#99): the account's remaining balance as one tiny
|
|
1496
|
+
* annotation on the same seat, read from the same status document as the
|
|
1497
|
+
* probe entry. Hidden whenever the document has no answer (signed-out,
|
|
1498
|
+
* error, missing `credits`); zero is a real balance and is shown, `unlimited`
|
|
1499
|
+
* renders as ∞ rather than as 0. The badge is why the control stays mounted
|
|
1500
|
+
* for non-candidate models: the probe entry alone is what disappears for
|
|
1501
|
+
* them.
|
|
1502
|
+
* - a **↻ beside the badge** is the only re-read after the mount fetch: there
|
|
1503
|
+
* is no interval and no focus polling, because every status GET also queries
|
|
1504
|
+
* billing upstream and the balance should not refresh behind the user's
|
|
1505
|
+
* back. A failed manual read hides the balance rather than passing the old
|
|
1506
|
+
* one off as current; a click also picks up probes started elsewhere, which
|
|
1507
|
+
* is the reconcile the removed poll used to provide.
|
|
1413
1508
|
*
|
|
1414
1509
|
* @module dsh-workbuddy-connect/client/probe-control
|
|
1415
1510
|
*/
|
|
@@ -1423,8 +1518,6 @@ window.__ModuleLoader__.load({
|
|
|
1423
1518
|
function cardVariantFor(provider) {
|
|
1424
1519
|
return CARD_VARIANTS.find((card) => card.id === provider);
|
|
1425
1520
|
}
|
|
1426
|
-
/** How often the control re-checks state when the window regains focus. */
|
|
1427
|
-
const RECONCILE_MS = 6e4;
|
|
1428
1521
|
const wrapperStyle = {
|
|
1429
1522
|
display: "inline-flex",
|
|
1430
1523
|
position: "relative",
|
|
@@ -1457,6 +1550,35 @@ window.__ModuleLoader__.load({
|
|
|
1457
1550
|
lineHeight: "16px",
|
|
1458
1551
|
color: "var(--dsw-alias-label-tertiary)"
|
|
1459
1552
|
};
|
|
1553
|
+
/**
|
|
1554
|
+
* The credit badge (#99). The same annotation register as {@link labelStyle} —
|
|
1555
|
+
* small and dim, on the model name's side of the seat — so a changing balance
|
|
1556
|
+
* reads as a note on the selection, not composer chrome of its own.
|
|
1557
|
+
*/
|
|
1558
|
+
const creditStyle = {
|
|
1559
|
+
fontSize: 11,
|
|
1560
|
+
lineHeight: "16px",
|
|
1561
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
1562
|
+
whiteSpace: "nowrap",
|
|
1563
|
+
padding: "0 4px"
|
|
1564
|
+
};
|
|
1565
|
+
/**
|
|
1566
|
+
* The badge's ↻ (#99): the only re-read after the mount fetch. An icon-only
|
|
1567
|
+
* button in the same dim register, so it reads as part of the annotation
|
|
1568
|
+
* rather than a fourth composer control.
|
|
1569
|
+
*/
|
|
1570
|
+
const refreshStyle = {
|
|
1571
|
+
display: "inline-flex",
|
|
1572
|
+
alignItems: "center",
|
|
1573
|
+
justifyContent: "center",
|
|
1574
|
+
width: 20,
|
|
1575
|
+
height: 20,
|
|
1576
|
+
padding: 0,
|
|
1577
|
+
border: 0,
|
|
1578
|
+
borderRadius: 6,
|
|
1579
|
+
background: "transparent",
|
|
1580
|
+
color: "var(--dsw-alias-label-tertiary)"
|
|
1581
|
+
};
|
|
1460
1582
|
/** Tooltip bubble: the Fast Mode shape (nowrap, one line, above the control). */
|
|
1461
1583
|
const tooltipStyle = {
|
|
1462
1584
|
position: "absolute",
|
|
@@ -1576,6 +1698,28 @@ window.__ModuleLoader__.load({
|
|
|
1576
1698
|
return status.probe?.results.find((result) => result.id === model);
|
|
1577
1699
|
}
|
|
1578
1700
|
/**
|
|
1701
|
+
* The credit badge's one line, or `undefined` whenever there is no honest
|
|
1702
|
+
* answer to show (#99).
|
|
1703
|
+
*
|
|
1704
|
+
* Every non-answer collapses to hidden: a signed-out or errored document, a
|
|
1705
|
+
* missing `credits` section (which is also all a `creditsError` leaves behind),
|
|
1706
|
+
* or a total that is not a finite number — the status guard deliberately does
|
|
1707
|
+
* not validate optional fields, so this narrows before reading. Zero is a real
|
|
1708
|
+
* balance and is shown; `unlimited` renders as ∞, never as 0.
|
|
1709
|
+
*/
|
|
1710
|
+
function creditBadge(status, card, t) {
|
|
1711
|
+
if (status === void 0 || status.status !== "signed-in") return void 0;
|
|
1712
|
+
if (status.creditsError !== void 0) return void 0;
|
|
1713
|
+
const credits = status.credits;
|
|
1714
|
+
if (credits === void 0) return void 0;
|
|
1715
|
+
const total = credits.unlimited === true ? "∞" : typeof credits.total === "number" && Number.isFinite(credits.total) ? new Intl.NumberFormat(void 0, { maximumFractionDigits: 2 }).format(credits.total) : void 0;
|
|
1716
|
+
if (total === void 0) return void 0;
|
|
1717
|
+
return t("composerCredit", {
|
|
1718
|
+
prefix: card.creditPrefix,
|
|
1719
|
+
total
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1722
|
+
/**
|
|
1579
1723
|
* The one-line tooltip: current state first, then what a click does — the same
|
|
1580
1724
|
* two-part shape Fast Mode uses.
|
|
1581
1725
|
*
|
|
@@ -1618,7 +1762,16 @@ window.__ModuleLoader__.load({
|
|
|
1618
1762
|
const [tooltipVisible, setTooltipVisible] = (0, react.useState)(false);
|
|
1619
1763
|
const [failed, setFailed] = (0, react.useState)(false);
|
|
1620
1764
|
const [note, setNote] = (0, react.useState)();
|
|
1765
|
+
/**
|
|
1766
|
+
* A manual credit read failed (#99). The balance hides until a later read
|
|
1767
|
+
* succeeds, so the old number can never pose as current; the probe state is
|
|
1768
|
+
* untouched — the two features merely share one document.
|
|
1769
|
+
*/
|
|
1770
|
+
const [creditFailed, setCreditFailed] = (0, react.useState)(false);
|
|
1771
|
+
/** Whether a manual credit refresh is in flight, for the ↻'s busy state. */
|
|
1772
|
+
const [refreshing, setRefreshing] = (0, react.useState)(false);
|
|
1621
1773
|
const inFlight = (0, react.useRef)(false);
|
|
1774
|
+
const refreshingRef = (0, react.useRef)(false);
|
|
1622
1775
|
const mounted = (0, react.useRef)(false);
|
|
1623
1776
|
const readSeq = (0, react.useRef)(0);
|
|
1624
1777
|
const tooltipId = (0, react.useId)();
|
|
@@ -1626,30 +1779,56 @@ window.__ModuleLoader__.load({
|
|
|
1626
1779
|
const seq = ++readSeq.current;
|
|
1627
1780
|
const response = await fetch(card.statusPath, {
|
|
1628
1781
|
credentials: "same-origin",
|
|
1782
|
+
cache: "no-store",
|
|
1629
1783
|
headers: { accept: "application/json" },
|
|
1630
1784
|
...signal === void 0 ? {} : { signal }
|
|
1631
1785
|
});
|
|
1632
1786
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
1633
1787
|
const value = await response.json().catch(() => void 0);
|
|
1634
1788
|
if (!isWorkBuddyWebStatus(value)) throw new Error(t("statusResponseInvalid"));
|
|
1635
|
-
if (mounted.current && !signal?.aborted && seq === readSeq.current)
|
|
1789
|
+
if (mounted.current && !signal?.aborted && seq === readSeq.current) {
|
|
1790
|
+
setStatus(value);
|
|
1791
|
+
setCreditFailed(false);
|
|
1792
|
+
}
|
|
1636
1793
|
}, [card.statusPath, t]);
|
|
1637
1794
|
(0, react.useEffect)(() => {
|
|
1638
1795
|
mounted.current = true;
|
|
1639
1796
|
const controller = new AbortController();
|
|
1640
|
-
|
|
1641
|
-
refresh(controller.signal).catch(() => {});
|
|
1642
|
-
};
|
|
1643
|
-
load();
|
|
1644
|
-
const timer = window.setInterval(load, RECONCILE_MS);
|
|
1645
|
-
window.addEventListener("focus", load);
|
|
1797
|
+
refresh(controller.signal).catch(() => {});
|
|
1646
1798
|
return () => {
|
|
1647
1799
|
mounted.current = false;
|
|
1648
1800
|
controller.abort();
|
|
1649
|
-
window.clearInterval(timer);
|
|
1650
|
-
window.removeEventListener("focus", load);
|
|
1651
1801
|
};
|
|
1652
1802
|
}, [refresh]);
|
|
1803
|
+
/**
|
|
1804
|
+
* The ↻'s action (#99): one manual re-read through the same status route.
|
|
1805
|
+
*
|
|
1806
|
+
* The guard is a ref, not the state: two clicks inside one act batch both
|
|
1807
|
+
* see the same stale `refreshing` closure, and only a synchronous check can
|
|
1808
|
+
* keep the second click from sending a second billing read.
|
|
1809
|
+
*
|
|
1810
|
+
* A failure hides the balance (see `creditFailed`) instead of leaving the old
|
|
1811
|
+
* number on screen as though it were fresh — but only when the failed read is
|
|
1812
|
+
* still the newest one (`refresh` bumped `readSeq` for it, and nothing newer
|
|
1813
|
+
* has started since). An out-of-date manual failure racing a successful
|
|
1814
|
+
* probe's trailing read must not hide the fresh balance that just arrived:
|
|
1815
|
+
* `readSeq` is what decides, and `refresh` itself already clears the flag on
|
|
1816
|
+
* any newer successful write.
|
|
1817
|
+
*/
|
|
1818
|
+
const checkNow = async () => {
|
|
1819
|
+
if (refreshingRef.current) return;
|
|
1820
|
+
refreshingRef.current = true;
|
|
1821
|
+
setRefreshing(true);
|
|
1822
|
+
const seqAtStart = readSeq.current + 1;
|
|
1823
|
+
try {
|
|
1824
|
+
await refresh();
|
|
1825
|
+
} catch {
|
|
1826
|
+
if (mounted.current && readSeq.current === seqAtStart) setCreditFailed(true);
|
|
1827
|
+
} finally {
|
|
1828
|
+
refreshingRef.current = false;
|
|
1829
|
+
if (mounted.current) setRefreshing(false);
|
|
1830
|
+
}
|
|
1831
|
+
};
|
|
1653
1832
|
const probe = status?.status === "signed-in" ? status.probe : void 0;
|
|
1654
1833
|
const key = status?.status === "signed-in" ? status.probeKey : void 0;
|
|
1655
1834
|
const result = status === void 0 ? void 0 : resultFor(status, model);
|
|
@@ -1701,7 +1880,7 @@ window.__ModuleLoader__.load({
|
|
|
1701
1880
|
if (mounted.current) setBusy(false);
|
|
1702
1881
|
}
|
|
1703
1882
|
};
|
|
1704
|
-
|
|
1883
|
+
const credit = creditFailed ? void 0 : creditBadge(status, card, t);
|
|
1705
1884
|
const text = tooltipText(t, model, {
|
|
1706
1885
|
busy,
|
|
1707
1886
|
result,
|
|
@@ -1718,7 +1897,39 @@ window.__ModuleLoader__.load({
|
|
|
1718
1897
|
setTooltipVisible(false);
|
|
1719
1898
|
},
|
|
1720
1899
|
children: [
|
|
1721
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1900
|
+
credit === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1901
|
+
style: creditStyle,
|
|
1902
|
+
children: credit
|
|
1903
|
+
}),
|
|
1904
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1905
|
+
type: "button",
|
|
1906
|
+
style: {
|
|
1907
|
+
...refreshStyle,
|
|
1908
|
+
opacity: refreshing ? .6 : 1,
|
|
1909
|
+
cursor: refreshing ? "default" : "pointer"
|
|
1910
|
+
},
|
|
1911
|
+
title: t("composerCreditRefresh"),
|
|
1912
|
+
"aria-label": t("composerCreditRefresh"),
|
|
1913
|
+
"aria-busy": refreshing,
|
|
1914
|
+
disabled: refreshing,
|
|
1915
|
+
onClick: () => {
|
|
1916
|
+
checkNow();
|
|
1917
|
+
},
|
|
1918
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
1919
|
+
width: "12",
|
|
1920
|
+
height: "12",
|
|
1921
|
+
viewBox: "0 0 24 24",
|
|
1922
|
+
fill: "none",
|
|
1923
|
+
stroke: "currentColor",
|
|
1924
|
+
strokeWidth: "2",
|
|
1925
|
+
strokeLinecap: "round",
|
|
1926
|
+
strokeLinejoin: "round",
|
|
1927
|
+
"aria-hidden": "true",
|
|
1928
|
+
focusable: "false",
|
|
1929
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M20 12a8 8 0 1 1-2.34-5.66" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M20 4v4h-4" })]
|
|
1930
|
+
})
|
|
1931
|
+
}),
|
|
1932
|
+
visible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1722
1933
|
type: "button",
|
|
1723
1934
|
"aria-label": text,
|
|
1724
1935
|
"aria-describedby": showTooltip ? tooltipId : void 0,
|
|
@@ -1771,13 +1982,13 @@ window.__ModuleLoader__.load({
|
|
|
1771
1982
|
children: label
|
|
1772
1983
|
})]
|
|
1773
1984
|
}),
|
|
1774
|
-
showTooltip && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1985
|
+
visible && showTooltip && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1775
1986
|
id: tooltipId,
|
|
1776
1987
|
role: "tooltip",
|
|
1777
1988
|
style: tooltipStyle,
|
|
1778
1989
|
children: text
|
|
1779
1990
|
}),
|
|
1780
|
-
confirming && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1991
|
+
visible && confirming && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1781
1992
|
style: confirmStyle,
|
|
1782
1993
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("probeBubbleBody") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1783
1994
|
style: confirmRowStyle,
|
|
@@ -1798,7 +2009,7 @@ window.__ModuleLoader__.load({
|
|
|
1798
2009
|
})]
|
|
1799
2010
|
})]
|
|
1800
2011
|
}),
|
|
1801
|
-
note
|
|
2012
|
+
visible && note !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1802
2013
|
role: "status",
|
|
1803
2014
|
"aria-live": "polite",
|
|
1804
2015
|
style: noteStyle,
|
|
@@ -2561,7 +2772,7 @@ window.__ModuleLoader__.load({
|
|
|
2561
2772
|
};
|
|
2562
2773
|
//#endregion
|
|
2563
2774
|
//#region src/version.ts
|
|
2564
|
-
const WORKBUDDY_CONNECT_VERSION = "0.7.
|
|
2775
|
+
const WORKBUDDY_CONNECT_VERSION = "0.7.2";
|
|
2565
2776
|
//#endregion
|
|
2566
2777
|
//#region src/client/WorkBuddyConfigPage.tsx
|
|
2567
2778
|
/**
|
|
@@ -2624,8 +2835,13 @@ window.__ModuleLoader__.load({
|
|
|
2624
2835
|
creditsTotal: "Total: {total}",
|
|
2625
2836
|
creditsTotalUnlimited: "Total: Unlimited",
|
|
2626
2837
|
unlimitedQuota: "Unlimited",
|
|
2838
|
+
composerCredit: "{prefix}{total} credits",
|
|
2839
|
+
composerCreditRefresh: "Refresh credit balance",
|
|
2627
2840
|
packageEnterprise: "Enterprise quota",
|
|
2628
2841
|
cycleResetAt: "Resets {time}",
|
|
2842
|
+
expiryWarningSoon: "{total} credit expires within 24 hours ({packages} packages)",
|
|
2843
|
+
expiryWarningWeek: "{total} credit expires within 7 days ({packages} packages)",
|
|
2844
|
+
expiryExpiresAt: "Earliest: {time}",
|
|
2629
2845
|
percentRemaining: "{percent}% remaining",
|
|
2630
2846
|
percentUnknown: "Remaining share unknown",
|
|
2631
2847
|
exactRemaining: "{remain} / {size} remaining",
|
|
@@ -2743,8 +2959,13 @@ window.__ModuleLoader__.load({
|
|
|
2743
2959
|
creditsTotal: "合计:{total}",
|
|
2744
2960
|
creditsTotalUnlimited: "合计:不限额",
|
|
2745
2961
|
unlimitedQuota: "不限额",
|
|
2962
|
+
composerCredit: "{prefix}{total}(积分)",
|
|
2963
|
+
composerCreditRefresh: "刷新积分",
|
|
2746
2964
|
packageEnterprise: "企业额度",
|
|
2747
2965
|
cycleResetAt: "重置时间:{time}",
|
|
2966
|
+
expiryWarningSoon: "有 {total} 积分将在 24 小时内过期({packages} 个套餐)",
|
|
2967
|
+
expiryWarningWeek: "有 {total} 积分将在 7 天内过期({packages} 个套餐)",
|
|
2968
|
+
expiryExpiresAt: "最早到期:{time}",
|
|
2748
2969
|
percentRemaining: "剩余 {percent}%",
|
|
2749
2970
|
percentUnknown: "剩余占比未知",
|
|
2750
2971
|
exactRemaining: "剩余 {remain} / {size}",
|