Skip to content

Commit 443af6c

Browse files
authored
Merge pull request #144 from os-checker/feat/rework-filetree
refactor(/file-tree): 添加筛选项来交互式查找诊断详情
2 parents cad072c + 50b8ad1 commit 443af6c

File tree

14 files changed

+948
-18
lines changed

14 files changed

+948
-18
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<script lang="ts" setup>
2+
import type { DropDownOptions } from '~/shared/file-tree/types';
3+
4+
type Props = { tag: string, counts: DropDownOptions, all: string };
5+
const { tag, counts } = defineProps<Props>();
6+
const selected = defineModel<string | null>({ default: null });
7+
</script>
8+
9+
<template>
10+
11+
<span class="input">{{ tag }}:</span>
12+
<span class="select">
13+
<Select v-model="selected" filter showClear :options="counts.names">
14+
<template #option="{ option }">
15+
<Tag severity="danger" class="drop-down-options">{{ counts.counts[option] }}</Tag>
16+
{{ option }}
17+
</template>
18+
19+
<!-- <template #value="{ value }"> -->
20+
<!-- {{ value || all }} -->
21+
<!-- <Tag severity="danger" style="margin-left: 5px">{{ counts.counts[value || all] }}</Tag> -->
22+
<!-- </template> -->
23+
</Select>
24+
</span>
25+
26+
</template>
27+
28+
<style scoped>
29+
.input {
30+
font-size: 14.5px;
31+
font-weight: bold;
32+
padding-right: 10px;
33+
color: var(--p-button-primary-background);
34+
}
35+
36+
.select {
37+
padding-right: 10px;
38+
}
39+
40+
.resolved-table {
41+
--p-datatable-header-cell-color: var(--p-button-primary-background);
42+
}
43+
44+
.sources {
45+
color: var(--p-orange-400);
46+
}
47+
48+
.sources-table {
49+
--p-datatable-header-cell-color: var(--p-orange-400);
50+
}
51+
52+
.drop-down-options {
53+
margin-right: 8px;
54+
width: 40px;
55+
justify-content: right;
56+
}
57+
</style>

os-checks/components/FileTree.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import type { FetchError } from 'ofetch';
33
import type { TreeNode } from 'primevue/treenode';
44
import type { FileTree, Kinds } from '~/shared/file-tree';
5+
import { getEmpty } from '../shared/file-tree/utils';
56
67
type Props = { fetch_path: (target: string) => string };
78
const props = defineProps<Props>();
@@ -10,7 +11,7 @@ highlightRust();
1011
1112
const tabs = ref<CheckerResult[]>([]);
1213
const selectedTab = ref("");
13-
const fileTree = ref<FileTree>({ kinds_order: [], data: [] });
14+
const fileTree = ref<FileTree>(getEmpty().fileTree);
1415
1516
const basic = useBasicStore();
1617
@@ -46,7 +47,7 @@ basic.init_with_and_subscribe_to_current((target: string) => {
4647
lang: "rust", severity: Severity.Info, disabled: false
4748
}];
4849
selectedTab.value = "All good! 🥳";
49-
fileTree.value = { kinds_order: [], data: [] };
50+
fileTree.value = getEmpty().fileTree;
5051
5152
// tabs.value = [{
5253
// kind: "Not Exists!", raw: ["该目标架构下,无原始报告数据。"],

