mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 21:03:01 +00:00
feat(plugins): add sorting to installed plugins section
Add A-Z, Z-A, and Enabled First sort options for installed plugins with localStorage persistence. Both installed and store sections now default to A-Z sorting. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -897,6 +897,9 @@ window.currentPluginConfig = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Installed plugins sort state
|
||||
let installedSort = localStorage.getItem('installedSort') || 'a-z';
|
||||
|
||||
// Shared on-demand status store (mirrors Alpine store when available)
|
||||
window.__onDemandStore = window.__onDemandStore || {
|
||||
loading: true,
|
||||
@@ -1010,7 +1013,7 @@ window.initPluginsPage = function() {
|
||||
// If we fetched data before the DOM existed, render it now
|
||||
if (window.__pendingInstalledPlugins) {
|
||||
console.log('[RENDER] Applying pending installed plugins data');
|
||||
renderInstalledPlugins(window.__pendingInstalledPlugins);
|
||||
sortAndRenderInstalledPlugins(window.__pendingInstalledPlugins);
|
||||
window.__pendingInstalledPlugins = null;
|
||||
}
|
||||
if (window.__pendingStorePlugins) {
|
||||
@@ -1266,7 +1269,7 @@ function loadInstalledPlugins(forceRefresh = false) {
|
||||
}));
|
||||
pluginLog('[CACHE] Dispatched pluginsUpdated event from cache');
|
||||
// Still render to ensure UI is updated
|
||||
renderInstalledPlugins(pluginLoadCache.data);
|
||||
sortAndRenderInstalledPlugins(pluginLoadCache.data);
|
||||
return Promise.resolve(pluginLoadCache.data);
|
||||
}
|
||||
|
||||
@@ -1325,7 +1328,7 @@ function loadInstalledPlugins(forceRefresh = false) {
|
||||
});
|
||||
}
|
||||
|
||||
renderInstalledPlugins(installedPlugins);
|
||||
sortAndRenderInstalledPlugins(installedPlugins);
|
||||
|
||||
// Update count
|
||||
const countEl = document.getElementById('installed-count');
|
||||
@@ -1366,6 +1369,24 @@ function refreshInstalledPlugins() {
|
||||
window.pluginManager.loadInstalledPlugins = loadInstalledPlugins;
|
||||
// Note: searchPluginStore will be exposed after its definition (see below)
|
||||
|
||||
function sortAndRenderInstalledPlugins(plugins) {
|
||||
const sorted = [...plugins].sort((a, b) => {
|
||||
const nameA = (a.name || a.id || '').toLowerCase();
|
||||
const nameB = (b.name || b.id || '').toLowerCase();
|
||||
switch (installedSort) {
|
||||
case 'z-a':
|
||||
return nameB.localeCompare(nameA);
|
||||
case 'enabled':
|
||||
if (a.enabled !== b.enabled) return a.enabled ? -1 : 1;
|
||||
return nameA.localeCompare(nameB);
|
||||
case 'a-z':
|
||||
default:
|
||||
return nameA.localeCompare(nameB);
|
||||
}
|
||||
});
|
||||
renderInstalledPlugins(sorted);
|
||||
}
|
||||
|
||||
function renderInstalledPlugins(plugins) {
|
||||
const container = document.getElementById('installed-plugins-grid');
|
||||
if (!container) {
|
||||
@@ -5085,7 +5106,7 @@ function handleUninstallSuccess(pluginId) {
|
||||
if (typeof installedPlugins !== 'undefined') {
|
||||
installedPlugins = updatedPlugins;
|
||||
}
|
||||
renderInstalledPlugins(updatedPlugins);
|
||||
sortAndRenderInstalledPlugins(updatedPlugins);
|
||||
showNotification(`Plugin uninstalled successfully`, 'success');
|
||||
|
||||
// Also refresh from server to ensure consistency
|
||||
@@ -5127,20 +5148,16 @@ function restartDisplay() {
|
||||
// --- Store Filter/Sort Functions ---
|
||||
|
||||
function setupStoreFilterListeners() {
|
||||
console.log('[FILTER SETUP] setupStoreFilterListeners() called');
|
||||
// Sort dropdown
|
||||
const sortSelect = document.getElementById('store-sort');
|
||||
console.log('[FILTER SETUP] store-sort element:', !!sortSelect, 'listenerSetup:', sortSelect?._listenerSetup);
|
||||
if (sortSelect && !sortSelect._listenerSetup) {
|
||||
sortSelect._listenerSetup = true;
|
||||
sortSelect.value = storeFilterState.sort;
|
||||
sortSelect.addEventListener('change', () => {
|
||||
console.log('[FILTER] Sort changed to:', sortSelect.value, 'cache:', !!pluginStoreCache);
|
||||
storeFilterState.sort = sortSelect.value;
|
||||
storeFilterState.persist();
|
||||
applyStoreFiltersAndSort();
|
||||
});
|
||||
console.log('[FILTER SETUP] Sort listener attached');
|
||||
}
|
||||
|
||||
// Verified filter toggle
|
||||
@@ -5197,11 +5214,9 @@ function setupStoreFilterListeners() {
|
||||
// Tag pills (event delegation on container)
|
||||
// Category pills (event delegation on container)
|
||||
const catsPills = document.getElementById('filter-categories-pills');
|
||||
console.log('[FILTER SETUP] filter-categories-pills element:', catsPills, 'listenerSetup:', catsPills?._listenerSetup);
|
||||
if (catsPills && !catsPills._listenerSetup) {
|
||||
catsPills._listenerSetup = true;
|
||||
catsPills.addEventListener('click', (e) => {
|
||||
console.log('[FILTER] Category pill click, target:', e.target, 'closest:', e.target.closest('.category-filter-pill'));
|
||||
const pill = e.target.closest('.category-filter-pill');
|
||||
if (!pill) return;
|
||||
const cat = pill.dataset.category;
|
||||
@@ -5213,10 +5228,8 @@ function setupStoreFilterListeners() {
|
||||
storeFilterState.filterCategories.push(cat);
|
||||
pill.dataset.active = 'true';
|
||||
}
|
||||
console.log('[FILTER] Categories now:', storeFilterState.filterCategories, 'cache size:', pluginStoreCache?.length);
|
||||
applyStoreFiltersAndSort();
|
||||
});
|
||||
console.log('[FILTER SETUP] Category pill listener attached');
|
||||
}
|
||||
|
||||
// Clear filters button
|
||||
@@ -5248,11 +5261,25 @@ function setupStoreFilterListeners() {
|
||||
applyStoreFiltersAndSort();
|
||||
});
|
||||
}
|
||||
|
||||
// Installed plugins sort dropdown
|
||||
const installedSortSelect = document.getElementById('installed-sort');
|
||||
if (installedSortSelect && !installedSortSelect._listenerSetup) {
|
||||
installedSortSelect._listenerSetup = true;
|
||||
installedSortSelect.value = installedSort;
|
||||
installedSortSelect.addEventListener('change', () => {
|
||||
installedSort = installedSortSelect.value;
|
||||
localStorage.setItem('installedSort', installedSort);
|
||||
const plugins = window.installedPlugins || [];
|
||||
if (plugins.length > 0) {
|
||||
sortAndRenderInstalledPlugins(plugins);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function applyStoreFiltersAndSort() {
|
||||
console.log('[FILTER] applyStoreFiltersAndSort called, cache:', pluginStoreCache?.length, 'state:', JSON.stringify(storeFilterState));
|
||||
if (!pluginStoreCache) { console.log('[FILTER] No cache, returning'); return; }
|
||||
if (!pluginStoreCache) return;
|
||||
|
||||
let plugins = [...pluginStoreCache];
|
||||
const installedIds = new Set(
|
||||
|
||||
@@ -1375,7 +1375,7 @@
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
|
||||
<!-- Custom v3 styles -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='v3/app.css') }}?v=20260216a">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='v3/app.css') }}?v=20260216b">
|
||||
</head>
|
||||
<body x-data="app()" class="bg-gray-50 min-h-screen">
|
||||
<!-- Header -->
|
||||
@@ -5013,7 +5013,7 @@
|
||||
<script src="{{ url_for('static', filename='v3/js/widgets/plugin-loader.js') }}" defer></script>
|
||||
|
||||
<!-- Legacy plugins_manager.js (for backward compatibility during migration) -->
|
||||
<script src="{{ url_for('static', filename='v3/plugins_manager.js') }}?v=20260216a" defer></script>
|
||||
<script src="{{ url_for('static', filename='v3/plugins_manager.js') }}?v=20260216b" defer></script>
|
||||
|
||||
<!-- Custom feeds table helper functions -->
|
||||
<script>
|
||||
|
||||
@@ -28,6 +28,16 @@
|
||||
<h3 class="text-lg font-bold text-gray-900">Installed Plugins</h3>
|
||||
<span id="installed-count" class="text-sm text-gray-500 font-medium">0 installed</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<label for="installed-sort" class="text-sm font-medium text-gray-700 whitespace-nowrap">
|
||||
<i class="fas fa-sort mr-1"></i>Sort:
|
||||
</label>
|
||||
<select id="installed-sort" class="text-sm px-3 py-1.5 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500">
|
||||
<option value="a-z">A → Z</option>
|
||||
<option value="z-a">Z → A</option>
|
||||
<option value="enabled">Enabled First</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div id="installed-plugins-content" class="block">
|
||||
<div id="installed-plugins-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-6">
|
||||
|
||||
Reference in New Issue
Block a user