mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-10-06 01:45:31 -03:00
feat(update): add a Buzz price alerts panel to the notification bell
P5a of docs/plans/paid-model-price-tracking.md: one surface that answers "what got cheaper / became free", without a permanent button (the grid filter was dropped by owner decision, so the panel carries the actions itself). - price_alert_since records when an alert started, so the panel can say "dropped 3 d ago" and count what is new since the user last looked; it is set on the first sight of an already-cheap version, preserved while the alert stands, and cleared when the price rises back above the threshold - get_price_alerts() compares the threshold at read time (editing it takes effect immediately, no refresh needed) and returns both kinds in one list; model_type=None covers every type, which the shared update DB makes a single query. "became free" needs no price data, so it is reported even while price tracking is off - GET /api/lm/price-alerts, registered once in MiscRoutes rather than per model type, decorating rows best-effort with the local model name and file path from the scanner indexes (a cold cache just omits them) - a third tab in the notification bell: segments for under-threshold and became-free, the three states (tracking off / nothing matching / stale), and per-row actions (CivitAI always, Open when the model is local) - two non-permanent entry points share one helper: the controls-bar updates dropdown and the global context menu, whose label carries the unread count - unread state stays client-side (localStorage watermark); the count is fetched once on init and only when price tracking is enabled - the per-type frontend client method is removed as dead code; the per-type backend route stays for the companion extension
This commit is contained in:
@@ -98,7 +98,9 @@ export function getApiEndpoints(modelType) {
|
||||
modelUpdateVersions: `/api/lm/${modelType}/updates/versions`,
|
||||
ignoreModelUpdate: `/api/lm/${modelType}/updates/ignore`,
|
||||
ignoreVersionUpdate: `/api/lm/${modelType}/updates/ignore-version`,
|
||||
priceAlerts: `/api/lm/${modelType}/updates/price-alerts`,
|
||||
|
||||
// Price alerts are app-wide (all model types in one query), so they are
|
||||
// not part of this per-type endpoint map; see UpdateService.js.
|
||||
|
||||
// Preview management
|
||||
replacePreview: `/api/lm/${modelType}/replace-preview`,
|
||||
|
||||
@@ -1086,33 +1086,6 @@ export class BaseModelApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versions whose stored price currently crosses the alert threshold.
|
||||
* Backed by the persisted alert state, so it matches the version badges.
|
||||
* @param {{limit?: number}} [options]
|
||||
* @returns {Promise<{alerts: Array, thresholdBuzz: number, enabled: boolean}>}
|
||||
*/
|
||||
async getPriceAlerts({ limit = 200 } = {}) {
|
||||
const endpoint = this.apiConfig?.endpoints?.priceAlerts;
|
||||
if (!endpoint) {
|
||||
return { alerts: [], thresholdBuzz: 0, enabled: false };
|
||||
}
|
||||
|
||||
const response = await fetch(`${endpoint}?limit=${encodeURIComponent(limit)}`, {
|
||||
method: 'GET'
|
||||
});
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
if (!response.ok || payload?.success !== true) {
|
||||
throw new Error(payload?.error || response.statusText || 'Failed to load price alerts');
|
||||
}
|
||||
|
||||
return {
|
||||
alerts: Array.isArray(payload.alerts) ? payload.alerts : [],
|
||||
thresholdBuzz: payload.thresholdBuzz ?? 0,
|
||||
enabled: payload.enabled === true
|
||||
};
|
||||
}
|
||||
|
||||
async refreshUpdatesForModels(modelIds, { force = false } = {}) {
|
||||
if (!Array.isArray(modelIds) || modelIds.length === 0) {
|
||||
throw new Error('No model IDs provided');
|
||||
|
||||
Reference in New Issue
Block a user