mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-13 00:08:56 +00:00
add task list
This commit is contained in:
parent
ede8f1cd82
commit
f3894d2bff
@ -149,3 +149,38 @@ export const EditStrategy = {
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const GetAsyncTaskList = {
|
||||||
|
variable: "$request: AsyncProfilerTaskListRequest!",
|
||||||
|
query: `
|
||||||
|
asyncTaskList: queryAsyncProfilerTaskList(request: $request) {
|
||||||
|
errorReason
|
||||||
|
tasks {
|
||||||
|
id
|
||||||
|
serviceId
|
||||||
|
serviceInstanceIds
|
||||||
|
createTime
|
||||||
|
events
|
||||||
|
duration
|
||||||
|
execArgs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GetAsyncProfileTaskProcess = {
|
||||||
|
variable: "$taskID: String",
|
||||||
|
query: `
|
||||||
|
taskLogs: queryAsyncProfilerTaskProgress(taskID: $taskID) {
|
||||||
|
logs {
|
||||||
|
id
|
||||||
|
instanceId
|
||||||
|
instanceName
|
||||||
|
operationType
|
||||||
|
operationTime
|
||||||
|
}
|
||||||
|
errorInstanceIds
|
||||||
|
successInstanceIds
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
@ -23,6 +23,8 @@ import {
|
|||||||
GetProfileTaskLogs,
|
GetProfileTaskLogs,
|
||||||
GetStrategyList,
|
GetStrategyList,
|
||||||
EditStrategy,
|
EditStrategy,
|
||||||
|
GetAsyncTaskList,
|
||||||
|
GetAsyncProfileTaskProcess,
|
||||||
} from "../fragments/profile";
|
} from "../fragments/profile";
|
||||||
|
|
||||||
export const saveProfileTask = `mutation createProfileTask(${CreateProfileTask.variable}) {${CreateProfileTask.query}}`;
|
export const saveProfileTask = `mutation createProfileTask(${CreateProfileTask.variable}) {${CreateProfileTask.query}}`;
|
||||||
@ -40,3 +42,7 @@ export const getProfileTaskLogs = `query profileTaskLogs(${GetProfileTaskLogs.va
|
|||||||
export const getStrategyList = `query getStrategyList(${GetStrategyList.variable}) {${GetStrategyList.query}}`;
|
export const getStrategyList = `query getStrategyList(${GetStrategyList.variable}) {${GetStrategyList.query}}`;
|
||||||
|
|
||||||
export const editStrategy = `mutation editStrategy(${EditStrategy.variable}) {${EditStrategy.query}}`;
|
export const editStrategy = `mutation editStrategy(${EditStrategy.variable}) {${EditStrategy.query}}`;
|
||||||
|
|
||||||
|
export const getAsyncTaskList = `query getAsyncTaskList(${GetAsyncTaskList.variable}) {${GetAsyncTaskList.query}}`;
|
||||||
|
|
||||||
|
export const getAsyncProfileTaskProcess = `query getAsyncProfileTaskProcess(${GetAsyncProfileTaskProcess.variable}) {${GetAsyncProfileTaskProcess.query}}`;
|
||||||
|
75
src/store/modules/async-profiling.ts
Normal file
75
src/store/modules/async-profiling.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
import type { Option } from "@/types/app";
|
||||||
|
import type { AsyncProfilingTaskList } from "@/types/async-profiling";
|
||||||
|
import { store } from "@/store";
|
||||||
|
import graphql from "@/graphql";
|
||||||
|
import type { AxiosResponse } from "axios";
|
||||||
|
|
||||||
|
interface AsyncProfilingState {
|
||||||
|
taskList: Array<Recordable<AsyncProfilingTaskList>>;
|
||||||
|
labels: Option[];
|
||||||
|
asyncProfilingTips: string;
|
||||||
|
selectedTask: Recordable<AsyncProfilingTaskList>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const asyncProfilingStore = defineStore({
|
||||||
|
id: "asyncProfiling",
|
||||||
|
state: (): AsyncProfilingState => ({
|
||||||
|
taskList: [],
|
||||||
|
labels: [{ value: "", label: "" }],
|
||||||
|
asyncProfilingTips: "",
|
||||||
|
selectedTask: {},
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
setSelectedTask(task: Recordable<AsyncProfilingTaskList>) {
|
||||||
|
this.selectedTask = task || {};
|
||||||
|
},
|
||||||
|
async getTaskList(params: { serviceId: string; targets: string[] }) {
|
||||||
|
if (!params.serviceId) {
|
||||||
|
return new Promise((resolve) => resolve({}));
|
||||||
|
}
|
||||||
|
const res: AxiosResponse = await graphql.query("getAsyncTaskList").params(params);
|
||||||
|
|
||||||
|
this.asyncProfilingTips = "";
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.taskList = res.data.data.asyncTaskList || [];
|
||||||
|
this.selectedTask = this.taskList[0] || {};
|
||||||
|
this.setSelectedTask(this.selectedTask);
|
||||||
|
if (!this.taskList.length) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getTaskLogs(param: { taskID: string }) {
|
||||||
|
const res: AxiosResponse = await graphql.query("getAsyncProfileTaskProcess").params(param);
|
||||||
|
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.taskLogs = res.data.data.taskLogs;
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useAsyncProfilingStore(): Recordable {
|
||||||
|
return asyncProfilingStore(store);
|
||||||
|
}
|
26
src/types/async-profiling.ts
Normal file
26
src/types/async-profiling.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type AsyncProfilingTaskList = {
|
||||||
|
id: string;
|
||||||
|
serviceId: string;
|
||||||
|
serviceInstanceIds: string[];
|
||||||
|
createTime: number;
|
||||||
|
events: string;
|
||||||
|
duration: number;
|
||||||
|
execArgs: string;
|
||||||
|
};
|
@ -0,0 +1,177 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div class="profile-task-list flex-v">
|
||||||
|
<div class="profile-task-wrapper flex-v">
|
||||||
|
<div class="profile-t-tool flex-h">{{ t("taskList") }}</div>
|
||||||
|
<div class="profile-t-wrapper">
|
||||||
|
<div class="no-data" v-show="!asyncProfilingStore.taskList.length">
|
||||||
|
{{ t("noData") }}
|
||||||
|
</div>
|
||||||
|
<table class="profile-t">
|
||||||
|
<tr
|
||||||
|
class="profile-tr cp"
|
||||||
|
v-for="(i, index) in asyncProfilingStore.taskList"
|
||||||
|
@click="changeTask(i)"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<td
|
||||||
|
class="profile-td"
|
||||||
|
:class="{
|
||||||
|
selected: asyncProfilingStore.currentTask && asyncProfilingStore.currentTask.id === i.id,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="ell">
|
||||||
|
<span>{{ i.endpointName }}</span>
|
||||||
|
<a class="profile-btn r" @click="viewTask($event, i)">
|
||||||
|
<Icon iconName="view" size="middle" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="grey ell sm">
|
||||||
|
<span class="mr-10 sm">
|
||||||
|
{{ dateFormat(i.startTime) }}
|
||||||
|
</span>
|
||||||
|
<span class="mr-10 sm">
|
||||||
|
{{ dateFormat(i.startTime + i.duration * 60 * 1000) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
|
||||||
|
import type { TaskLog, TaskListItem } from "@/types/profile";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { dateFormat } from "@/utils/dateFormat";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const asyncProfilingStore = useAsyncProfilingStore();
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
|
const viewDetail = ref<boolean>(false);
|
||||||
|
const service = ref<string>("");
|
||||||
|
// const selectedTask = ref<TaskListItem | Record<string, never>>({});
|
||||||
|
const instanceLogs = ref<TaskLog | any>({});
|
||||||
|
|
||||||
|
async function changeTask(item: TaskListItem) {
|
||||||
|
asyncProfilingStore.setCurrentSegment({});
|
||||||
|
asyncProfilingStore.setCurrentTask(item);
|
||||||
|
const res = await asyncProfilingStore.getSegmentList({ taskID: item.id });
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function viewTask(e: Event, item: TaskListItem) {
|
||||||
|
e.stopPropagation();
|
||||||
|
viewDetail.value = true;
|
||||||
|
asyncProfilingStore.setCurrentTask(item);
|
||||||
|
service.value = (selectorStore.services.filter((s: any) => s.id === item.serviceId)[0] || {}).label;
|
||||||
|
const res = await asyncProfilingStore.getTaskLogs({ taskID: item.id });
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item.logs = asyncProfilingStore.taskLogs;
|
||||||
|
instanceLogs.value = {};
|
||||||
|
for (const d of item.logs) {
|
||||||
|
if (instanceLogs.value[d.instanceName]) {
|
||||||
|
instanceLogs.value[d.instanceName].push({
|
||||||
|
operationType: d.operationType,
|
||||||
|
operationTime: d.operationTime,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
instanceLogs.value[d.instanceName] = [{ operationType: d.operationType, operationTime: d.operationTime }];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
asyncProfilingStore.setCurrentTask(item);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.profile-task-list {
|
||||||
|
width: 300px;
|
||||||
|
height: calc((100% - 60px) / 2);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item span {
|
||||||
|
height: 21px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-td {
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-bottom: 1px solid var(--sw-trace-list-border);
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: var(--sw-list-selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-t-wrapper {
|
||||||
|
overflow: auto;
|
||||||
|
flex-grow: 1;
|
||||||
|
border-right: 1px solid var(--sw-trace-list-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-t {
|
||||||
|
width: 100%;
|
||||||
|
border-spacing: 0;
|
||||||
|
table-layout: fixed;
|
||||||
|
flex-grow: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tr {
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--sw-list-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-segment {
|
||||||
|
border-top: 1px solid var(--sw-trace-list-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-t-tool {
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-right: 1px solid var(--sw-trace-list-border);
|
||||||
|
border-bottom: 1px solid var(--sw-trace-list-border);
|
||||||
|
background-color: var(--sw-table-header);
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-item {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-btn {
|
||||||
|
color: $font-color;
|
||||||
|
padding: 1px 3px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: $font-size-smaller;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user