Skip to content

Commit

Permalink
feat(rule): implement virtual scroll on rules and rule providers, fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
kunish committed Sep 26, 2023
1 parent f8bf02e commit 7145cec
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 55 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"@tabler/icons-solidjs": "^2.35.0",
"@tanstack/match-sorter-utils": "^8.8.4",
"@tanstack/solid-table": "^8.10.3",
"@tanstack/solid-virtual": "3.0.0-beta.6",
"@tanstack/solid-virtual": "3.0.0-beta.60",
"@tanstack/virtual-core": "3.0.0-beta.60",
"@thisbeyond/solid-dnd": "^0.7.4",
"@types/byte-size": "^8.1.0",
"@types/lodash": "^4.14.199",
Expand Down
25 changes: 15 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

144 changes: 100 additions & 44 deletions src/pages/Rules.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IconReload } from '@tabler/icons-solidjs'
import { createVirtualizer } from '@tanstack/solid-virtual'
import { For, Show, createSignal, onMount } from 'solid-js'
import { twMerge } from 'tailwind-merge'
import { Button } from '~/components'
Expand Down Expand Up @@ -56,6 +57,30 @@ export default () => {
},
]

let parentRef: HTMLDivElement | undefined

const ruleVirtualizer = createVirtualizer({
get count() {
return rules().length
},
getScrollElement: () => parentRef!,
estimateSize: () => 74,
overscan: 5,
})

const ruleVirtualizerItems = ruleVirtualizer.getVirtualItems()

const ruleProviderVirtualizer = createVirtualizer({
get count() {
return ruleProviders().length
},
getScrollElement: () => parentRef!,
estimateSize: () => 74,
overscan: 5,
})

const ruleProviderVirtualizerItems = ruleProviderVirtualizer.getVirtualItems()

return (
<div class="flex h-full flex-col gap-2">
<div class="flex items-center gap-2">
Expand Down Expand Up @@ -92,60 +117,91 @@ export default () => {
</Show>
</div>

<div class="flex-1 overflow-y-auto">
<div ref={(ref) => (parentRef = ref)} class="flex-1 overflow-y-auto">
<Show when={activeTab() === ActiveTab.rules}>
<div class="grid gap-2">
<For each={rules()}>
{(rule) => (
<div class="card card-bordered card-compact bg-base-200 p-4">
<div class="flex items-center gap-2">
<span class="break-all">{rule.payload}</span>
<Show
when={typeof rule.size === 'number' && rule.size !== -1}
>
<div class="badge badge-sm">{rule.size}</div>
</Show>
</div>
<div class="text-xs text-slate-500">
{rule.type} :: {rule.proxy}
<div
class="relative"
style={{ height: `${ruleVirtualizer.getTotalSize()}px` }}
>
{ruleVirtualizerItems.map((virtualizerItem) => {
const rule = rules()[virtualizerItem.index]

return (
<div
ref={(el) =>
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)`,
}}
>
<div class="card card-bordered card-compact bg-base-200 p-4">
<div class="flex items-center gap-2">
<span class="break-all">{rule.payload}</span>

<Show when={rule.size !== -1}>
<div class="badge badge-sm">{rule.size}</div>
</Show>
</div>

<div class="text-xs text-slate-500">
{rule.type} :: {rule.proxy}
</div>
</div>
</div>
)}
</For>
)
})}
</div>
</Show>

<Show when={activeTab() === ActiveTab.ruleProviders}>
<div class="grid gap-2">
<For each={ruleProviders()}>
{(ruleProvider) => (
<div class="card card-bordered card-compact bg-base-200 p-4">
<div class="flex items-center gap-2 pr-8">
<span class="break-all">{ruleProvider.name}</span>
<div class="badge badge-sm">{ruleProvider.ruleCount}</div>
</div>
<div class="relative">
{ruleProviderVirtualizerItems.map((virtualizerItem) => {
const ruleProvider = ruleProviders()[virtualizerItem.index]

<div class="text-xs text-slate-500">
{ruleProvider.vehicleType} / {ruleProvider.behavior} /
{t('updated')} {formatTimeFromNow(ruleProvider.updatedAt)}
</div>
return (
<div
ref={(el) =>
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)`,
}}
>
<div class="card card-bordered card-compact bg-base-200 p-4">
<div class="flex items-center gap-2 pr-8">
<span class="break-all">{ruleProvider.name}</span>
<div class="badge badge-sm">{ruleProvider.ruleCount}</div>
</div>

<div class="text-xs text-slate-500">
{ruleProvider.vehicleType} / {ruleProvider.behavior} /
{t('updated')} {formatTimeFromNow(ruleProvider.updatedAt)}
</div>

<Button
class="btn-circle btn-sm absolute right-2 top-2 mr-2 h-4"
disabled={updatingMap()[ruleProvider.name]}
onClick={(e) => onUpdateProviderClick(e, ruleProvider.name)}
icon={
<IconReload
class={twMerge(
updatingMap()[ruleProvider.name] &&
'animate-spin text-success',
)}
/>
}
/>
<Button
class="btn-circle btn-sm absolute right-2 top-2 mr-2 h-4"
disabled={updatingMap()[ruleProvider.name]}
onClick={(e) =>
onUpdateProviderClick(e, ruleProvider.name)
}
icon={
<IconReload
class={twMerge(
updatingMap()[ruleProvider.name] &&
'animate-spin text-success',
)}
/>
}
/>
</div>
</div>
)}
</For>
)
})}
</div>
</Show>
</div>
Expand Down

0 comments on commit 7145cec

Please sign in to comment.