@jxgame2020/dsh-token-quota 0.1.8 → 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/lib/client.js CHANGED
@@ -35,11 +35,22 @@ window.__ModuleLoader__.load({
35
35
  error: null,
36
36
  monitored: null,
37
37
  onFull: "stop",
38
+ checkUpdates: true,
39
+ upgrade: null,
40
+ upgradeDismissed: false,
41
+ checkingUpdates: false,
42
+ lastCheckResult: "idle",
38
43
  dialogOpen: false,
39
44
  fullNotice: null,
40
45
  reset: null,
41
46
  logOpen: false,
42
- log: null
47
+ log: null,
48
+ logSearch: "",
49
+ logPage: 0,
50
+ logPageSize: 15,
51
+ logClearOpen: false,
52
+ logClearBefore: "",
53
+ logClearing: false
43
54
  }),
44
55
  actions: {
45
56
  setSnapshot: (d, snapshot) => {
@@ -59,6 +70,22 @@ window.__ModuleLoader__.load({
59
70
  d.monitored = monitored;
60
71
  d.onFull = onFull;
61
72
  },
73
+ setCheckUpdates: (d, checkUpdates) => {
74
+ d.checkUpdates = checkUpdates;
75
+ },
76
+ setUpgrade: (d, upgrade) => {
77
+ if (d.upgrade === null || d.upgrade.latestVersion !== upgrade?.latestVersion) d.upgradeDismissed = false;
78
+ d.upgrade = upgrade;
79
+ },
80
+ setUpgradeDismissed: (d, dismissed) => {
81
+ d.upgradeDismissed = dismissed;
82
+ },
83
+ setCheckingUpdates: (d, checking) => {
84
+ d.checkingUpdates = checking;
85
+ },
86
+ setLastCheckResult: (d, result) => {
87
+ d.lastCheckResult = result;
88
+ },
62
89
  setDialogOpen: (d, open) => {
63
90
  d.dialogOpen = open;
64
91
  },
@@ -73,6 +100,26 @@ window.__ModuleLoader__.load({
73
100
  },
74
101
  setLog: (d, log) => {
75
102
  d.log = log;
103
+ },
104
+ setLogSearch: (d, search) => {
105
+ d.logSearch = search;
106
+ d.logPage = 0;
107
+ },
108
+ setLogPage: (d, page) => {
109
+ d.logPage = page;
110
+ },
111
+ setLogPageSize: (d, size) => {
112
+ d.logPageSize = size;
113
+ d.logPage = 0;
114
+ },
115
+ setLogClearOpen: (d, open) => {
116
+ d.logClearOpen = open;
117
+ },
118
+ setLogClearBefore: (d, before) => {
119
+ d.logClearBefore = before;
120
+ },
121
+ setLogClearing: (d, clearing) => {
122
+ d.logClearing = clearing;
76
123
  }
77
124
  }
78
125
  });
@@ -119,7 +166,7 @@ window.__ModuleLoader__.load({
119
166
  }
120
167
  //#endregion
121
168
  //#region \0dsh-css:/Users/jxgame/Desktop/works/deepseek-harness-package/dsh-token-quota/packages/token-quota/src/client/TokenQuotaPanel.module.css.mjs
122
- const css = ".NPLLIq_panel{box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);pointer-events:auto;z-index:40;border-radius:12px;flex-direction:column;width:320px;max-height:min(72vh,560px);display:flex;position:fixed;top:56px;right:12px;overflow:hidden;box-shadow:0 8px 28px #0000002e}.NPLLIq_header{border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:flex-start;gap:8px;padding:10px 12px;display:flex}.NPLLIq_header:active{cursor:grabbing}.NPLLIq_headerText{flex-direction:column;gap:2px;min-width:0;display:flex}.NPLLIq_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.NPLLIq_subtitle{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_collapse{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_collapse:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_body{padding:4px 0;overflow-y:auto}.NPLLIq_row{border-bottom:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:6px;padding:8px 12px;display:flex}.NPLLIq_rowHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.NPLLIq_rowName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:6px;font-size:12px;font-weight:500;display:inline-flex;overflow:hidden}.NPLLIq_currentBadge{color:var(--dsw-alias-state-success-primary);border:1px solid var(--dsw-alias-state-success-primary);border-radius:8px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_rowMeta{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.NPLLIq_bar{background:var(--dsw-alias-bg-layer-1);border-radius:3px;height:6px;overflow:hidden}.NPLLIq_fillIdle{background:var(--dsw-alias-brand-primary);height:100%;transition:width .2s}.NPLLIq_fillWarn{background:var(--dsw-alias-state-warn-primary);height:100%;transition:width .2s}.NPLLIq_fillOver{background:var(--dsw-alias-state-error-primary);height:100%;transition:width .2s}.NPLLIq_controls{align-items:center;gap:6px;display:flex}.NPLLIq_input{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);min-width:0;color:var(--dsw-alias-label-primary);border-radius:6px;flex:1;padding:4px 8px;font-size:11px}.NPLLIq_input::placeholder{color:var(--dsw-alias-label-secondary)}.NPLLIq_save,.NPLLIq_switch{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px;font-size:11px}.NPLLIq_save:hover,.NPLLIq_switch:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2)}.NPLLIq_switch:disabled{opacity:.5;cursor:default}.NPLLIq_notice,.NPLLIq_noticeError{color:var(--dsw-alias-label-secondary);padding:10px 12px;font-size:12px}.NPLLIq_noticeError{color:var(--dsw-alias-state-error-primary)}.NPLLIq_tab{background:var(--dsw-alias-brand-primary);border:1px solid var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay);pointer-events:auto;cursor:pointer;z-index:90;border-radius:10px;align-items:center;gap:6px;padding:9px 14px;font-size:12px;font-weight:600;display:inline-flex;position:fixed;top:56px;right:12px;box-shadow:0 6px 20px #00000040}.NPLLIq_tab:hover{filter:brightness(1.08)}.NPLLIq_tabIcon{font-size:12px;line-height:1}.NPLLIq_tabLabel{white-space:nowrap}.NPLLIq_headerActions{flex:none;align-items:center;gap:4px;display:flex}.NPLLIq_settingsBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_settingsBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_selectBtn{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border-radius:6px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_selectBtn:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_gearBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;margin-left:6px;padding:0 2px;font-size:12px;line-height:1}.NPLLIq_gearBtn:hover{color:var(--dsw-alias-label-primary)}.NPLLIq_fullNotice{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;margin:6px 12px;padding:8px 10px;font-size:12px}.NPLLIq_dialog{z-index:100;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;gap:12px;width:280px;max-height:80vh;padding:14px;display:flex;position:fixed;top:50%;left:50%;overflow-y:auto;transform:translate(-50%,-50%);box-shadow:0 8px 28px #00000040}.NPLLIq_dialogTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.NPLLIq_dialogSection{flex-direction:column;gap:6px;display:flex}.NPLLIq_dialogLabel{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500}.NPLLIq_monitorHint{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_monitorList{flex-direction:column;gap:2px;max-height:180px;display:flex;overflow-y:auto}.NPLLIq_monitorRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:2px 4px;font-size:12px;display:flex}.NPLLIq_monitorRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_monitorName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.NPLLIq_radioRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:3px 4px;font-size:12px;display:flex}.NPLLIq_radioRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_dialogActions{justify-content:flex-end;gap:6px;display:flex}.NPLLIq_dialogBtn,.NPLLIq_dialogBtnPrimary{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;border-radius:6px;padding:4px 12px;font-size:11px}.NPLLIq_dialogBtn{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.NPLLIq_dialogBtnPrimary{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay)}.NPLLIq_dialogHeader{z-index:2;background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:center;gap:8px;margin:-14px -14px 0;padding:14px 14px 8px;display:flex;position:sticky;top:-14px}.NPLLIq_dialogHeader:active{cursor:grabbing}.NPLLIq_dialogClose{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;flex:none;justify-content:center;align-items:center;font-size:18px;line-height:1;display:flex}.NPLLIq_dialogClose:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_resetRow{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.NPLLIq_resetSelect{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:6px;padding:3px 6px;font-size:12px}.NPLLIq_logTable{border-collapse:collapse;width:100%;font-size:11px}.NPLLIq_logTable th{text-align:left;color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);padding:4px 6px;font-weight:500}.NPLLIq_logTable td{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);font-variant-numeric:tabular-nums;padding:4px 6px}.NPLLIq_logDayCol{white-space:nowrap;color:var(--dsw-alias-label-secondary)}.NPLLIq_logModelCol{text-overflow:ellipsis;white-space:nowrap;max-width:160px;overflow:hidden}.NPLLIq_logUsedCol{text-align:right}.NPLLIq_logDialog{gap:0;width:380px;max-height:min(72vh,480px);padding:0}.NPLLIq_logHeader{background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;flex:none;justify-content:space-between;align-items:center;gap:8px;padding:14px 14px 8px;display:flex}.NPLLIq_logHeader:active{cursor:grabbing}.NPLLIq_logScroll{flex:1;min-height:0;padding:0 14px 14px;overflow:auto}";
169
+ const css = ".NPLLIq_panel{box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);pointer-events:auto;z-index:40;border-radius:12px;flex-direction:column;width:320px;max-height:min(72vh,560px);display:flex;position:fixed;top:56px;right:12px;overflow:hidden;box-shadow:0 8px 28px #0000002e}.NPLLIq_header{border-bottom:1px solid var(--dsw-alias-border-l1);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:flex-start;gap:8px;padding:10px 12px;display:flex}.NPLLIq_header:active{cursor:grabbing}.NPLLIq_headerText{flex-direction:column;gap:2px;min-width:0;display:flex}.NPLLIq_title{color:var(--dsw-alias-label-primary);align-items:baseline;gap:6px;font-size:13px;font-weight:600;display:flex}.NPLLIq_version{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:10px;font-weight:500}.NPLLIq_versionNew{color:var(--dsw-alias-status-warning-foreground,#b56900);background:var(--dsw-alias-status-warning-background,#fff6d7);cursor:default;border-radius:4px;padding:1px 6px}.NPLLIq_subtitle{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_collapse{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_collapse:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_body{padding:4px 0;overflow-y:auto}.NPLLIq_row{border-bottom:1px solid var(--dsw-alias-border-l1);flex-direction:column;gap:6px;padding:8px 12px;display:flex}.NPLLIq_rowHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.NPLLIq_rowName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:6px;font-size:12px;font-weight:500;display:inline-flex;overflow:hidden}.NPLLIq_currentBadge{color:var(--dsw-alias-state-success-primary);border:1px solid var(--dsw-alias-state-success-primary);border-radius:8px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_rowMeta{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.NPLLIq_bar{background:var(--dsw-alias-bg-layer-1);border-radius:3px;height:6px;overflow:hidden}.NPLLIq_fillIdle{background:var(--dsw-alias-brand-primary);height:100%;transition:width .2s}.NPLLIq_fillWarn{background:var(--dsw-alias-state-warn-primary);height:100%;transition:width .2s}.NPLLIq_fillOver{background:var(--dsw-alias-state-error-primary);height:100%;transition:width .2s}.NPLLIq_controls{align-items:center;gap:6px;display:flex}.NPLLIq_input{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);min-width:0;color:var(--dsw-alias-label-primary);border-radius:6px;flex:1;padding:4px 8px;font-size:11px}.NPLLIq_input::placeholder{color:var(--dsw-alias-label-secondary)}.NPLLIq_save,.NPLLIq_switch{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px;font-size:11px}.NPLLIq_save:hover,.NPLLIq_switch:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2)}.NPLLIq_switch:disabled{opacity:.5;cursor:default}.NPLLIq_notice,.NPLLIq_noticeError{color:var(--dsw-alias-label-secondary);padding:10px 12px;font-size:12px}.NPLLIq_noticeError{color:var(--dsw-alias-state-error-primary)}.NPLLIq_tab{background:var(--dsw-alias-brand-primary);border:1px solid var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay);pointer-events:auto;cursor:pointer;z-index:90;border-radius:10px;align-items:center;gap:6px;padding:9px 14px;font-size:12px;font-weight:600;display:inline-flex;position:fixed;top:56px;right:12px;box-shadow:0 6px 20px #00000040}.NPLLIq_tab:hover{filter:brightness(1.08)}.NPLLIq_tabIcon{font-size:12px;line-height:1}.NPLLIq_tabLabel{white-space:nowrap}.NPLLIq_headerActions{flex:none;align-items:center;gap:4px;display:flex}.NPLLIq_settingsBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;padding:2px 6px;font-size:11px}.NPLLIq_settingsBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_selectBtn{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border-radius:6px;flex:none;padding:1px 6px;font-size:10px}.NPLLIq_selectBtn:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_gearBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;margin-left:6px;padding:0 2px;font-size:12px;line-height:1}.NPLLIq_gearBtn:hover{color:var(--dsw-alias-label-primary)}.NPLLIq_fullNotice{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-state-error-primary);border-radius:8px;margin:6px 12px;padding:8px 10px;font-size:12px}.NPLLIq_upgradeBanner{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-divider-1,#0000001a);border-radius:8px;margin:6px 12px;padding:10px 30px 10px 10px;font-size:12px;position:relative}.NPLLIq_upgradeBannerText{margin-bottom:6px;font-weight:600}.NPLLIq_upgradeCommands{flex-direction:column;gap:4px;display:flex}.NPLLIq_upgradeCommandRow{align-items:center;gap:6px;display:flex}.NPLLIq_upgradeCommand{background:var(--dsw-alias-bg-layer-2,#0000000a);white-space:nowrap;border-radius:4px;flex:1;min-width:0;padding:4px 6px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:11px;overflow-x:auto}.NPLLIq_copyBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;flex:none;padding:3px 8px;font-size:11px}.NPLLIq_copyBtn:hover{background:var(--dsw-alias-bg-layer-3,#00000014)}.NPLLIq_upgradeHint{color:var(--dsw-alias-label-secondary);margin-top:6px;font-size:11px}.NPLLIq_upgradeClose{width:20px;height:20px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;font-size:16px;line-height:1;position:absolute;top:4px;right:6px}.NPLLIq_upgradeClose:hover{background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary)}.NPLLIq_checkUpdatesRow{justify-content:space-between;align-items:center;gap:12px;display:flex}.NPLLIq_checkUpdatesLabel{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:center;gap:6px;font-size:12px;display:flex}.NPLLIq_checkUpdatesLabel input{margin:0}.NPLLIq_checkBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-2,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;text-align:center;border-radius:4px;flex:none;min-width:72px;padding:4px 10px;font-size:12px}.NPLLIq_checkBtn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-3,#00000014)}.NPLLIq_checkBtn:disabled{opacity:.6;cursor:default}.NPLLIq_dialog{z-index:100;box-sizing:border-box;background:var(--dsw-alias-bg-overlay);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;gap:12px;width:280px;max-height:80vh;padding:14px;display:flex;position:fixed;top:50%;left:50%;overflow-y:auto;transform:translate(-50%,-50%);box-shadow:0 8px 28px #00000040}.NPLLIq_dialogTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.NPLLIq_dialogSection{flex-direction:column;gap:6px;display:flex}.NPLLIq_dialogLabel{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500}.NPLLIq_monitorHint{color:var(--dsw-alias-label-secondary);font-size:11px}.NPLLIq_monitorList{flex-direction:column;gap:2px;max-height:180px;display:flex;overflow-y:auto}.NPLLIq_monitorRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:2px 4px;font-size:12px;display:flex}.NPLLIq_monitorRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_monitorName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.NPLLIq_radioRow{color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:3px 4px;font-size:12px;display:flex}.NPLLIq_radioRow:hover{background:var(--dsw-alias-bg-layer-1)}.NPLLIq_dialogActions{justify-content:flex-end;gap:6px;display:flex}.NPLLIq_dialogBtn,.NPLLIq_dialogBtnPrimary{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;border-radius:6px;padding:4px 12px;font-size:11px}.NPLLIq_dialogBtn{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.NPLLIq_dialogBtnPrimary{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-overlay)}.NPLLIq_dialogHeader{z-index:2;background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;justify-content:space-between;align-items:center;gap:8px;margin:-14px -14px 0;padding:14px 14px 8px;display:flex;position:sticky;top:-14px}.NPLLIq_dialogHeader:active{cursor:grabbing}.NPLLIq_dialogClose{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;flex:none;justify-content:center;align-items:center;font-size:18px;line-height:1;display:flex}.NPLLIq_dialogClose:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1)}.NPLLIq_resetRow{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.NPLLIq_resetSelect{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:6px;padding:3px 6px;font-size:12px}.NPLLIq_logTable{border-collapse:collapse;width:100%;font-size:11px}.NPLLIq_logTable th{text-align:left;color:var(--dsw-alias-label-secondary);border-bottom:1px solid var(--dsw-alias-border-l1);padding:4px 6px;font-weight:500}.NPLLIq_logTable td{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);font-variant-numeric:tabular-nums;padding:4px 6px}.NPLLIq_logDayCol{white-space:nowrap;color:var(--dsw-alias-label-secondary)}.NPLLIq_logModelCol{text-overflow:ellipsis;white-space:nowrap;max-width:160px;overflow:hidden}.NPLLIq_logUsedCol{text-align:right}.NPLLIq_logDialog{gap:0;width:380px;max-height:min(72vh,480px);padding:0}.NPLLIq_logHeader{background:var(--dsw-alias-bg-overlay);cursor:grab;user-select:none;touch-action:none;flex:none;justify-content:space-between;align-items:center;gap:8px;padding:14px 14px 8px;display:flex}.NPLLIq_logHeader:active{cursor:grabbing}.NPLLIq_logScroll{flex:1;min-height:0;padding:0 14px 14px;overflow:auto}.NPLLIq_logToolbar{flex:1;align-items:center;gap:6px;display:flex}.NPLLIq_logSearch{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);min-width:0;color:var(--dsw-alias-label-primary);border-radius:4px;flex:1;padding:3px 6px;font-size:11px}.NPLLIq_logSearch:focus{border-color:var(--dsw-alias-accent-1,#4a9eff);outline:none}.NPLLIq_logClearBtn{border:1px solid var(--dsw-alias-state-error-border,#b400004d);color:var(--dsw-alias-state-error-primary,#c00);cursor:pointer;white-space:nowrap;background:0 0;border-radius:4px;flex:none;padding:3px 8px;font-size:11px}.NPLLIq_logClearBtn:hover{background:var(--dsw-alias-state-error-background,#ff00000f)}.NPLLIq_logPager{border-top:1px solid var(--dsw-alias-divider-1,#00000014);background:var(--dsw-alias-bg-overlay);color:var(--dsw-alias-label-secondary);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:6px 14px;font-size:11px;display:flex}.NPLLIq_logPagerInfo{white-space:nowrap}.NPLLIq_logPagerControls{align-items:center;gap:4px;display:flex}.NPLLIq_logPagerBtn{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);width:24px;height:24px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;font-size:13px;line-height:1}.NPLLIq_logPagerBtn:disabled{opacity:.4;cursor:default}.NPLLIq_logPagerPages{text-align:center;min-width:50px;color:var(--dsw-alias-label-secondary)}.NPLLIq_logPageSizeSelect{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:4px;padding:2px 4px;font-size:11px}.NPLLIq_dialogOverlay{z-index:100001;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.NPLLIq_logClearDialog{gap:0;width:320px;padding:16px}.NPLLIq_dialogBody{color:var(--dsw-alias-label-secondary);margin:6px 0 10px;font-size:12px;line-height:1.5}.NPLLIq_logClearDate{border:1px solid var(--dsw-alias-divider-1,#00000026);background:var(--dsw-alias-bg-layer-1,#0000000a);width:100%;color:var(--dsw-alias-label-primary);border-radius:6px;margin-bottom:12px;padding:6px 8px;font-size:13px}.NPLLIq_logClearDate:focus{border-color:var(--dsw-alias-accent-1,#4a9eff);outline:none}";
123
170
  const tagId = "@jxgame2020/dsh-token-quota/TokenQuotaPanel.module.css";
124
171
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
125
172
  const tag = document.createElement("style");
@@ -129,59 +176,85 @@ window.__ModuleLoader__.load({
129
176
  document.head.appendChild(tag);
130
177
  }
131
178
  var TokenQuotaPanel_module_css_default = {
132
- "fillOver": "NPLLIq_fillOver",
133
- "fillIdle": "NPLLIq_fillIdle",
134
- "monitorList": "NPLLIq_monitorList",
135
- "switch": "NPLLIq_switch",
136
- "subtitle": "NPLLIq_subtitle",
137
- "monitorName": "NPLLIq_monitorName",
138
- "currentBadge": "NPLLIq_currentBadge",
139
- "collapse": "NPLLIq_collapse",
140
- "row": "NPLLIq_row",
141
- "fillWarn": "NPLLIq_fillWarn",
142
- "rowHeader": "NPLLIq_rowHeader",
143
- "input": "NPLLIq_input",
144
- "radioRow": "NPLLIq_radioRow",
145
179
  "logHeader": "NPLLIq_logHeader",
180
+ "title": "NPLLIq_title",
181
+ "radioRow": "NPLLIq_radioRow",
146
182
  "logModelCol": "NPLLIq_logModelCol",
147
- "logDayCol": "NPLLIq_logDayCol",
183
+ "logPagerInfo": "NPLLIq_logPagerInfo",
184
+ "upgradeClose": "NPLLIq_upgradeClose",
185
+ "dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
186
+ "subtitle": "NPLLIq_subtitle",
187
+ "logPagerControls": "NPLLIq_logPagerControls",
148
188
  "dialogBtn": "NPLLIq_dialogBtn",
149
- "dialogActions": "NPLLIq_dialogActions",
189
+ "logPagerPages": "NPLLIq_logPagerPages",
190
+ "headerActions": "NPLLIq_headerActions",
191
+ "monitorHint": "NPLLIq_monitorHint",
192
+ "dialogTitle": "NPLLIq_dialogTitle",
150
193
  "logDialog": "NPLLIq_logDialog",
151
- "notice": "NPLLIq_notice",
152
- "tabLabel": "NPLLIq_tabLabel",
194
+ "header": "NPLLIq_header",
153
195
  "dialog": "NPLLIq_dialog",
154
- "logScroll": "NPLLIq_logScroll",
155
- "resetRow": "NPLLIq_resetRow",
156
- "rowMeta": "NPLLIq_rowMeta",
157
196
  "tab": "NPLLIq_tab",
158
- "monitorHint": "NPLLIq_monitorHint",
159
- "title": "NPLLIq_title",
160
- "noticeError": "NPLLIq_noticeError",
197
+ "dialogHeader": "NPLLIq_dialogHeader",
198
+ "logToolbar": "NPLLIq_logToolbar",
199
+ "dialogLabel": "NPLLIq_dialogLabel",
200
+ "logClearDate": "NPLLIq_logClearDate",
201
+ "upgradeBanner": "NPLLIq_upgradeBanner",
202
+ "bar": "NPLLIq_bar",
203
+ "row": "NPLLIq_row",
204
+ "copyBtn": "NPLLIq_copyBtn",
205
+ "dialogActions": "NPLLIq_dialogActions",
206
+ "logUsedCol": "NPLLIq_logUsedCol",
161
207
  "monitorRow": "NPLLIq_monitorRow",
162
- "dialogBtnPrimary": "NPLLIq_dialogBtnPrimary",
163
- "tabIcon": "NPLLIq_tabIcon",
164
- "rowName": "NPLLIq_rowName",
208
+ "tabLabel": "NPLLIq_tabLabel",
209
+ "monitorName": "NPLLIq_monitorName",
210
+ "logPageSizeSelect": "NPLLIq_logPageSizeSelect",
211
+ "dialogSection": "NPLLIq_dialogSection",
165
212
  "save": "NPLLIq_save",
213
+ "switch": "NPLLIq_switch",
214
+ "upgradeCommandRow": "NPLLIq_upgradeCommandRow",
215
+ "tabIcon": "NPLLIq_tabIcon",
216
+ "version": "NPLLIq_version",
217
+ "upgradeBannerText": "NPLLIq_upgradeBannerText",
218
+ "panel": "NPLLIq_panel",
219
+ "notice": "NPLLIq_notice",
220
+ "fillOver": "NPLLIq_fillOver",
221
+ "dialogOverlay": "NPLLIq_dialogOverlay",
166
222
  "fullNotice": "NPLLIq_fullNotice",
167
- "dialogClose": "NPLLIq_dialogClose",
168
- "header": "NPLLIq_header",
169
- "bar": "NPLLIq_bar",
170
- "dialogHeader": "NPLLIq_dialogHeader",
223
+ "logDayCol": "NPLLIq_logDayCol",
224
+ "rowHeader": "NPLLIq_rowHeader",
225
+ "settingsBtn": "NPLLIq_settingsBtn",
226
+ "gearBtn": "NPLLIq_gearBtn",
171
227
  "headerText": "NPLLIq_headerText",
172
- "selectBtn": "NPLLIq_selectBtn",
228
+ "collapse": "NPLLIq_collapse",
173
229
  "resetSelect": "NPLLIq_resetSelect",
230
+ "upgradeCommands": "NPLLIq_upgradeCommands",
231
+ "body": "NPLLIq_body",
232
+ "rowName": "NPLLIq_rowName",
233
+ "monitorList": "NPLLIq_monitorList",
234
+ "logScroll": "NPLLIq_logScroll",
235
+ "input": "NPLLIq_input",
236
+ "resetRow": "NPLLIq_resetRow",
237
+ "logPagerBtn": "NPLLIq_logPagerBtn",
238
+ "logClearDialog": "NPLLIq_logClearDialog",
174
239
  "logTable": "NPLLIq_logTable",
175
- "panel": "NPLLIq_panel",
240
+ "upgradeHint": "NPLLIq_upgradeHint",
241
+ "rowMeta": "NPLLIq_rowMeta",
242
+ "fillIdle": "NPLLIq_fillIdle",
243
+ "logClearBtn": "NPLLIq_logClearBtn",
244
+ "logPager": "NPLLIq_logPager",
245
+ "versionNew": "NPLLIq_versionNew",
246
+ "dialogBody": "NPLLIq_dialogBody",
247
+ "noticeError": "NPLLIq_noticeError",
248
+ "checkUpdatesRow": "NPLLIq_checkUpdatesRow",
249
+ "logSearch": "NPLLIq_logSearch",
250
+ "checkBtn": "NPLLIq_checkBtn",
251
+ "selectBtn": "NPLLIq_selectBtn",
252
+ "upgradeCommand": "NPLLIq_upgradeCommand",
253
+ "currentBadge": "NPLLIq_currentBadge",
176
254
  "controls": "NPLLIq_controls",
177
- "headerActions": "NPLLIq_headerActions",
178
- "body": "NPLLIq_body",
179
- "settingsBtn": "NPLLIq_settingsBtn",
180
- "gearBtn": "NPLLIq_gearBtn",
181
- "logUsedCol": "NPLLIq_logUsedCol",
182
- "dialogTitle": "NPLLIq_dialogTitle",
183
- "dialogSection": "NPLLIq_dialogSection",
184
- "dialogLabel": "NPLLIq_dialogLabel"
255
+ "fillWarn": "NPLLIq_fillWarn",
256
+ "dialogClose": "NPLLIq_dialogClose",
257
+ "checkUpdatesLabel": "NPLLIq_checkUpdatesLabel"
185
258
  };
186
259
  //#endregion
187
260
  //#region lib/types/client/TokenQuotaPanel.js
@@ -268,7 +341,7 @@ window.__ModuleLoader__.load({
268
341
  * @param props - composed slot props.
269
342
  * @returns the panel element tree.
270
343
  */
271
- function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored, setOnFull, setReset, useStore, actions, useSessions }) {
344
+ function TokenQuotaPanel({ t, load, setLimit, selectModel, setMonitored, setOnFull, setReset, setCheckUpdates, checkUpdatesNow, clearLogBefore, useStore, actions, useSessions }) {
272
345
  const [collapsed, setCollapsed] = (0, react.useState)(false);
273
346
  const [drafts, setDrafts] = (0, react.useState)({});
274
347
  const [editingKey, setEditingKey] = (0, react.useState)(null);
@@ -290,10 +363,21 @@ window.__ModuleLoader__.load({
290
363
  const current = useStore((s) => s.current);
291
364
  const monitored = useStore((s) => s.monitored);
292
365
  const onFull = useStore((s) => s.onFull);
366
+ const checkUpdates = useStore((s) => s.checkUpdates);
367
+ const upgrade = useStore((s) => s.upgrade);
368
+ const upgradeDismissed = useStore((s) => s.upgradeDismissed);
369
+ const checkingUpdates = useStore((s) => s.checkingUpdates);
370
+ const lastCheckResult = useStore((s) => s.lastCheckResult);
293
371
  const reset = useStore((s) => s.reset);
294
372
  const dialogOpen = useStore((s) => s.dialogOpen);
295
373
  const logOpen = useStore((s) => s.logOpen);
296
374
  const log = useStore((s) => s.log);
375
+ const logSearch = useStore((s) => s.logSearch);
376
+ const logPage = useStore((s) => s.logPage);
377
+ const logPageSize = useStore((s) => s.logPageSize);
378
+ const logClearOpen = useStore((s) => s.logClearOpen);
379
+ const logClearBefore = useStore((s) => s.logClearBefore);
380
+ const logClearing = useStore((s) => s.logClearing);
297
381
  const fullNotice = useStore((s) => s.fullNotice);
298
382
  const loading = useStore((s) => s.loading);
299
383
  const error = useStore((s) => s.error);
@@ -310,6 +394,39 @@ window.__ModuleLoader__.load({
310
394
  name: model.name
311
395
  }))).sort((a, b) => a.key.localeCompare(b.key)), [groups]);
312
396
  const isMonitoredKey = (key) => monitored === null || monitored.includes(key);
397
+ const filteredLogEntries = (0, react.useMemo)(() => {
398
+ if (log === null) return [];
399
+ const q = logSearch.trim().toLowerCase();
400
+ if (q === "") return log.entries;
401
+ return log.entries.filter((e) => e.key.toLowerCase().includes(q) || e.provider.toLowerCase().includes(q) || e.model.toLowerCase().includes(q));
402
+ }, [log, logSearch]);
403
+ const logTotalPages = Math.max(1, Math.ceil(filteredLogEntries.length / logPageSize));
404
+ const logCurrentPage = Math.min(logPage, logTotalPages - 1);
405
+ const logPageEntries = (0, react.useMemo)(() => {
406
+ const start = logCurrentPage * logPageSize;
407
+ return filteredLogEntries.slice(start, start + logPageSize);
408
+ }, [
409
+ filteredLogEntries,
410
+ logCurrentPage,
411
+ logPageSize
412
+ ]);
413
+ /** Copy text to the clipboard (clipboard API with execCommand fallback). */
414
+ const copyToClipboard = async (text) => {
415
+ try {
416
+ await navigator.clipboard.writeText(text);
417
+ } catch {
418
+ const el = document.createElement("textarea");
419
+ el.value = text;
420
+ el.style.position = "fixed";
421
+ el.style.opacity = "0";
422
+ document.body.appendChild(el);
423
+ el.select();
424
+ try {
425
+ document.execCommand("copy");
426
+ } catch {}
427
+ document.body.removeChild(el);
428
+ }
429
+ };
313
430
  (0, react.useEffect)(() => {
314
431
  if (!logOpen) return;
315
432
  let cancelled = false;
@@ -376,9 +493,21 @@ window.__ModuleLoader__.load({
376
493
  },
377
494
  children: [(0, react_jsx_runtime.jsxs)("div", {
378
495
  className: TokenQuotaPanel_module_css_default.headerText,
379
- children: [(0, react_jsx_runtime.jsx)("div", {
496
+ children: [(0, react_jsx_runtime.jsxs)("div", {
380
497
  className: TokenQuotaPanel_module_css_default.title,
381
- children: t("title")
498
+ children: [t("title"), upgrade !== null ? (0, react_jsx_runtime.jsxs)("span", {
499
+ className: `${TokenQuotaPanel_module_css_default.version} ${TokenQuotaPanel_module_css_default.versionNew}`,
500
+ title: t("upgradeAvailableHint"),
501
+ children: [
502
+ "v",
503
+ "0.1.12",
504
+ " → v",
505
+ upgrade.latestVersion
506
+ ]
507
+ }) : (0, react_jsx_runtime.jsxs)("span", {
508
+ className: TokenQuotaPanel_module_css_default.version,
509
+ children: ["v", "0.1.12"]
510
+ })]
382
511
  }), (0, react_jsx_runtime.jsx)("div", {
383
512
  className: TokenQuotaPanel_module_css_default.subtitle,
384
513
  children: t("subtitle")
@@ -430,6 +559,46 @@ window.__ModuleLoader__.load({
430
559
  role: "alert",
431
560
  children: fullNotice
432
561
  }),
562
+ upgrade !== null && !upgradeDismissed && (0, react_jsx_runtime.jsxs)("div", {
563
+ className: TokenQuotaPanel_module_css_default.upgradeBanner,
564
+ role: "alert",
565
+ children: [
566
+ (0, react_jsx_runtime.jsx)("div", {
567
+ className: TokenQuotaPanel_module_css_default.upgradeBannerText,
568
+ children: t("upgradeAvailable").replace("{version}", upgrade.latestVersion)
569
+ }),
570
+ (0, react_jsx_runtime.jsx)("div", {
571
+ className: TokenQuotaPanel_module_css_default.upgradeCommands,
572
+ children: upgrade.commands.map((cmd) => (0, react_jsx_runtime.jsxs)("div", {
573
+ className: TokenQuotaPanel_module_css_default.upgradeCommandRow,
574
+ children: [(0, react_jsx_runtime.jsx)("code", {
575
+ className: TokenQuotaPanel_module_css_default.upgradeCommand,
576
+ children: cmd
577
+ }), (0, react_jsx_runtime.jsx)("button", {
578
+ type: "button",
579
+ className: TokenQuotaPanel_module_css_default.copyBtn,
580
+ onClick: () => {
581
+ copyToClipboard(cmd);
582
+ },
583
+ children: t("copy")
584
+ })]
585
+ }, cmd))
586
+ }),
587
+ (0, react_jsx_runtime.jsx)("div", {
588
+ className: TokenQuotaPanel_module_css_default.upgradeHint,
589
+ children: t("upgradeHint")
590
+ }),
591
+ (0, react_jsx_runtime.jsx)("button", {
592
+ type: "button",
593
+ className: TokenQuotaPanel_module_css_default.upgradeClose,
594
+ onClick: () => {
595
+ actions.setUpgradeDismissed(true);
596
+ },
597
+ "aria-label": t("close"),
598
+ children: "×"
599
+ })
600
+ ]
601
+ }),
433
602
  !loading && error === null && visibleRows.length === 0 && (0, react_jsx_runtime.jsx)("div", {
434
603
  className: TokenQuotaPanel_module_css_default.notice,
435
604
  children: monitored !== null && monitored.length === 0 ? t("noMonitored") : t("waiting")
@@ -657,6 +826,28 @@ window.__ModuleLoader__.load({
657
826
  ]
658
827
  })
659
828
  ]
829
+ }),
830
+ (0, react_jsx_runtime.jsx)("div", {
831
+ className: TokenQuotaPanel_module_css_default.dialogSection,
832
+ children: (0, react_jsx_runtime.jsxs)("div", {
833
+ className: TokenQuotaPanel_module_css_default.checkUpdatesRow,
834
+ children: [(0, react_jsx_runtime.jsxs)("label", {
835
+ className: TokenQuotaPanel_module_css_default.checkUpdatesLabel,
836
+ children: [(0, react_jsx_runtime.jsx)("input", {
837
+ type: "checkbox",
838
+ checked: checkUpdates,
839
+ onChange: (event) => {
840
+ setCheckUpdates(event.target.checked);
841
+ }
842
+ }), (0, react_jsx_runtime.jsx)("span", { children: t("checkUpdatesLabel") })]
843
+ }), (0, react_jsx_runtime.jsx)("button", {
844
+ type: "button",
845
+ className: TokenQuotaPanel_module_css_default.checkBtn,
846
+ disabled: checkingUpdates,
847
+ onClick: checkUpdatesNow,
848
+ children: checkingUpdates ? t("checkingUpdates") : lastCheckResult === "up-to-date" ? t("checkUpToDate") : lastCheckResult === "error" ? t("checkFailed") : t("checkUpdatesNow")
849
+ })]
850
+ })
660
851
  })
661
852
  ]
662
853
  }),
@@ -674,22 +865,47 @@ window.__ModuleLoader__.load({
674
865
  onPointerDown: (event) => {
675
866
  beginDrag(event, logRef.current, setLogPos);
676
867
  },
677
- children: [(0, react_jsx_runtime.jsx)("div", {
678
- className: TokenQuotaPanel_module_css_default.dialogTitle,
679
- children: t("logsTitle")
680
- }), (0, react_jsx_runtime.jsx)("button", {
681
- type: "button",
682
- className: TokenQuotaPanel_module_css_default.dialogClose,
683
- title: t("close"),
684
- onClick: () => {
685
- actions.setLogOpen(false);
686
- },
687
- children: "×"
688
- })]
868
+ children: [
869
+ (0, react_jsx_runtime.jsx)("div", {
870
+ className: TokenQuotaPanel_module_css_default.dialogTitle,
871
+ children: t("logsTitle")
872
+ }),
873
+ (0, react_jsx_runtime.jsxs)("div", {
874
+ className: TokenQuotaPanel_module_css_default.logToolbar,
875
+ onPointerDown: (event) => {
876
+ event.stopPropagation();
877
+ },
878
+ children: [(0, react_jsx_runtime.jsx)("input", {
879
+ type: "search",
880
+ className: TokenQuotaPanel_module_css_default.logSearch,
881
+ placeholder: t("logSearchPlaceholder"),
882
+ value: logSearch,
883
+ onChange: (event) => {
884
+ actions.setLogSearch(event.target.value);
885
+ }
886
+ }), (0, react_jsx_runtime.jsx)("button", {
887
+ type: "button",
888
+ className: TokenQuotaPanel_module_css_default.logClearBtn,
889
+ onClick: () => {
890
+ actions.setLogClearOpen(true);
891
+ },
892
+ children: t("logClear")
893
+ })]
894
+ }),
895
+ (0, react_jsx_runtime.jsx)("button", {
896
+ type: "button",
897
+ className: TokenQuotaPanel_module_css_default.dialogClose,
898
+ title: t("close"),
899
+ onClick: () => {
900
+ actions.setLogOpen(false);
901
+ },
902
+ children: "×"
903
+ })
904
+ ]
689
905
  }),
690
- log !== null && log.entries.length === 0 && (0, react_jsx_runtime.jsx)("div", {
906
+ log !== null && filteredLogEntries.length === 0 && (0, react_jsx_runtime.jsx)("div", {
691
907
  className: TokenQuotaPanel_module_css_default.notice,
692
- children: t("logEmpty")
908
+ children: logSearch.trim() !== "" ? t("logNoMatch") : t("logEmpty")
693
909
  }),
694
910
  (0, react_jsx_runtime.jsx)("div", {
695
911
  className: TokenQuotaPanel_module_css_default.logScroll,
@@ -702,7 +918,7 @@ window.__ModuleLoader__.load({
702
918
  className: TokenQuotaPanel_module_css_default.logUsedCol,
703
919
  children: t("logUsed")
704
920
  })
705
- ] }) }), (0, react_jsx_runtime.jsx)("tbody", { children: log?.entries.map((entry) => (0, react_jsx_runtime.jsxs)("tr", { children: [
921
+ ] }) }), (0, react_jsx_runtime.jsx)("tbody", { children: logPageEntries.map((entry) => (0, react_jsx_runtime.jsxs)("tr", { children: [
706
922
  (0, react_jsx_runtime.jsx)("td", {
707
923
  className: TokenQuotaPanel_module_css_default.logDayCol,
708
924
  children: entry.day
@@ -718,8 +934,105 @@ window.__ModuleLoader__.load({
718
934
  })
719
935
  ] }, `${entry.day}/${entry.key}`)) })]
720
936
  })
937
+ }),
938
+ (0, react_jsx_runtime.jsxs)("div", {
939
+ className: TokenQuotaPanel_module_css_default.logPager,
940
+ children: [(0, react_jsx_runtime.jsx)("span", {
941
+ className: TokenQuotaPanel_module_css_default.logPagerInfo,
942
+ children: t("logPagerInfo").replace("{from}", String(logCurrentPage * logPageSize + 1)).replace("{to}", String(Math.min((logCurrentPage + 1) * logPageSize, filteredLogEntries.length))).replace("{total}", String(filteredLogEntries.length))
943
+ }), (0, react_jsx_runtime.jsxs)("div", {
944
+ className: TokenQuotaPanel_module_css_default.logPagerControls,
945
+ children: [
946
+ (0, react_jsx_runtime.jsx)("button", {
947
+ type: "button",
948
+ className: TokenQuotaPanel_module_css_default.logPagerBtn,
949
+ disabled: logCurrentPage <= 0,
950
+ onClick: () => {
951
+ actions.setLogPage(logCurrentPage - 1);
952
+ },
953
+ children: "‹"
954
+ }),
955
+ (0, react_jsx_runtime.jsxs)("span", {
956
+ className: TokenQuotaPanel_module_css_default.logPagerPages,
957
+ children: [
958
+ logCurrentPage + 1,
959
+ " / ",
960
+ logTotalPages
961
+ ]
962
+ }),
963
+ (0, react_jsx_runtime.jsx)("button", {
964
+ type: "button",
965
+ className: TokenQuotaPanel_module_css_default.logPagerBtn,
966
+ disabled: logCurrentPage >= logTotalPages - 1,
967
+ onClick: () => {
968
+ actions.setLogPage(logCurrentPage + 1);
969
+ },
970
+ children: "›"
971
+ }),
972
+ (0, react_jsx_runtime.jsx)("select", {
973
+ className: TokenQuotaPanel_module_css_default.logPageSizeSelect,
974
+ value: logPageSize,
975
+ onChange: (event) => {
976
+ actions.setLogPageSize(Number(event.target.value));
977
+ },
978
+ children: [
979
+ 10,
980
+ 15,
981
+ 20,
982
+ 50,
983
+ 100
984
+ ].map((size) => (0, react_jsx_runtime.jsxs)("option", {
985
+ value: size,
986
+ children: [size, t("logPerPage")]
987
+ }, size))
988
+ })
989
+ ]
990
+ })]
721
991
  })
722
992
  ]
993
+ }),
994
+ logClearOpen && (0, react_jsx_runtime.jsx)("div", {
995
+ className: TokenQuotaPanel_module_css_default.dialogOverlay,
996
+ children: (0, react_jsx_runtime.jsxs)("div", {
997
+ className: `${TokenQuotaPanel_module_css_default.dialog} ${TokenQuotaPanel_module_css_default.logClearDialog}`,
998
+ children: [
999
+ (0, react_jsx_runtime.jsx)("div", {
1000
+ className: TokenQuotaPanel_module_css_default.dialogTitle,
1001
+ children: t("logClearTitle")
1002
+ }),
1003
+ (0, react_jsx_runtime.jsx)("div", {
1004
+ className: TokenQuotaPanel_module_css_default.dialogBody,
1005
+ children: t("logClearHint")
1006
+ }),
1007
+ (0, react_jsx_runtime.jsx)("input", {
1008
+ type: "date",
1009
+ className: TokenQuotaPanel_module_css_default.logClearDate,
1010
+ value: logClearBefore,
1011
+ onChange: (event) => {
1012
+ actions.setLogClearBefore(event.target.value);
1013
+ }
1014
+ }),
1015
+ (0, react_jsx_runtime.jsxs)("div", {
1016
+ className: TokenQuotaPanel_module_css_default.dialogActions,
1017
+ children: [(0, react_jsx_runtime.jsx)("button", {
1018
+ type: "button",
1019
+ className: TokenQuotaPanel_module_css_default.checkBtn,
1020
+ disabled: logClearBefore === "" || logClearing,
1021
+ onClick: () => {
1022
+ clearLogBefore(logClearBefore);
1023
+ },
1024
+ children: logClearing ? t("logClearing") : t("logClearConfirm")
1025
+ }), (0, react_jsx_runtime.jsx)("button", {
1026
+ type: "button",
1027
+ className: TokenQuotaPanel_module_css_default.checkBtn,
1028
+ onClick: () => {
1029
+ actions.setLogClearOpen(false);
1030
+ },
1031
+ children: t("logClearCancel")
1032
+ })]
1033
+ })
1034
+ ]
1035
+ })
723
1036
  })
724
1037
  ]
725
1038
  });
@@ -769,13 +1082,32 @@ window.__ModuleLoader__.load({
769
1082
  logs: "日志",
770
1083
  logsTitle: "用量日志",
771
1084
  logEmpty: "暂无记录",
1085
+ logNoMatch: "无匹配记录",
1086
+ logSearchPlaceholder: "搜索模型…",
1087
+ logClear: "清除",
1088
+ logClearTitle: "清除历史日志",
1089
+ logClearHint: "将删除所选日期之前的所有记录(不含当日)",
1090
+ logClearConfirm: "确认清除",
1091
+ logClearCancel: "取消",
1092
+ logClearing: "清除中…",
1093
+ logPagerInfo: "第 {from}-{to} 条 / 共 {total} 条",
1094
+ logPerPage: "条/页",
772
1095
  logDay: "日期",
773
1096
  logModel: "模型",
774
1097
  logUsed: "用量",
775
1098
  resetLabel: "每日重置时间",
776
1099
  resetHint: "选择时区与时间,到点自动清零当日计数",
777
1100
  resetOffset: "时区",
778
- resetTime: "时间"
1101
+ resetTime: "时间",
1102
+ upgradeAvailableHint: "有新版本可用",
1103
+ upgradeAvailable: "发现新版本 v{version},请在终端执行以下命令升级:",
1104
+ copy: "复制",
1105
+ upgradeHint: "升级后请重启 dsh web 并刷新浏览器页面",
1106
+ checkUpdatesLabel: "自动检查更新",
1107
+ checkUpdatesNow: "立即检查",
1108
+ checkingUpdates: "检查中…",
1109
+ checkUpToDate: "已是最新",
1110
+ checkFailed: "检查失败"
779
1111
  };
780
1112
  /** English copy. */
781
1113
  const en = {
@@ -814,13 +1146,32 @@ window.__ModuleLoader__.load({
814
1146
  logs: "Logs",
815
1147
  logsTitle: "Usage Log",
816
1148
  logEmpty: "No records",
1149
+ logNoMatch: "No matching records",
1150
+ logSearchPlaceholder: "Search model…",
1151
+ logClear: "Clear",
1152
+ logClearTitle: "Clear historical log",
1153
+ logClearHint: "This deletes all records before the selected date (the date itself is kept).",
1154
+ logClearConfirm: "Confirm",
1155
+ logClearCancel: "Cancel",
1156
+ logClearing: "Clearing…",
1157
+ logPagerInfo: "{from}-{to} of {total}",
1158
+ logPerPage: "/page",
817
1159
  logDay: "Day",
818
1160
  logModel: "Model",
819
1161
  logUsed: "Used",
820
1162
  resetLabel: "Daily reset",
821
1163
  resetHint: "Pick a timezone and time; counters reset there",
822
1164
  resetOffset: "Timezone",
823
- resetTime: "Time"
1165
+ resetTime: "Time",
1166
+ upgradeAvailableHint: "A new version is available",
1167
+ upgradeAvailable: "A new version v{version} is available. Run one of the following commands in your terminal to upgrade:",
1168
+ copy: "Copy",
1169
+ upgradeHint: "After upgrading, restart dsh web and refresh the browser",
1170
+ checkUpdatesLabel: "Check for updates automatically",
1171
+ checkUpdatesNow: "Check now",
1172
+ checkingUpdates: "Checking…",
1173
+ checkUpToDate: "Up to date",
1174
+ checkFailed: "Check failed"
824
1175
  };
825
1176
  //#endregion
826
1177
  //#region lib/types/client/index.js
@@ -957,6 +1308,7 @@ window.__ModuleLoader__.load({
957
1308
  lastOnFull = rawOnFull === "switchPriority" ? "switchAll" : rawOnFull;
958
1309
  lastReset = doc?.reset !== void 0 && doc.reset !== null && typeof doc.reset === "object" && typeof doc.reset.offsetHours === "number" ? doc.reset : null;
959
1310
  bound?.setSettings(lastMonitored, lastOnFull);
1311
+ bound?.setCheckUpdates(doc?.checkUpdates ?? true);
960
1312
  bound?.setReset(lastReset);
961
1313
  fetch("/token-quota", { headers: { accept: "application/json" } }).then((response) => {
962
1314
  if (!response.ok) {
@@ -969,6 +1321,7 @@ window.__ModuleLoader__.load({
969
1321
  }).then((snapshot) => {
970
1322
  if (snapshot === void 0) return;
971
1323
  bound?.setSnapshot(snapshot);
1324
+ bound?.setUpgrade(snapshot.upgrade ?? null);
972
1325
  actOnFull(snapshot);
973
1326
  });
974
1327
  if (pullCount % 2 === 0) refreshCurrent();
@@ -1016,6 +1369,37 @@ window.__ModuleLoader__.load({
1016
1369
  bound?.setSettings(lastMonitored, lastOnFull);
1017
1370
  scope.set("onFull", action);
1018
1371
  };
1372
+ const setCheckUpdates = (enabled) => {
1373
+ bound?.setCheckUpdates(enabled);
1374
+ scope.set("checkUpdates", enabled);
1375
+ };
1376
+ /** Ask the Host to check the registry right now, then refresh the snapshot. */
1377
+ const checkUpdatesNow = () => {
1378
+ bound?.setCheckingUpdates(true);
1379
+ bound?.setLastCheckResult("idle");
1380
+ fetch("/token-quota/check-updates", { method: "POST" }).then((response) => {
1381
+ if (!response.ok) {
1382
+ bound?.setError(`check-updates route: ${String(response.status)}`);
1383
+ bound?.setLastCheckResult("error");
1384
+ return;
1385
+ }
1386
+ return response.json();
1387
+ }, () => {
1388
+ bound?.setError("update check failed");
1389
+ bound?.setLastCheckResult("error");
1390
+ }).then((snapshot) => {
1391
+ if (snapshot !== void 0) {
1392
+ bound?.setSnapshot(snapshot);
1393
+ bound?.setUpgrade(snapshot.upgrade ?? null);
1394
+ actOnFull(snapshot);
1395
+ if (snapshot.upgrade === null) bound?.setLastCheckResult("up-to-date");
1396
+ }
1397
+ bound?.setCheckingUpdates(false);
1398
+ setTimeout(() => {
1399
+ bound?.setLastCheckResult("idle");
1400
+ }, 2500);
1401
+ });
1402
+ };
1019
1403
  const setReset = (reset) => {
1020
1404
  lastReset = reset;
1021
1405
  bound?.setReset(reset);
@@ -1037,6 +1421,27 @@ window.__ModuleLoader__.load({
1037
1421
  bound?.setError("model switch failed");
1038
1422
  });
1039
1423
  };
1424
+ /** Ask the Host to clear log entries before a given date, then refresh. */
1425
+ const clearLogBefore = (before) => {
1426
+ bound?.setLogClearing(true);
1427
+ fetch("/token-quota/clear-log", {
1428
+ method: "POST",
1429
+ headers: { "content-type": "application/json" },
1430
+ body: JSON.stringify({ before })
1431
+ }).then((response) => {
1432
+ if (!response.ok) {
1433
+ bound?.setError(`clear-log route: ${String(response.status)}`);
1434
+ return;
1435
+ }
1436
+ return response.json();
1437
+ }, () => {
1438
+ bound?.setError("clear log failed");
1439
+ }).then((log) => {
1440
+ if (log !== void 0) bound?.setLog(log);
1441
+ bound?.setLogClearing(false);
1442
+ bound?.setLogClearOpen(false);
1443
+ });
1444
+ };
1040
1445
  const injected = (actions) => {
1041
1446
  bound = actions;
1042
1447
  return {
@@ -1045,7 +1450,10 @@ window.__ModuleLoader__.load({
1045
1450
  selectModel,
1046
1451
  setMonitored,
1047
1452
  setOnFull,
1048
- setReset
1453
+ setReset,
1454
+ setCheckUpdates,
1455
+ checkUpdatesNow,
1456
+ clearLogBefore
1049
1457
  };
1050
1458
  };
1051
1459
  ctx.slots.inject("shell.overlay", () => ctx.slots.register({