Skip to content
33 changes: 33 additions & 0 deletions os-checks/components/InfoTestCases.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<template>

<DataTable :value="data" showGridlines>

<Column field="idx" header="Idx" />
<Column field="binary_name" header="Binary Name" />
<Column field="kind" header="Kind" />
<Column field="test" header="Test Case" />

</DataTable>

</template>

<script setup lang="ts">
import type { Test } from '~/shared/info';

const { tests } = defineProps<{ tests: Test[] }>();

const data = computed(() => {
let idx = 0;
return tests.map(test => {
return test.testcases.map(t => {
idx += 1;
return {
idx,
binary_name: test.binary_name,
kind: test.kind,
test: t,
}
})
}).flat();
});
</script>
4 changes: 4 additions & 0 deletions os-checks/components/TopBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
<Button title="Github Workflows" icon="pi pi-bell" />
</NuxtLink>

<NuxtLink to="/info">
<Button title="Package & Testcase Infomation" icon="pi pi-microchip" />
</NuxtLink>

</div>

<div class="topBarRight">
Expand Down
4 changes: 2 additions & 2 deletions os-checks/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,13 @@ const progressRatio = computed(() => {
}

.nav-link {
color: #336ad7;
color: var(--p-indigo-500);
/* 统一的链接颜色 */
text-decoration: none;
}

.nav-link.router-link-active {
color: #336ad7;
color: var(--p-indigo-500);
/* 重置激活链接的颜色 */
}

Expand Down
252 changes: 252 additions & 0 deletions os-checks/pages/info.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
<template>
<div>
<DataTable :value="data" tableStyle="min-width: 50rem;" scrollable scrollHeight="800px" showGridlines
selectionMode="single" v-model:selection="selectedPkg" v-model:filters="filters"
:globalFilterFields="['user', 'repo', 'pkg', 'description', 'categories', 'os_categories']" removableSort
sortMode="multiple" paginator :rows="10" :rowsPerPageOptions="[5, 10, 20, 50, 100, 200, 1000]">

<template #header>
<div style="display: flex; justify-content: space-between;">
<div style="display: flex; gap: 20px;">
<MultiSelect v-model="selectedCategories" display="chip" :options="categories" filter :maxSelectedLabels="4"
placeholder="Select Categories" />

<MultiSelect v-model="selectedOSCategories" display="chip" :options="os_categories" filter
:maxSelectedLabels="4" placeholder="Select OS Categories" />

<MultiSelect v-model="selectedAuthors" display="chip" :options="authors" filter :maxSelectedLabels="4"
placeholder="Select Authors" />
</div>

<div style="width: 30%">
<IconField>
<InputIcon>
<i class="pi pi-search" />
</InputIcon>
<InputText style="width: 100%" v-model="filters['global'].value"
placeholder="Search in all text columns" />
</IconField>
</div>

</div>
</template>

<Column frozen sortable field="idx" header="Idx" />
<Column frozen sortable field="user" header="User" style="min-width: 150px;" />
<Column frozen sortable field="repo" header="Repo" style="min-width: 180px;" />
<Column frozen sortable field="pkg" header="Package" style="min-width: 200px;" />

<Column sortable field="version" header="Version" style="text-align: center;" />
<Column sortable field="dependencies" header="Depen-dencies" style="text-align: center;" />

<Column sortable field="testcases" header="Test Cases" style="text-align: center;" />

<Column sortable field="tests" header="Tests" style="text-align: center;" />
<Column sortable field="examples" header="Examples" style="text-align: center;" />
<Column sortable field="benches" header="Benches" style="text-align: center;" />

<Column sortable field="categories" header="Categories" style="min-width: 210px;">
<template #body="{ data: { categories } }">
<div v-for="tag of categories">
<Tag severity="warn" :value="tag" style="margin-bottom: 5px;"></Tag>
</div>
</template>
</Column>

<Column sortable field="os_categories" header="OS Categories">
<template #body="{ data: { os_categories } }">
<div v-for="tag of os_categories">
<Tag severity="warn" :value="tag" style="margin-bottom: 5px;"></Tag>
</div>
</template>
</Column>

<Column field="description" header="Description" style="min-width: 400px;" />

<Column sortable field="author" header="Author" style="min-width: 400px;">
<template #body="{ data: { author } }">
<div v-for="tag of author">
<Tag severity="info" :value="tag" style="margin-bottom: 5px;"></Tag>
</div>
</template>
</Column>

</DataTable>

<Dialog v-model:visible="dialogShow" modal :style="{ width: '70%' }">
<template #header>
<span style="display: inline-flex; justify-content: center; gap: 40px; font-size: larger; font-weight: bold;">
<div>
<NuxtLink :to="dialogHeader?.repo_url" target="_blank">
<Tag icon="pi pi-github" severity="info" style="font-weight: bold;">
{{ dialogHeader?.repo }}
</Tag>
</NuxtLink>
</div>

<div>Test Cases of package
<span style="color: var(--p-emerald-500); margin-right: 5px;">{{ dialogHeader?.pkg_name }}</span>
</div>
</span>
</template>

<div>
<div class="dialog-header">
Description: <b style="color: var(--p-emerald-500)">{{ dialogHeader?.pkg.description }}</b>
</div>
<div class="dialog-header">
Categories:
<Tag v-for="tag of dialogHeader?.pkg.categories" severity="warn" :value="tag" style="margin-right: 6px;" />
</div>
<div class="dialog-header">
OS Categories:
<Tag v-for="tag of dialogHeader?.pkg.os_categories" severity="warn" :value="tag" style="margin-right: 6px;" />
</div>
<div class="dialog-header">
Authors:
<Tag v-for="tag of dialogHeader?.pkg.author" severity="info" :value="tag" style="margin-bottom: 5px;"></Tag>
</div>

<InfoTestCases :tests="testCases" />
</div>
</Dialog>
</div>
</template>

<script setup lang="ts">
import type { Pkg, PkgInfo, Test } from '~/shared/info';
import { FilterMatchMode } from '@primevue/core/api';

// interactive filter/search inputs
const filters = ref<any>({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
});

const summaries = ref<PkgInfo[]>([]);

githubFetch<PkgInfo[]>({
path: "plugin/cargo/info/summaries.json"
}).then(val => {
summaries.value = val;
});

const summaryTable = computed<SummaryTable[]>(() => {
const value = summaries.value.map(val => {
return Object.entries(val.pkgs).map(([name, pkg]) => {
return {
idx: 0,
user: val.user,
repo: val.repo,
pkg: name,
version: pkg.version,
dependencies: pkg.dependencies || null,
testcases: pkg.testcases ? pkg.testcases.pkg_tests_count : null,
tests: pkg.tests || null,
examples: pkg.examples || null,
benches: pkg.benches || null,
author: pkg.author.length === 0 ? null : pkg.author,
description: pkg.description,
categories: pkg.categories.length === 0 ? null : pkg.categories,
os_categories: pkg.os_categories.length === 0 ? null : pkg.os_categories,
}
})
}).flat();

return value.sort((a, b) => {
const a_test = a.testcases ?? 0;
const b_test = b.testcases ?? 0;
if (a_test < b_test) {
return 1;
} else if (a_test > b_test) {
return -1;
} else if (a.user < b.user) {
return -1;
} else if (a.user > b.user) {
return 1;
} else if (a.repo < b.repo) {
return -1;
} else if (a.repo > b.repo) {
return 1;
} else if (a.pkg < b.pkg) {
return -1;
} else if (a.pkg > b.pkg) {
return 1;
}
return 0;
}).map((val, idx) => {
val.idx = idx + 1;
return val;
});
});

type SummaryTable = { idx: number; user: string; repo: string; pkg: string; version: string; dependencies: number | null; testcases: number | null; tests: number | null; examples: number | null; benches: number | null; author: string[] | null; description: string[]; categories: string[] | null; os_categories: string[] | null; };
const data = ref<SummaryTable[]>([]);
watch(summaryTable, (val) => data.value = val);

const categories = computed(() => [...new Set(summaryTable.value.map(val => val.categories).flat().filter(c => c))].sort());
const os_categories = computed(() => [...new Set(summaryTable.value.map(val => val.os_categories).flat().filter(c => c))].sort());
const authors = computed(() => [...new Set(summaryTable.value.map(val => val.author).flat().filter(c => c))].sort());
const selectedCategories = ref<string[]>([]);
const selectedOSCategories = ref<string[]>([]);
const selectedAuthors = ref<string[]>([]);
watchEffect(() => {
const cat = selectedCategories.value;
const os_cat = selectedOSCategories.value;
const au = selectedAuthors.value;

const is_empty_cat = cat.length === 0;
const is_empty_os_cat = os_cat.length === 0;
const is_empty_au = au.length === 0;

// reset
if (is_empty_cat && is_empty_os_cat && is_empty_au) {
data.value = summaryTable.value;
return;
}

data.value = summaryTable.value.filter(val => {
const find_cat = cat.find(c => val.categories?.find(vc => vc === c));
const find_os_cat = os_cat.find(o => val.os_categories?.find(vo => vo === o));
const find_au = au.find(a => val.author?.find(va => va === a));

return (is_empty_cat ? true : find_cat) && (is_empty_os_cat ? true : find_os_cat) && (is_empty_au ? true : find_au)
}).map((x, idx) => {
x.idx = idx + 1;
return x;
});
});

const dialogShow = ref(false);
const dialogHeader = ref<{ repo: string, repo_url: string, pkg_name: string, pkg: Pkg } | null>();
const testCases = ref<Test[]>([]);

type SelectedRow = { user: string, repo: string, pkg: string, testcases: number };
const selectedPkg = ref<SelectedRow | null>(null);
watch(selectedPkg, val => {

if (!val?.testcases) { return; }

// for now, pop up a dialog to display testcases only if any
dialogShow.value = true;

const pkg = summaries.value
.find(summary => summary.user === val.user && summary.repo === val.repo)
?.pkgs[val.pkg];

if (!pkg?.testcases) { return; }

const repo = `${val.user}/${val.repo}`;
const repo_url = `https://github.com/${repo}`;
dialogHeader.value = { repo, repo_url, pkg_name: val.pkg, pkg };

testCases.value = pkg.testcases.tests;
});


</script>

<style lang="css">
.dialog-header {
margin-bottom: 10px;
}
</style>
34 changes: 34 additions & 0 deletions os-checks/shared/info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export type PkgInfo = {
user: string,
repo: string,
pkgs: { [key: string]: Pkg }
}

export type Pkg = {
version: string,
dependencies: number,
lib: boolean,
bin: boolean,
testcases: TestCases | null,
tests: number,
examples: number,
benches: number,
author: string[]
description: string[],
categories: string[]
os_categories: string[],
}

export type TestCases = {
tests: Test[],
pkg_tests_count: number,
workspace_tests_count: number,
}

export type Test = {
id: string,
kind: string,
binary_name: string,
binary_path: string,
testcases: string[]
}
Loading