/** * Workflows page functionality */ import { createChoices, getChoicesValues, type Choices } from "../choices"; import { FuzzySearch, type SearchItem } from "../search"; import { fetchData, debounce, escapeHtml, getGitHubUrl, getActionButtonsHtml, setupActionHandlers, getLastUpdatedHtml, } from "../utils"; import { setupModal, openFileModal } from "../modal"; interface Workflow extends SearchItem { id: string; path: string; triggers: string[]; tags: string[]; lastUpdated?: string | null; } interface WorkflowsData { items: Workflow[]; filters: { triggers: string[]; tags: string[]; }; } type SortOption = "title" | "lastUpdated"; const resourceType = "workflow"; let allItems: Workflow[] = []; let search = new FuzzySearch(); let triggerSelect: Choices; let tagSelect: Choices; let currentFilters = { triggers: [] as string[], tags: [] as string[], }; let currentSort: SortOption = "title"; function sortItems(items: Workflow[]): Workflow[] { return [...items].sort((a, b) => { if (currentSort === "lastUpdated") { const dateA = a.lastUpdated ? new Date(a.lastUpdated).getTime() : 0; const dateB = b.lastUpdated ? new Date(b.lastUpdated).getTime() : 0; return dateB - dateA; } return a.title.localeCompare(b.title); }); } function applyFiltersAndRender(): void { const searchInput = document.getElementById( "search-input" ) as HTMLInputElement; const countEl = document.getElementById("results-count"); const query = searchInput?.value || ""; let results = query ? search.search(query) : [...allItems]; if (currentFilters.triggers.length > 0) { results = results.filter((item) => item.triggers.some((t) => currentFilters.triggers.includes(t)) ); } if (currentFilters.tags.length > 0) { results = results.filter((item) => item.tags.some((t) => currentFilters.tags.includes(t)) ); } results = sortItems(results); renderItems(results, query); const activeFilters: string[] = []; if (currentFilters.triggers.length > 0) activeFilters.push( `${currentFilters.triggers.length} trigger${ currentFilters.triggers.length > 1 ? "s" : "" }` ); if (currentFilters.tags.length > 0) activeFilters.push( `${currentFilters.tags.length} tag${ currentFilters.tags.length > 1 ? "s" : "" }` ); let countText = `${results.length} of ${allItems.length} workflows`; if (activeFilters.length > 0) { countText += ` (filtered by ${activeFilters.join(", ")})`; } if (countEl) countEl.textContent = countText; } function renderItems(items: Workflow[], query = ""): void { const list = document.getElementById("resource-list"); if (!list) return; if (items.length === 0) { list.innerHTML = '

No workflows found

Try a different search term or adjust filters

'; return; } list.innerHTML = items .map( (item) => `
${ query ? search.highlight(item.title, query) : escapeHtml(item.title) }
${escapeHtml( item.description || "No description" )}
${item.triggers .map( (t) => `${escapeHtml(t)}` ) .join("")} ${item.tags .map( (t) => `${escapeHtml(t)}` ) .join("")} ${getLastUpdatedHtml(item.lastUpdated)}
${getActionButtonsHtml(item.path)} GitHub
` ) .join(""); // Add click handlers for opening modal list.querySelectorAll(".resource-item").forEach((el) => { el.addEventListener("click", (e) => { if ((e.target as HTMLElement).closest(".resource-actions")) return; const path = (el as HTMLElement).dataset.path; if (path) openFileModal(path, resourceType); }); }); } export async function initWorkflowsPage(): Promise { const list = document.getElementById("resource-list"); const searchInput = document.getElementById( "search-input" ) as HTMLInputElement; const clearFiltersBtn = document.getElementById("clear-filters"); const sortSelect = document.getElementById( "sort-select" ) as HTMLSelectElement; const data = await fetchData("workflows.json"); if (!data || !data.items) { if (list) list.innerHTML = '

Failed to load data

'; return; } allItems = data.items; search.setItems(allItems); // Setup trigger filter triggerSelect = createChoices("#filter-trigger", { placeholderValue: "All Triggers", }); triggerSelect.setChoices( data.filters.triggers.map((t) => ({ value: t, label: t })), "value", "label", true ); document.getElementById("filter-trigger")?.addEventListener("change", () => { currentFilters.triggers = getChoicesValues(triggerSelect); applyFiltersAndRender(); }); // Setup tag filter tagSelect = createChoices("#filter-tag", { placeholderValue: "All Tags", }); tagSelect.setChoices( data.filters.tags.map((t) => ({ value: t, label: t })), "value", "label", true ); document.getElementById("filter-tag")?.addEventListener("change", () => { currentFilters.tags = getChoicesValues(tagSelect); applyFiltersAndRender(); }); sortSelect?.addEventListener("change", () => { currentSort = sortSelect.value as SortOption; applyFiltersAndRender(); }); applyFiltersAndRender(); searchInput?.addEventListener( "input", debounce(() => applyFiltersAndRender(), 200) ); clearFiltersBtn?.addEventListener("click", () => { currentFilters = { triggers: [], tags: [] }; currentSort = "title"; triggerSelect.removeActiveItems(); tagSelect.removeActiveItems(); if (searchInput) searchInput.value = ""; if (sortSelect) sortSelect.value = "title"; applyFiltersAndRender(); }); setupModal(); setupActionHandlers(); } // Auto-initialize when DOM is ready document.addEventListener("DOMContentLoaded", initWorkflowsPage);