os-checks/components/FileTree2.vue

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
<script setup lang="ts">
2+
import { cloneDeep } from 'es-toolkit/compat';
3+
import type { TreeNode } from 'primevue/treenode';
4+
import type { FileTree } from '~/shared/file-tree';
5+
import { updateSelectedKey, type Get } from '~/shared/file-tree/utils';
6+
7+
type Props = { get: Get, count: number | null };
8+
const { get, count } = defineProps<Props>();
9+
10+
const fullTabs = ref(cloneDeep(get.tabs));
11+
watch(() => get, g => fullTabs.value = cloneDeep(g.tabs));
12+
13+
const filtered_fileTree = computed<FileTree>(() => get.fileTree);
14+
15+
const nodes = computed<TreeNode[]>(() => {
16+
let nodes = [];
17+
18+
let key = 0;
19+
for (const datum of filtered_fileTree.value.data) {
20+
let node: TreeNode = {
21+
key: (key++).toString(), label: `[${datum.count}] ${datum.repo} #${datum.pkg}`, children: [],
22+
};
23+
let count_fmt = 0;
24+
let count_clippy_warn = 0;
25+
let count_clippy_error = 0;
26+
for (const report of datum.raw_reports) {
27+
node.children?.push({
28+
key: (key++).toString(),
29+
label: `[${report.count}] ${report.file}`,
30+
data: report.file
31+
});
32+
33+
}
34+
node.data = {
35+
user: datum.user, repo: datum.repo, pkg: datum.pkg,
36+
total: datum.count, fmt: count_fmt, clippy_warn: count_clippy_warn, clippy_error: count_clippy_error
37+
};
38+
nodes.push(node);
39+
}
40+
return nodes;
41+
});
42+
43+
const selectedKey = ref({});
44+
watch(() => ({ key: selectedKey.value, n: nodes.value, ft: filtered_fileTree.value }),
45+
({ key, n, ft }) => {
46+
const val = updateSelectedKey(key, n, ft);
47+
if (val !== undefined) {
48+
get.tabs = val.results;
49+
get.selectedTab = val.selectedTab;
50+
} else {
51+
// display full diagnostics if none is selected or something is not found
52+
get.tabs = cloneDeep(fullTabs.value);
53+
}
54+
});
55+
56+
function resetSelectKey() {
57+
selectedKey.value = {};
58+
get.tabs = cloneDeep(fullTabs.value);
59+
}
60+
61+
// true means keeping file tree panel open (thus shows left arrow icon to indicate close)
62+
const displayFileTree = ref(true);
63+
const displayFileTreeIcon = computed<string>(() => displayFileTree.value ? "pi pi-angle-double-left" : "pi pi-angle-double-right");
64+
65+
// true means keeping filter panel open (thus shows up arrow icon to indicate close)
66+
const displayFilters = defineModel<boolean>("filters", { default: true });
67+
const displayFiltersIcon = computed<string>(() => displayFilters.value ? "pi pi-angle-double-up" : "pi pi-angle-double-down");
68+
69+
onMounted(() => {
70+
document.addEventListener("keydown", ({ code }: KeyboardEvent) => {
71+
if (code === "Space") displayFileTree.value = !displayFileTree.value;
72+
else if (code === "Escape") displayFilters.value = !displayFilters.value;
73+
else if (code === "ArrowLeft") displayFileTree.value = false;
74+
else if (code === "ArrowRight") displayFileTree.value = true;
75+
else if (code === "ArrowUp") displayFilters.value = false;
76+
else if (code === "ArrowDown") displayFilters.value = true;
77+
});
78+
});
79+
80+
const { viewportHeight } = storeToRefs(useStyleStore());
81+
const heightCodePanel = computed(() => {
82+
const height = viewportHeight.value;
83+
// add more space to scroll codeblock panel to the bottom if filters exist
84+
const adjust = displayFilters.value ? 100 : 0;
85+
return `${height * 0.85 - adjust}px`;
86+
});
87+
</script>
88+
89+
<template>
90+
<div class="fileViewPanel">
91+
92+
<div class="fileViewNavi" v-if="displayFileTree">
93+
<div style="height: 3.2rem; display: flex; justify-content: space-between; align-items: center;">
94+
<div style="display: flex; justify-content: left; gap: 8px;">
95+
<div style="margin-left: 10px;">
96+
<Button class="btn" :icon="displayFileTreeIcon" severity="secondary" variant="text"
97+
@click="() => displayFileTree = !displayFileTree" />
98+
</div>
99+
<div>
100+
<Button class="btn" :icon="displayFiltersIcon" severity="secondary" variant="text"
101+
@click="() => displayFilters = !displayFilters" />
102+
</div>
103+
</div>
104+
<div v-if="count" style="padding-right: 0.6rem;">
105+
<b style="margin-right: 10px;">Total Count:</b>
106+
<Button class="btn" severity="danger" @click="resetSelectKey"> {{ count }} </Button>
107+
</div>
108+
</div>
109+
110+
<ScrollPanel class="fileViewMenu" :style="{ height: heightCodePanel }">
111+
<PackageFileMenu :nodes="nodes" :selectedKey="selectedKey" @update:selectedKey="selectedKey = $event" />
112+
</ScrollPanel>
113+
</div>
114+
115+
<div class="fileViewResult">
116+
<Tabs :value="get.selectedTab" scrollable>
117+
<TabList>
118+
<Tab v-for="tab in get.tabs" :value="tab.kind" :disabled="tab.disabled">
119+
{{ tab.kind }}
120+
<span class="tabBadge">
121+
<Badge :value="tab.raw.length" :severity="tab.severity" />
122+
</span>
123+
</Tab>
124+
</TabList>
125+
<TabPanels>
126+
<TabPanel v-for="tab in get.tabs" :value="tab.kind">
127+
<ScrollPanel :dt="{ bar: { background: '{primary.color}' } }" :style="{ height: heightCodePanel }">
128+
<CodeBlock :snippets="tab.raw" :lang="tab.lang" />
129+
</ScrollPanel>
130+
</TabPanel>
131+
</TabPanels>
132+
</Tabs>
133+
</div>
134+
135+
</div>
136+
</template>
137+
138+
<style scoped>
139+
.tabBadge {
140+
vertical-align: super;
141+
--p-badge-padding: 0.2rem;
142+
--p-badge-font-size: normal;
143+
--p-badge-height: 1rem;
144+
--p-badge-min-width: 1.5rem;
145+
--p-badge-secondary-color: grey;
146+
}
147+
148+
.fileViewPanel {
149+
display: flex;
150+
}
151+
152+
.fileViewNavi {
153+
flex: 0 0 25%;
154+
padding-left: 0.25rem;
155+
padding-right: 0.5rem;
156+
/* flex-grow, flex-shrink, flex-basis */
157+
/* 左边div不扩展也不收缩,基础宽度为10% */
158+
}
159+
160+
.fileViewMenu {
161+
flex: 1;
162+
height: 92vh;
163+
/* 允许不含空格的单词在任何地方换行 */
164+
word-break: break-all;
165+
font-size: smaller;
166+
}
167+
168+
.fileViewResult {
169+
flex: 1;
170+
overflow-x: auto;
171+
overflow-y: auto;
172+
padding: 0rem 0.5rem 0rem 1rem;
173+
/* 控制代码块容器的 padding: 上、右、下、左 */
174+
--p-tabs-tabpanel-padding: 0.35rem 0rem 0 0;
175+
/* 右边div占据剩余空间 */
176+
/* 可以省略flex-grow为1,因为默认值就是1 */
177+
178+
/* 选中标签页的底部块的高度 */
179+
--p-tabs-active-bar-height: 3.2px;
180+
}
181+
182+
.btn {
183+
height: 2.4rem;
184+
}
185+
</style>

