import { IconReload } from '@tabler/icons-solidjs' import { createVirtualizer } from '@tanstack/solid-virtual' import { matchSorter } from 'match-sorter' import { For, Show, createMemo, createSignal, onMount } from 'solid-js' import { twMerge } from 'tailwind-merge' import { Button } from '~/components' import { useStringBooleanMap } from '~/helpers' import { useI18n } from '~/i18n' import { formatTimeFromNow, useRules } from '~/signals' import { Rule, RuleProvider } from '~/types' enum ActiveTab { ruleProviders = 'ruleProviders', rules = 'rules', } export default () => { const [t] = useI18n() const { rules, ruleProviders, updateRules, updateAllRuleProvider, updateRuleProviderByName, } = useRules() onMount(updateRules) const { map: updatingMap, setWithCallback: setUpdatingMap } = useStringBooleanMap() const [allProviderIsUpdating, setAllProviderIsUpdating] = createSignal(false) const onUpdateProviderClick = (e: MouseEvent, name: string) => { e.stopPropagation() void setUpdatingMap(name, () => updateRuleProviderByName(name)) } const onUpdateAllProviderClick = async (e: MouseEvent) => { e.stopPropagation() setAllProviderIsUpdating(true) try { await updateAllRuleProvider() } catch {} setAllProviderIsUpdating(false) } const [activeTab, setActiveTab] = createSignal(ActiveTab.rules) const tabs = () => [ { type: ActiveTab.rules, name: t('rules'), count: rules().length, }, { type: ActiveTab.ruleProviders, name: t('ruleProviders'), count: ruleProviders().length, }, ] const [globalFilter, setGlobalFilter] = createSignal('') const filteredRules = createMemo(() => globalFilter() ? matchSorter(rules(), globalFilter(), { keys: ['type', 'payload', 'type'] as (keyof Rule)[], }) : rules(), ) const filteredRuleProviders = createMemo(() => globalFilter() ? matchSorter(ruleProviders(), globalFilter(), { keys: ['name', 'vehicleType', 'behavior'] as (keyof RuleProvider)[], }) : ruleProviders(), ) let scrollElementRef: HTMLDivElement | undefined const ruleVirtualizer = createVirtualizer({ get count() { return filteredRules().length }, getItemKey: (index) => filteredRules()[index].payload, getScrollElement: () => scrollElementRef!, estimateSize: () => 74, overscan: 5, }) const ruleVirtualizerItems = ruleVirtualizer.getVirtualItems() const ruleProviderVirtualizer = createVirtualizer({ get count() { return filteredRuleProviders().length }, getItemKey: (index) => filteredRuleProviders()[index].name, getScrollElement: () => scrollElementRef!, estimateSize: () => 74, overscan: 5, }) const ruleProviderVirtualizerItems = ruleProviderVirtualizer.getVirtualItems() return (
{(tab) => ( )}
setGlobalFilter(e.currentTarget.value)} />
(scrollElementRef = ref)} class="flex-1 overflow-y-auto" >
{ruleVirtualizerItems.map((virtualizerItem) => { const rule = filteredRules().find( (rule) => rule.payload === virtualizerItem.key, )! return (
onMount(() => ruleVirtualizer.measureElement(el)) } data-index={virtualizerItem.index} class="absolute inset-x-0 top-0 pb-2 last:pb-0" style={{ transform: `translateY(${virtualizerItem.start}px)`, }} >
{rule.payload}
{rule.size}
{rule.type} :: {rule.proxy}
) })}
{ruleProviderVirtualizerItems.map((virtualizerItem) => { const ruleProvider = ruleProviders().find( (ruleProvider) => ruleProvider.name === virtualizerItem.key, )! return (
onMount(() => ruleProviderVirtualizer.measureElement(el)) } data-index={virtualizerItem.index} class="absolute inset-x-0 top-0 pb-2 last:pb-0" style={{ transform: `translateY(${virtualizerItem.start}px)`, }} >
{ruleProvider.name}
{ruleProvider.ruleCount}
{ruleProvider.vehicleType} / {ruleProvider.behavior} / {t('updated')} {formatTimeFromNow(ruleProvider.updatedAt)}
) })}
) }