mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-12 15:52:57 +00:00
new task
This commit is contained in:
parent
bdf12cee62
commit
5044f2988c
@ -184,3 +184,14 @@ export const GetAsyncProfileTaskProcess = {
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const CreateAsyncProfileTask = {
|
||||
variable: "$asyncProfilerTaskCreationRequest: AsyncProfilerTaskCreationRequest!",
|
||||
query: `
|
||||
task: createAsyncProfilerTask(asyncProfilerTaskCreationRequest: $asyncProfilerTaskCreationRequest) {
|
||||
id
|
||||
errorReason
|
||||
code
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
@ -25,6 +25,7 @@ import {
|
||||
EditStrategy,
|
||||
GetAsyncTaskList,
|
||||
GetAsyncProfileTaskProcess,
|
||||
CreateAsyncProfileTask,
|
||||
} from "../fragments/profile";
|
||||
|
||||
export const saveProfileTask = `mutation createProfileTask(${CreateProfileTask.variable}) {${CreateProfileTask.query}}`;
|
||||
@ -46,3 +47,5 @@ export const editStrategy = `mutation editStrategy(${EditStrategy.variable}) {${
|
||||
export const getAsyncTaskList = `query getAsyncTaskList(${GetAsyncTaskList.variable}) {${GetAsyncTaskList.query}}`;
|
||||
|
||||
export const getAsyncProfileTaskProcess = `query getAsyncProfileTaskProcess(${GetAsyncProfileTaskProcess.variable}) {${GetAsyncProfileTaskProcess.query}}`;
|
||||
|
||||
export const saveAsyncProfileTask = `mutation createAsyncProfileTask(${CreateAsyncProfileTask.variable}) {${CreateAsyncProfileTask.query}}`;
|
||||
|
@ -390,5 +390,8 @@ const msg = {
|
||||
mappingTip: "Notice: The mapping key is a Regex string, e.g. ^([0-9])$",
|
||||
valueDashboard: "Data Value Related Dashboard",
|
||||
viewValueDashboard: "View Dashboard",
|
||||
errorInstances: "Error Instances",
|
||||
successInstances: "Success Instances",
|
||||
profilingEvents: "Async Profiling Events",
|
||||
};
|
||||
export default msg;
|
||||
|
@ -390,5 +390,8 @@ const msg = {
|
||||
mappingTip: "Aviso: La clave de mapeo es una cadena Regex, p. ej. ^([0-9])$",
|
||||
valueDashboard: "Data Value Related Dashboard",
|
||||
viewValueDashboard: "View Dashboard",
|
||||
errorInstances: "Error Instances",
|
||||
successInstances: "Success Instances",
|
||||
profilingEvents: "Async Profiling Events",
|
||||
};
|
||||
export default msg;
|
||||
|
@ -388,5 +388,8 @@ const msg = {
|
||||
mappingTip: "注意: 映射键是一个正则表达式字符串,比如 ^([0-9])$",
|
||||
valueDashboard: "数据值相关的仪表板",
|
||||
viewValueDashboard: "查看仪表板",
|
||||
errorInstances: "错误的实例",
|
||||
successInstances: "成功的实例",
|
||||
profilingEvents: "异步分析事件",
|
||||
};
|
||||
export default msg;
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
import { defineStore } from "pinia";
|
||||
import type { Option } from "@/types/app";
|
||||
import type { AsyncProfilingTaskList } from "@/types/async-profiling";
|
||||
import type { AsyncProfilingTaskList, AsyncProfileTaskCreationRequest } from "@/types/async-profiling";
|
||||
import { store } from "@/store";
|
||||
import graphql from "@/graphql";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
@ -46,11 +46,11 @@ export const asyncProfilingStore = defineStore({
|
||||
setSelectedTask(task: Recordable<AsyncProfilingTaskList>) {
|
||||
this.selectedTask = task || {};
|
||||
},
|
||||
async getTaskList(params: { serviceId: string; targets: string[] }) {
|
||||
async getTaskList(params: { serviceId: string; startTime: number; endTime: number }) {
|
||||
if (!params.serviceId) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
const res: AxiosResponse = await graphql.query("getAsyncTaskList").params(params);
|
||||
const res: AxiosResponse = await graphql.query("getAsyncTaskList").params({ ...params, limit: 10000 });
|
||||
|
||||
this.asyncProfilingTips = "";
|
||||
if (res.data.errors) {
|
||||
@ -87,6 +87,17 @@ export const asyncProfilingStore = defineStore({
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
async createTask(param: AsyncProfileTaskCreationRequest) {
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("saveAsyncProfileTask")
|
||||
.params({ asyncProfilerTaskCreationRequest: param });
|
||||
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.getTaskList();
|
||||
return res.data;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -24,3 +24,11 @@ export type AsyncProfilingTaskList = {
|
||||
duration: number;
|
||||
execArgs: string;
|
||||
};
|
||||
|
||||
export type AsyncProfileTaskCreationRequest = {
|
||||
serviceId: string;
|
||||
serviceInstanceIds: string[];
|
||||
duration: number;
|
||||
events: string[];
|
||||
execArgs: string;
|
||||
};
|
||||
|
2
src/types/components.d.ts
vendored
2
src/types/components.d.ts
vendored
@ -12,6 +12,8 @@ declare module 'vue' {
|
||||
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
|
@ -25,6 +25,7 @@ limitations under the License. -->
|
||||
<span>{{ t("delete") }}</span>
|
||||
</div>
|
||||
</el-popover>
|
||||
<Header :needQuery="needQuery" />
|
||||
<Content :config="props.data" />
|
||||
</div>
|
||||
</template>
|
||||
@ -33,6 +34,7 @@ limitations under the License. -->
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import Content from "../related/async-profiling/Content.vue";
|
||||
import Header from "../related/async-profiling/Header.vue";
|
||||
|
||||
/*global defineProps*/
|
||||
const props = defineProps({
|
||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="flex-h content">
|
||||
<div>Tasks</div>
|
||||
<TaskList />
|
||||
<div class="vis-graph ml-5">Profiling</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -25,6 +25,7 @@ limitations under the License. -->
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
|
||||
import TaskList from "./components/TaskList.vue";
|
||||
|
||||
const asyncProfilingStore = useAsyncProfilingStore();
|
||||
|
||||
|
102
src/views/dashboard/related/async-profiling/Header.vue
Normal file
102
src/views/dashboard/related/async-profiling/Header.vue
Normal file
@ -0,0 +1,102 @@
|
||||
<!-- 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="flex-h header">
|
||||
<el-input
|
||||
v-model="keywords"
|
||||
style="width: 240px"
|
||||
placeholder="Please input create time to search"
|
||||
@change="searchTasks()"
|
||||
>
|
||||
<template #append>
|
||||
<el-button size="small">
|
||||
<Icon size="sm" iconName="search" />
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button class="search-btn" size="small" @click="createTask">
|
||||
{{ t("newTask") }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-dialog v-model="newTask" :destroy-on-close="true" fullscreen @closed="newTask = false">
|
||||
<NewTask @close="newTask = false" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { EntityType } from "../../data";
|
||||
import NewTask from "./components/NewTask.vue";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
needQuery: { type: Boolean, default: true },
|
||||
});
|
||||
const asyncProfilingStore = useAsyncProfilingStore();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { t } = useI18n();
|
||||
const keywords = ref<string>("");
|
||||
const newTask = ref<boolean>(false);
|
||||
|
||||
if (props.needQuery) {
|
||||
searchTasks();
|
||||
}
|
||||
|
||||
async function searchTasks() {
|
||||
const res = await asyncProfilingStore.getTaskList({
|
||||
serviceId: selectorStore.currentService.id,
|
||||
});
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
|
||||
function createTask() {
|
||||
newTask.value = true;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => selectorStore.currentService,
|
||||
() => {
|
||||
searchTasks();
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => appStore.durationTime,
|
||||
() => {
|
||||
if (dashboardStore.entity === EntityType[1].value) {
|
||||
searchTasks();
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.header {
|
||||
padding: 10px;
|
||||
font-size: $font-size-smaller;
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 270px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,125 @@
|
||||
<!-- 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">
|
||||
<div>
|
||||
<div class="label">{{ t("instance") }}</div>
|
||||
<Selector
|
||||
class="profile-input"
|
||||
:multiple="true"
|
||||
:value="serviceInstanceIds"
|
||||
size="small"
|
||||
:options="asyncProfilingStore.instances"
|
||||
placeholder="Select instances"
|
||||
@change="changeInstances"
|
||||
:filterable="false"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="label">{{ t("duration") }}</div>
|
||||
<Radio class="mb-5" :value="duration" :options="DurationOptions" @change="changeDuration" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="label">{{ t("profilingEvents") }}</div>
|
||||
<el-checkbox-group v-model="asyncEvents" class="profile-input mb-5">
|
||||
<el-checkbox v-for="event in ProfilingEvents" :label="event.label" :value="event.value" :key="event.value" />
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
<div>
|
||||
<div class="label">{{ t("execArgs") }}</div>
|
||||
<el-input size="small" class="profile-input" v-model="execArgs" />
|
||||
</div>
|
||||
<div>
|
||||
<el-button @click="createTask" type="primary" class="create-task-btn">
|
||||
{{ t("createTask") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { ElMessage } from "element-plus";
|
||||
import type { Option } from "@/types/app";
|
||||
import { DurationOptions, ProfilingEvents } from "./data";
|
||||
|
||||
/* global defineEmits */
|
||||
const emits = defineEmits(["close"]);
|
||||
const asyncProfilingStore = useAsyncProfilingStore();
|
||||
const selectorStore = useSelectorStore();
|
||||
const { t } = useI18n();
|
||||
const serviceInstanceIds = ref<string[]>([]);
|
||||
const asyncEvents = ref<string[]>([ProfilingEvents[0].value]);
|
||||
const duration = ref<string>(DurationOptions[0].value);
|
||||
const execArgs = ref<string>("");
|
||||
|
||||
function changeDuration(val: string) {
|
||||
duration.value = val;
|
||||
}
|
||||
|
||||
function changeInstances(options: Option[]) {
|
||||
serviceInstanceIds.value = options.map((d: Option) => d.value);
|
||||
}
|
||||
|
||||
async function createTask() {
|
||||
emits("close");
|
||||
const params = {
|
||||
serviceId: selectorStore.currentService.id,
|
||||
serviceInstanceIds: serviceInstanceIds.value,
|
||||
duration: Number(duration.value),
|
||||
createTime: new Date().getTime(),
|
||||
events: asyncEvents.value,
|
||||
execArgs: execArgs.value,
|
||||
};
|
||||
const res = await asyncProfilingStore.createTask(params);
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
}
|
||||
const { tip } = res.data;
|
||||
if (tip) {
|
||||
ElMessage.error(tip);
|
||||
return;
|
||||
}
|
||||
ElMessage.success("Task created successfully");
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.profile-task {
|
||||
margin: 0 auto;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: $font-size-smaller;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-top: 10px;
|
||||
font-size: $font-size-normal;
|
||||
}
|
||||
|
||||
.profile-input {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.create-task-btn {
|
||||
width: 300px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
@ -103,7 +103,7 @@ limitations under the License. -->
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="mb-10 mt-10" v-show="errorInstances.length"> {{ t("errorInstanceIds") }}. </h5>
|
||||
<h5 class="mb-10 mt-10" v-show="errorInstances.length"> {{ t("errorInstances") }}. </h5>
|
||||
<div class="log-item" v-for="(instance, index) in errorInstances" :key="instance.value || index">
|
||||
<div class="mb-10 sm">
|
||||
<span class="mr-10 grey">{{ t("instance") }}:</span>
|
||||
@ -115,6 +115,19 @@ limitations under the License. -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="mb-10 mt-10" v-show="successInstances.length"> {{ t("successInstances") }}. </h5>
|
||||
<div class="log-item" v-for="(instance, index) in successInstances" :key="instance.value || index">
|
||||
<div class="mb-10 sm">
|
||||
<span class="mr-10 grey">{{ t("instance") }}:</span>
|
||||
<span>{{ instance.label }}</span>
|
||||
</div>
|
||||
<div v-for="(d, index) in instance.attributes" :key="d.value + index">
|
||||
<span class="mr-10 grey">{{ d.name }}:</span>
|
||||
<span class="mr-20">{{ d.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -138,6 +151,17 @@ limitations under the License. -->
|
||||
const errorInstances = ref<Instance[]>([]);
|
||||
const successInstances = ref<Instance[]>([]);
|
||||
|
||||
fetchTasks();
|
||||
|
||||
async function fetchTasks() {
|
||||
const res = await asyncProfilingStore.getTaskList({
|
||||
serviceId: selectorStore.currentService.id,
|
||||
});
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
|
||||
async function changeTask(item: TaskListItem) {
|
||||
asyncProfilingStore.setCurrentSegment({});
|
||||
asyncProfilingStore.setCurrentTask(item);
|
||||
|
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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 const DurationOptions = [
|
||||
{ value: "5", label: "5 min" },
|
||||
{ value: "10", label: "10 min" },
|
||||
{ value: "15", label: "15 min" },
|
||||
];
|
||||
|
||||
export const ProfilingEvents = [
|
||||
{ value: "CPU", label: "CPU" },
|
||||
{ value: "ALLOC", label: "ALLOC" },
|
||||
];
|
Loading…
Reference in New Issue
Block a user