mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-10-05 17:35:33 -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:
@@ -185,6 +185,9 @@
|
||||
<div class="context-menu-item" data-action="check-model-updates">
|
||||
<i class="fas fa-sync-alt"></i> <span>{{ t('globalContextMenu.checkModelUpdates.label') }}</span>
|
||||
</div>
|
||||
<div class="context-menu-item" data-action="price-alerts">
|
||||
<i class="fas fa-tags"></i> <span id="globalPriceAlertsLabel">{{ t('globalContextMenu.priceAlerts.label') }}</span>
|
||||
</div>
|
||||
<div class="context-menu-item" data-action="fetch-missing-licenses">
|
||||
<i class="fas fa-shield-alt"></i> <span>{{ t('globalContextMenu.fetchMissingLicenses.label') }}</span>
|
||||
</div>
|
||||
|
||||
@@ -122,6 +122,9 @@
|
||||
<div id="checkUpdatesMenuItem" class="dropdown-item" data-action="check-updates" title="{{ t('loras.controls.updates.checkTooltip') }}">
|
||||
<i class="fas fa-sync-alt"></i> <span>{{ t('loras.controls.updates.check') }}</span>
|
||||
</div>
|
||||
<div id="priceAlertsMenuItem" class="dropdown-item" data-action="price-alerts" title="{{ t('loras.controls.updates.priceAlertsTooltip') }}">
|
||||
<i class="fas fa-tags"></i> <span>{{ t('loras.controls.updates.priceAlerts') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
<span>{{ t('update.tabs.messages') }}</span>
|
||||
<span class="notification-tab-badge" id="bannerTabBadge"></span>
|
||||
</button>
|
||||
<button type="button" class="notification-tab" id="priceAlertsTab" role="tab" aria-selected="false" aria-controls="priceAlertsPanel" tabindex="-1" data-notification-tab="priceAlerts">
|
||||
<span>{{ t('update.tabs.priceAlerts') }}</span>
|
||||
<span class="notification-tab-badge" id="priceAlertsTabBadge"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="notification-panels">
|
||||
<div class="notification-panel active" id="updatesPanel" role="tabpanel" aria-labelledby="updatesTab" aria-hidden="false" tabindex="0" data-notification-panel="updates">
|
||||
@@ -94,6 +98,34 @@
|
||||
<ul class="banner-history-list" id="bannerHistoryList"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="notification-panel" id="priceAlertsPanel" role="tabpanel" aria-labelledby="priceAlertsTab" aria-hidden="true" tabindex="-1" data-notification-panel="priceAlerts">
|
||||
<div class="price-alerts">
|
||||
<!-- Shown while price tracking is off: the panel still lists
|
||||
versions that became free, but says why prices are missing. -->
|
||||
<div class="price-alerts-disabled hidden" id="priceAlertsDisabled">
|
||||
<p class="price-alerts-disabled-text">{{ t('update.priceAlerts.disabled') }}</p>
|
||||
<button type="button" class="price-alerts-settings-btn" id="priceAlertsSettingsBtn">
|
||||
<i class="fas fa-sliders-h"></i> {{ t('update.priceAlerts.openSettings') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="price-alerts-toolbar">
|
||||
<div class="price-alerts-segments" role="tablist" aria-label="{{ t('update.priceAlerts.segmentsLabel') }}">
|
||||
<button type="button" class="price-alerts-segment active" data-price-alert-segment="below_threshold" role="tab" aria-selected="true">
|
||||
{{ t('update.priceAlerts.segments.belowThreshold') }}
|
||||
</button>
|
||||
<button type="button" class="price-alerts-segment" data-price-alert-segment="became_free" role="tab" aria-selected="false">
|
||||
{{ t('update.priceAlerts.segments.becameFree') }}
|
||||
</button>
|
||||
</div>
|
||||
<span class="price-alerts-threshold" id="priceAlertsThreshold"></span>
|
||||
</div>
|
||||
|
||||
<p class="price-alerts-note hidden" id="priceAlertsStale"></p>
|
||||
<p class="price-alerts-empty" id="priceAlertsEmpty">{{ t('update.priceAlerts.empty') }}</p>
|
||||
<ul class="price-alerts-list" id="priceAlertsList"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user