os-checks/components/Print.vue

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script setup lang="ts">
2+
import Button from 'primevue/button';
3+
import type { CheckerResult, FileTree } from '~/shared/file-tree';
4+
import type { Get } from '~/shared/file-tree/utils';
5+
6+
type Props = {
7+
get: Get, tmp: string,
8+
tabs: CheckerResult[],
9+
selectedTab: string,
10+
fileTree: FileTree,
11+
};
12+
const props = defineProps<Props>();
13+
14+
watch(() => props.get, val => console.log("Print", val));
15+
watch(() => props.fileTree, val => console.log("Print fileTree", val));
16+
</script>
17+
18+
<template>
19+
<Button>{{ props.tmp }}</Button>
20+
<div>
21+
fileTree.data.length: {{ props.fileTree.data.length }}
22+
</div>
23+
<div>
24+
tabs: {{ props.tabs }}
25+
</div>
26+
<div>
27+
selectedTab: {{ props.selectedTab }}
28+
</div>
29+
30+
{{ props.get }}
31+
</template>

os-checks/components/TargetDropDown.vue

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,14 @@ function fetch() {
4343
});
4444
}
4545
46-
function change(path: string, params: any) {
47-
// console.log("path =", path);
48-
const excludes = ["/", "/repos", "/charts", "/target", "/workflows", "/testcases"];
49-
if (excludes.findIndex(p => p === path) !== -1) {
50-
visible.value = false;
51-
return;
52-
} else if (params) {
53-
// console.log("path =", path);
46+
function change(path: string, _params: any) {
47+
const includes = ["/diagnostics"];
48+
if (includes.findIndex(p => p === path) !== -1) {
49+
visible.value = true;
5450
fetch();
51+
} else {
52+
visible.value = false;
5553
}
56-
visible.value = true;
5754
}
5855
</script>
5956

os-checks/package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

os-checks/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"chart.js": "^4.4.5",
1616
"chartjs-plugin-datalabels": "^2.2.0",
1717
"dompurify": "^3.1.7",
18+
"es-toolkit": "^1.32.0",
1819
"highlight.js": "^11.10.0",
1920
"nuxt": "^3.13.2",
2021
"ofetch": "^1.4.1",

0 commit comments

Comments
 (0)