-        
-          User:
-          
-            
-          
-
-          Repo:
-          
-            
-          
-
-          
-
-        
+    
 
     
@@ -54,11 +36,9 @@ import type { Basic } from '~/shared/types';
 useHead({ title: 'Issue File Tree' });
 highlightRust();
 
-const label = (a: string) => a;
-
 const selected = reactive<{
-  user: string,
-  repo: string,
+  user: string | null,
+  repo: string | null,
   target: string | null,
   pkg: string | null,
   features: string | null,
@@ -88,7 +68,7 @@ githubFetch
({ path: "ui/user_repo.json" })
 
 // Init filters.
 const users = computed(() => Object.keys(user_repo.value).sort());
-const repos = computed(() => user_repo.value[selected.user]);
+const repos = computed(() => selected.user ? user_repo.value[selected.user] : []);
 const targets = computed(() => {
   const t = basic.value?.targets;
   return t ? gen_targets(t) : emptyOptions();
@@ -334,17 +314,3 @@ watch(lockURL, lock => {
   router_params.value = query;
 });
 
-
-
-
diff --git a/os-checks/pages/testcases.vue b/os-checks/pages/testcases.vue
index 34c1869..a5c4fb7 100644
--- a/os-checks/pages/testcases.vue
+++ b/os-checks/pages/testcases.vue
@@ -1,6 +1,6 @@
 
 
-   No testcases found. 
     
       
-        
-          
-          
+        
+          
+          
+          
+          
+          
+          
         
 
         
           
               
-            
+            
           
         
 
@@ -93,6 +98,9 @@
 import type { DataTableSortMeta } from 'primevue/datatable';
 import { FilterMatchMode } from '@primevue/core/api';
 import type { PkgInfo } from '~/shared/info';
+import { cloneDeep, uniq } from 'es-toolkit/compat';
+
+useHead({ title: 'Test Cases' });
 
 // styling
 const { viewportHeight } = storeToRefs(useStyleStore());
@@ -108,6 +116,7 @@ const ptColumnRight = ref({
 highlightRust();
 
 const testcases = ref
([]);
+const testcasesFiltered = ref([]);
 const selectedTest = ref(null);
 
 // pop up details
@@ -118,6 +127,7 @@ githubFetch({
   path: "plugin/cargo/info/summaries.json"
 }).then(val => {
   testcases.value = summariesToTestResult(val);
+  testcasesFiltered.value = cloneDeep(testcases.value);
 });
 
 type TestResult = {
@@ -174,12 +184,94 @@ function sortsChanged(meta?: DataTableSortMeta[] | null) {
 }
 
 const selected = reactive<{
+  user: string | null,
+  repo: string | null,
+  pkg: string | null,
+  kind: string | null,
+  test_pass: string | null,
+  miri_pass: string | null,
+  miri_timeout: string | null,
   text: any,
   sorts: DataTableSortMeta[],
 }>({
+  user: null,
+  repo: null,
+  pkg: null,
+  kind: null,
+  test_pass: null,
+  miri_pass: null,
+  miri_timeout: null,
   text: { global: { value: null, matchMode: FilterMatchMode.CONTAINS }, },
   sorts: [],
 });
 
-useHead({ title: 'Test Cases' });
+type Options = {
+  user: string[],
+  repo: string[],
+  pkg: string[],
+  kind: string[],
+  test_pass: string[],
+  miri_pass: string[],
+  miri_timeout: string[],
+};
+function defaultOptions(): Options {
+  return {
+    user: [],
+    repo: [],
+    pkg: [],
+    kind: [],
+    test_pass: [],
+    miri_pass: [],
+    miri_timeout: [],
+  };
+}
+const options = reactive<{ val: Options }>({ val: defaultOptions() });
+
+// init options
+watch(testcases, tc => options.val = testcasesToOptions(tc));
+
+// update table when filter selection changes
+watch(
+  selected,
+  ({ user, repo, pkg, kind, test_pass, miri_pass, miri_timeout }) => {
+    // for simplicity, the data of testcases are supposed to remain unchanged
+    const chosen_testcases = testcases.value.filter(test => {
+      let chosen = true;
+      if (user) chosen &&= test.user === user;
+      if (repo) chosen &&= test.repo === repo;
+      if (pkg) chosen &&= test.pkg === pkg;
+      if (kind) chosen &&= test.kind === repo;
+      if (test_pass) chosen &&= test.test_pass === test_pass;
+      if (miri_pass) chosen &&= test.miri_pass === miri_pass;
+      if (miri_timeout || miri_timeout === "") chosen &&= test.miri_timeout === miri_timeout;
+      return chosen;
+    });
+    testcasesFiltered.value = chosen_testcases.map((tc, idx) => {
+      tc.idx = idx;
+      return tc;
+    });
+    // options.val = testcasesToOptions(chosen_testcases);
+  });
+
+function testcasesToOptions(tc: TestResult[]): Options {
+  let opts = defaultOptions();
+  for (const test of tc) {
+    opts.user.push(test.user);
+    opts.repo.push(test.repo);
+    opts.pkg.push(test.pkg);
+    opts.kind.push(test.kind);
+    opts.test_pass.push(test.test_pass);
+    opts.miri_pass.push(test.miri_pass);
+    opts.miri_timeout.push(test.miri_timeout);
+  }
+
+  opts.user = uniq(opts.user).sort();
+  opts.repo = uniq(opts.repo).sort();
+  opts.pkg = uniq(opts.pkg).sort();
+  opts.kind = uniq(opts.kind).sort();
+  opts.test_pass = uniq(opts.test_pass).sort();
+  opts.miri_pass = uniq(opts.miri_pass).sort();
+  opts.miri_timeout = uniq(opts.miri_timeout).sort();
+  return opts;
+}