Skip to content

Commit e1b39e8

Browse files
committed
feat: basic filters
1 parent ac53eb7 commit e1b39e8

File tree

2 files changed

+131
-17
lines changed

2 files changed

+131
-17
lines changed

packages/devtools/src/app/pages/session/[session]/index.vue

Lines changed: 127 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,117 @@
11
<script setup lang="ts">
22
import type { SessionContext } from '../../../types/data'
3-
import { computedWithControl } from '@vueuse/core'
3+
import { useRoute, useRouter } from '#app/composables/router'
4+
import { clearUndefined } from '@antfu/utils'
5+
import { computedWithControl, debouncedWatch } from '@vueuse/core'
46
import Fuse from 'fuse.js'
57
import { computed, reactive } from 'vue'
8+
import { parseReadablePath } from '../../../utils/filepath'
9+
import { getFileTypeFromModuleId, getFileTypeFromName } from '../../../utils/icon'
610
711
const props = defineProps<{
812
session: SessionContext
913
}>()
1014
11-
const filters = reactive({
12-
search: '',
15+
interface Filters {
16+
search: string
17+
file_types: string[] | null
18+
node_modules: string[] | null
19+
}
20+
21+
const route = useRoute()
22+
const router = useRouter()
23+
24+
const filters = reactive<Filters>({
25+
search: (route.query.search || '') as string,
26+
file_types: (route.query.file_types || null) as string[] | null,
27+
node_modules: (route.query.node_modules || null) as string[] | null,
28+
})
29+
30+
debouncedWatch(
31+
filters,
32+
(f) => {
33+
const query: any = {
34+
...route.query,
35+
search: f.search || undefined,
36+
file_types: f.file_types || undefined,
37+
node_modules: f.node_modules || undefined,
38+
}
39+
router.replace({
40+
query: clearUndefined(query),
41+
})
42+
},
43+
{ debounce: 500 },
44+
)
45+
46+
const parsedPaths = computed(() => props.session.modulesList.map((mod) => {
47+
const path = parseReadablePath(mod.id, props.session.rootDir)
48+
const type = getFileTypeFromModuleId(mod.id)
49+
return {
50+
mod,
51+
path,
52+
type,
53+
}
54+
}))
55+
56+
// const allNodeModules = computed(() => {
57+
// const nodeModules = new Set<string>()
58+
// for (const mod of parsedPaths.value) {
59+
// if (mod.path.moduleName)
60+
// nodeModules.add(mod.path.moduleName)
61+
// }
62+
// return nodeModules
63+
// })
64+
65+
const allFileTypes = computed(() => {
66+
const fileTypes = new Set<string>()
67+
for (const mod of parsedPaths.value) {
68+
fileTypes.add(mod.type.name)
69+
}
70+
return fileTypes
1371
})
1472
73+
const filtered = computed(() => {
74+
let modules = parsedPaths.value
75+
if (filters.file_types) {
76+
modules = modules.filter(mod => filters.file_types!.includes(mod.type.name))
77+
}
78+
if (filters.node_modules) {
79+
modules = modules.filter(mod => mod.path.moduleName && filters.node_modules!.includes(mod.path.moduleName))
80+
}
81+
return modules.map(mod => mod.mod)
82+
})
83+
84+
function isFileTypeSelected(type: string) {
85+
return filters.file_types == null || filters.file_types.includes(type)
86+
}
87+
88+
function toggleFileType(type: string) {
89+
if (filters.file_types == null) {
90+
filters.file_types = Array.from(allFileTypes.value)
91+
}
92+
93+
if (filters.file_types.includes(type)) {
94+
filters.file_types = filters.file_types.filter(t => t !== type)
95+
}
96+
else {
97+
filters.file_types.push(type)
98+
}
99+
if (filters.file_types.length === allFileTypes.value.size) {
100+
filters.file_types = null
101+
}
102+
}
103+
15104
const fuse = computedWithControl(
16-
() => props.session.modulesList,
17-
() => new Fuse(props.session.modulesList, {
105+
() => filtered.value,
106+
() => new Fuse(filtered.value, {
18107
includeScore: true,
19108
keys: ['id'],
20109
}),
21110
)
22111
23-
const filtered = computed(() => {
112+
const searched = computed(() => {
24113
if (filters.search === '') {
25-
return props.session.modulesList
114+
return filtered.value
26115
}
27116
return fuse.value
28117
.search(filters.search)
@@ -32,15 +121,38 @@ const filtered = computed(() => {
32121

33122
<template>
34123
<div flex="~ col gap-2" p4>
35-
<div>
36-
<input
37-
v-model="filters.search"
38-
border="~ base rounded-full"
39-
p2 px4 w-full outline-none
40-
placeholder="Search"
41-
>
124+
<div flex="col gap-2">
125+
<div>
126+
<input
127+
v-model="filters.search"
128+
border="~ base rounded-full"
129+
p2 px4 w-full outline-none
130+
placeholder="Search"
131+
>
132+
</div>
133+
<div flex="~ gap-2" py2>
134+
<label
135+
v-for="type of allFileTypes"
136+
:key="type"
137+
border="~ base rounded" px2 py1
138+
flex="~ items-center gap-1"
139+
:title="type"
140+
:class="isFileTypeSelected(type) ? 'bg-active' : 'grayscale op50'"
141+
>
142+
<input
143+
type="checkbox"
144+
:checked="isFileTypeSelected(type)"
145+
mr1
146+
@change="toggleFileType(type)"
147+
>
148+
<div :class="getFileTypeFromName(type).icon" />
149+
<div text-sm>{{ getFileTypeFromName(type).description }}</div>
150+
</label>
151+
</div>
152+
<!-- TODO: should we add filters for node_modules? -->
153+
<!-- {{ allNodeModules }} -->
42154
</div>
43-
<template v-for="mod of filtered" :key="mod">
155+
<template v-for="mod of searched" :key="mod">
44156
<DisplayModuleId
45157
:id="mod.id"
46158
:session

packages/devtools/src/app/utils/icon.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { makeCachedFunction } from './cache'
2+
13
export interface ModuleTypeRule {
24
match: RegExp
35
name: string
@@ -128,7 +130,7 @@ export function getFileTypeFromName(name: string) {
128130
return ModuleTypeRules.find(rule => rule.name === name) ?? DefaultTypeRule
129131
}
130132

131-
export function getFileTypeFromModuleId(moduleId: string): ModuleTypeRule {
133+
export const getFileTypeFromModuleId = makeCachedFunction((moduleId: string): ModuleTypeRule => {
132134
moduleId = moduleId
133135
.replace(/(\?|&)v=[^&]*/, '$1')
134136
.replace(/\?$/, '')
@@ -140,4 +142,4 @@ export function getFileTypeFromModuleId(moduleId: string): ModuleTypeRule {
140142
}
141143

142144
return DefaultTypeRule
143-
}
145+
})

0 commit comments

Comments
 (0)