feat: Add filter persistence with settings integration (#78)
* feat: Add settings modal with GitHub PAT and filter toggle - Add GeneralSettingsModal with General and GitHub tabs - Create GitHub PAT input field that saves to .env as GITHUB_TOKEN - Add animated toggle component for SAVE_FILTER setting - Create API endpoints for settings management - Add Input and Toggle UI components - Implement smooth animations for toggle interactions - Add proper error handling and user feedback * feat: Add filter persistence with settings integration - Add filter persistence system that saves user filter preferences to .env - Create FILTERS variable in .env to store complete filter state as JSON - Add SAVE_FILTER toggle in settings to enable/disable persistence - Implement auto-save functionality with 500ms debounce - Add loading states and visual feedback for filter restoration - Create API endpoints for managing saved filters - Add filter management UI in settings modal - Support for search query, type filters, sort order, and updatable status - Seamless integration across all script tabs (Available, Downloaded, Installed) - Auto-clear saved filters when persistence is disabled
This commit is contained in:
committed by
GitHub
parent
92f78c7008
commit
5eaafbde48
@@ -26,6 +26,8 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
|
||||
sortBy: 'name',
|
||||
sortOrder: 'asc',
|
||||
});
|
||||
const [saveFiltersEnabled, setSaveFiltersEnabled] = useState(false);
|
||||
const [isLoadingFilters, setIsLoadingFilters] = useState(true);
|
||||
const gridRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { data: scriptCardsData, isLoading: githubLoading, error: githubError, refetch } = api.scripts.getScriptCardsWithCategories.useQuery();
|
||||
@@ -35,6 +37,62 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
|
||||
{ enabled: !!selectedSlug }
|
||||
);
|
||||
|
||||
// Load SAVE_FILTER setting and saved filters on component mount
|
||||
useEffect(() => {
|
||||
const loadSettings = async () => {
|
||||
try {
|
||||
// Load SAVE_FILTER setting
|
||||
const saveFilterResponse = await fetch('/api/settings/save-filter');
|
||||
let saveFilterEnabled = false;
|
||||
if (saveFilterResponse.ok) {
|
||||
const saveFilterData = await saveFilterResponse.json();
|
||||
saveFilterEnabled = saveFilterData.enabled ?? false;
|
||||
setSaveFiltersEnabled(saveFilterEnabled);
|
||||
}
|
||||
|
||||
// Load saved filters if SAVE_FILTER is enabled
|
||||
if (saveFilterEnabled) {
|
||||
const filtersResponse = await fetch('/api/settings/filters');
|
||||
if (filtersResponse.ok) {
|
||||
const filtersData = await filtersResponse.json();
|
||||
if (filtersData.filters) {
|
||||
setFilters(filtersData.filters as FilterState);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading settings:', error);
|
||||
} finally {
|
||||
setIsLoadingFilters(false);
|
||||
}
|
||||
};
|
||||
|
||||
void loadSettings();
|
||||
}, []);
|
||||
|
||||
// Save filters when they change (if SAVE_FILTER is enabled)
|
||||
useEffect(() => {
|
||||
if (!saveFiltersEnabled || isLoadingFilters) return;
|
||||
|
||||
const saveFilters = async () => {
|
||||
try {
|
||||
await fetch('/api/settings/filters', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ filters }),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error saving filters:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Debounce the save operation
|
||||
const timeoutId = setTimeout(() => void saveFilters(), 500);
|
||||
return () => clearTimeout(timeoutId);
|
||||
}, [filters, saveFiltersEnabled, isLoadingFilters]);
|
||||
|
||||
// Extract categories from metadata
|
||||
const categories = React.useMemo((): string[] => {
|
||||
if (!scriptCardsData?.success || !scriptCardsData.metadata?.categories) return [];
|
||||
@@ -337,6 +395,8 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
|
||||
totalScripts={scriptsWithStatus.length}
|
||||
filteredCount={filteredScripts.length}
|
||||
updatableCount={filterCounts.updatableCount}
|
||||
saveFiltersEnabled={saveFiltersEnabled}
|
||||
isLoadingFilters={isLoadingFilters}
|
||||
/>
|
||||
|
||||
{/* Legacy Search Bar (keeping for backward compatibility, but hidden) */}
|
||||
|
||||
Reference in New Issue
Block a user