add filters

This commit is contained in:
Qiuxia Fan 2022-04-20 17:48:55 +08:00
parent 70aec8f345
commit 20f49e6e21
6 changed files with 135 additions and 10 deletions

View File

@ -58,7 +58,7 @@ const props = defineProps({
}, },
size: { type: null, default: "default" }, size: { type: null, default: "default" },
placeholder: { placeholder: {
type: [String, Number] as PropType<string | number>, type: [String, undefined] as PropType<string>,
default: "Select a option", default: "Select a option",
}, },
borderRadius: { type: Number, default: 3 }, borderRadius: { type: Number, default: 3 },

2
src/types/ebpf.d.ts vendored
View File

@ -43,7 +43,7 @@ export interface EBPFProfilingSchedule {
startTime: number; startTime: number;
} }
type Process = { export type Process = {
id: string; id: string;
name: string; name: string;
serviceId: string; serviceId: string;

View File

@ -15,7 +15,7 @@ limitations under the License. -->
<template> <template>
<div class="flex-h content"> <div class="flex-h content">
<TaskList /> <TaskList />
<div class="vis-graph"> <div class="vis-graph ml-5">
<EBPFSchedules /> <EBPFSchedules />
<EBPFTree /> <EBPFTree />
</div> </div>

View File

@ -15,7 +15,7 @@ limitations under the License. -->
<template> <template>
<div class="flex-h header"> <div class="flex-h header">
<div>eBPF Profile</div> <div>eBPF Profile</div>
<el-button class="new-btn" size="small" @click="createTask"> <el-button type="primary" size="small" @click="createTask">
{{ t("newTask") }} {{ t("newTask") }}
</el-button> </el-button>
</div> </div>
@ -83,9 +83,10 @@ watch(
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.header { .header {
padding: 10px; padding: 5px 20px 5px 10px;
font-size: 12px; font-size: 12px;
border-bottom: 1px solid #dcdfe6; border-bottom: 1px solid #dcdfe6;
justify-content: space-between;
} }
.name { .name {

View File

@ -13,32 +13,145 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<div class="filters">
<Selector
:value="selectedLabels"
:options="labels"
size="small"
placeholder="Please select labels"
@change="changeLabels"
class="inputs mr-10"
:multiple="true"
/>
<el-popover placement="bottom" :width="680" trigger="click">
<template #reference>
<el-button type="primary" size="small">
Click to select processes
</el-button>
</template>
<el-table
:data="processes"
ref="multipleTableRef"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column
v-for="(h, index) of TableHeader"
:property="h.property"
:label="h.label"
:key="index"
width="150"
/>
<el-table-column width="300" label="Attributes">
<template #default="scope">
{{ scope.row.attributes.map((d: any) => `${d.name}=${d.value}`).join("; ") }}
</template>
</el-table-column>
</el-table>
</el-popover>
<el-button type="primary" size="small" @click="analyzeEBPF">
{{ t("analyze") }}
</el-button>
</div>
<div ref="timeline" class="schedules"></div> <div ref="timeline" class="schedules"></div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { useI18n } from "vue-i18n";
import { Option } from "@/types/app";
import { TableHeader } from "./data";
import { useEbpfStore } from "@/store/modules/ebpf"; import { useEbpfStore } from "@/store/modules/ebpf";
import { EBPFProfilingSchedule } from "@/types/ebpf"; import { EBPFProfilingSchedule, Process } from "@/types/ebpf";
import { DataSet, Timeline } from "vis-timeline/standalone"; import { DataSet, Timeline } from "vis-timeline/standalone";
import "vis-timeline/styles/vis-timeline-graph2d.css"; import "vis-timeline/styles/vis-timeline-graph2d.css";
import type { ElTable } from "element-plus";
const { t } = useI18n();
const ebpfStore = useEbpfStore(); const ebpfStore = useEbpfStore();
/*global Nullable */ /*global Nullable */
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
const selectedProcesses = ref<string[]>([]);
const timeline = ref<Nullable<HTMLDivElement>>(null); const timeline = ref<Nullable<HTMLDivElement>>(null);
const visGraph = ref<Nullable<any>>(null); const visGraph = ref<Nullable<any>>(null);
const labels = ref<Option[]>([{ label: "All", value: "0" }]);
const processes = ref<Process[]>([]);
const selectedLabels = ref<string[]>(["0"]);
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") => const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
dayjs(date).format(pattern); dayjs(date).format(pattern);
function changeLabels(opt: any[]) {
const arr = opt.map((d) => d.value);
// if (arr.includes("0")) {
// selectedLabels.value = labels.value.map((d: Option) => d.value);
// return;
// }
// selectedLabels.value = Array.from(new Set(arr));
selectedLabels.value = arr;
}
const handleSelectionChange = (arr: Process[]) => {
selectedProcesses.value = arr.map((d: Process) => d.id);
};
async function analyzeEBPF() {
let arr: string[] = [];
if (selectedLabels.value.includes("0")) {
arr = labels.value.map((d: Option) => d.value);
arr.pop();
}
console.log(arr);
const ranges: { start: number; end: number }[] = [];
const scheduleIdList = ebpfStore.eBPFSchedules.flatMap(
(d: EBPFProfilingSchedule) => {
const l = d.process.labels.find((d: string) => arr.includes(d));
const i = selectedLabels.value.includes(d.process.id);
if (l || i) {
ranges.push({
start: d.startTime,
end: d.endTime,
});
return d.scheduleId;
}
}
);
let timeRanges: { start: number; end: number }[] = [];
for (const r of ranges) {
if (timeRanges.length) {
for (const t of timeRanges) {
if (r.start > t.start && r.start < t.end) {
if (r.end > t.end) {
t.end = r.end;
}
}
}
} else {
timeRanges.push(r);
}
}
const res = await ebpfStore.getEBPFAnalyze({
scheduleIdList,
timeRanges,
});
}
function visTimeline() { function visTimeline() {
if (visGraph.value) { if (visGraph.value) {
visGraph.value.destroy(); visGraph.value.destroy();
} }
labels.value = [{ label: "All", value: "0" }];
processes.value = [];
const schedules = ebpfStore.eBPFSchedules.map( const schedules = ebpfStore.eBPFSchedules.map(
(d: EBPFProfilingSchedule, index: number) => { (d: EBPFProfilingSchedule, index: number) => {
for (const l of d.process.labels) {
labels.value.push({ label: l, value: l });
}
processes.value.push(d.process);
return { return {
id: index + 1, id: index + 1,
content: "schedule" + index, content: d.process.name,
start: dateFormat(d.startTime), start: dateFormat(d.startTime),
end: dateFormat(d.endTime), end: dateFormat(d.endTime),
}; };
@ -46,8 +159,7 @@ function visTimeline() {
); );
const items: any = new DataSet(schedules); const items: any = new DataSet(schedules);
const options = { const options = {
editable: true, height: 250,
selectable: true,
}; };
if (!timeline.value) { if (!timeline.value) {
return; return;
@ -63,8 +175,16 @@ watch(
); );
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.filters {
margin: 5px 0;
}
.schedules { .schedules {
width: 100%; width: 100%;
height: 400px; margin: 0 5px 5px 0;
}
.inputs {
width: 300px;
} }
</style> </style>

View File

@ -45,3 +45,7 @@ export const InitTaskField = {
{ value: "15", label: "15 min" }, { value: "15", label: "15 min" },
], ],
}; };
export const TableHeader = [
{ property: "name", label: "Name" },
{ property: "instanceName", label: "Instance Name" },
];