mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-10-15 20:59:18 +00:00
build: migrate the build tool from vue-cli to vite4 (#208)
This commit is contained in:
@@ -34,48 +34,48 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import TaskList from "./components/TaskList.vue";
|
||||
import SegmentList from "./components/SegmentList.vue";
|
||||
import SpanTree from "./components/SpanTree.vue";
|
||||
import StackTable from "./components/Stack/Index.vue";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import { ref } from "vue";
|
||||
import TaskList from "./components/TaskList.vue";
|
||||
import SegmentList from "./components/SegmentList.vue";
|
||||
import SpanTree from "./components/SpanTree.vue";
|
||||
import StackTable from "./components/Stack/Index.vue";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
const profileStore = useProfileStore();
|
||||
const loading = ref<boolean>(false);
|
||||
const profileStore = useProfileStore();
|
||||
|
||||
function loadTrees(l: boolean) {
|
||||
loading.value = l;
|
||||
}
|
||||
function loadTrees(l: boolean) {
|
||||
loading.value = l;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
height: calc(100% - 30px);
|
||||
width: 100%;
|
||||
}
|
||||
.content {
|
||||
height: calc(100% - 30px);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.item {
|
||||
height: 100%;
|
||||
flex-grow: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
.item {
|
||||
height: 100%;
|
||||
flex-grow: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.list {
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
}
|
||||
.list {
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.thread-stack {
|
||||
padding: 5px;
|
||||
height: calc(50% - 20px);
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
.thread-stack {
|
||||
padding: 5px;
|
||||
height: calc(50% - 20px);
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.t-loading {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: calc(50% - 20px);
|
||||
}
|
||||
.t-loading {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: calc(50% - 20px);
|
||||
}
|
||||
</style>
|
||||
|
@@ -27,114 +27,103 @@ limitations under the License. -->
|
||||
@query="searchEndpoints"
|
||||
/>
|
||||
</div>
|
||||
<el-button
|
||||
class="search-btn"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="searchTasks"
|
||||
>
|
||||
<el-button class="search-btn" size="small" type="primary" @click="searchTasks">
|
||||
{{ t("search") }}
|
||||
</el-button>
|
||||
<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"
|
||||
>
|
||||
<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 { useProfileStore } from "@/store/modules/profile";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { ElMessage } from "element-plus";
|
||||
import NewTask from "./components/NewTask.vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { EntityType } from "../../data";
|
||||
import { ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { ElMessage } from "element-plus";
|
||||
import NewTask from "./components/NewTask.vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { EntityType } from "../../data";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
needQuery: { type: Boolean, default: true },
|
||||
});
|
||||
const profileStore = useProfileStore();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { t } = useI18n();
|
||||
const endpointName = ref<string>("");
|
||||
const newTask = ref<boolean>(false);
|
||||
|
||||
if (props.needQuery) {
|
||||
searchTasks();
|
||||
searchEndpoints("");
|
||||
}
|
||||
|
||||
async function searchEndpoints(keyword: string) {
|
||||
if (!selectorStore.currentService) {
|
||||
return;
|
||||
}
|
||||
const service = selectorStore.currentService.id;
|
||||
const res = await profileStore.getEndpoints(service, keyword);
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
}
|
||||
endpointName.value = profileStore.endpoints[0].value;
|
||||
}
|
||||
|
||||
function changeEndpoint(opt: any[]) {
|
||||
endpointName.value = opt[0].value;
|
||||
}
|
||||
|
||||
async function searchTasks() {
|
||||
profileStore.setConditions({
|
||||
serviceId:
|
||||
(selectorStore.currentService && selectorStore.currentService.id) || "",
|
||||
endpointName: endpointName.value,
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
needQuery: { type: Boolean, default: true },
|
||||
});
|
||||
const res = await profileStore.getTaskList();
|
||||
const profileStore = useProfileStore();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { t } = useI18n();
|
||||
const endpointName = ref<string>("");
|
||||
const newTask = ref<boolean>(false);
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
|
||||
function createTask() {
|
||||
newTask.value = true;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => selectorStore.currentService,
|
||||
() => {
|
||||
if (props.needQuery) {
|
||||
searchTasks();
|
||||
console.log("service");
|
||||
searchEndpoints("");
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => appStore.durationTime,
|
||||
() => {
|
||||
if (dashboardStore.entity === EntityType[1].value) {
|
||||
searchTasks();
|
||||
|
||||
async function searchEndpoints(keyword: string) {
|
||||
if (!selectorStore.currentService) {
|
||||
return;
|
||||
}
|
||||
const service = selectorStore.currentService.id;
|
||||
const res = await profileStore.getEndpoints(service, keyword);
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
}
|
||||
endpointName.value = profileStore.endpoints[0].value;
|
||||
}
|
||||
|
||||
function changeEndpoint(opt: any[]) {
|
||||
endpointName.value = opt[0].value;
|
||||
}
|
||||
|
||||
async function searchTasks() {
|
||||
profileStore.setConditions({
|
||||
serviceId: (selectorStore.currentService && selectorStore.currentService.id) || "",
|
||||
endpointName: endpointName.value,
|
||||
});
|
||||
const res = await profileStore.getTaskList();
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function createTask() {
|
||||
newTask.value = true;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => selectorStore.currentService,
|
||||
() => {
|
||||
searchTasks();
|
||||
console.log("service");
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => appStore.durationTime,
|
||||
() => {
|
||||
if (dashboardStore.entity === EntityType[1].value) {
|
||||
searchTasks();
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.header {
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
}
|
||||
.header {
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 270px;
|
||||
}
|
||||
.name {
|
||||
width: 270px;
|
||||
}
|
||||
</style>
|
||||
|
@@ -31,19 +31,9 @@ limitations under the License. -->
|
||||
<div>
|
||||
<div class="label">{{ t("monitorTime") }}</div>
|
||||
<div>
|
||||
<Radio
|
||||
class="mb-5"
|
||||
:value="monitorTime"
|
||||
:options="InitTaskField.monitorTimeEn"
|
||||
@change="changeMonitorTime"
|
||||
/>
|
||||
<Radio class="mb-5" :value="monitorTime" :options="InitTaskField.monitorTimeEn" @change="changeMonitorTime" />
|
||||
<span class="date">
|
||||
<TimePicker
|
||||
:value="time"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
@input="changeTimeRange"
|
||||
/>
|
||||
<TimePicker :value="time" position="bottom" format="YYYY-MM-DD HH:mm:ss" @input="changeTimeRange" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -58,21 +48,11 @@ limitations under the License. -->
|
||||
</div>
|
||||
<div>
|
||||
<div class="label">{{ t("minThreshold") }} (ms)</div>
|
||||
<el-input-number
|
||||
size="small"
|
||||
class="profile-input"
|
||||
:min="0"
|
||||
v-model="minThreshold"
|
||||
/>
|
||||
<el-input-number size="small" class="profile-input" :min="0" v-model="minThreshold" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="label">{{ t("dumpPeriod") }}</div>
|
||||
<Radio
|
||||
class="mb-5"
|
||||
:value="dumpPeriod"
|
||||
:options="InitTaskField.dumpPeriod"
|
||||
@change="changeDumpPeriod"
|
||||
/>
|
||||
<Radio class="mb-5" :value="dumpPeriod" :options="InitTaskField.dumpPeriod" @change="changeDumpPeriod" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="label">{{ t("maxSamplingCount") }}</div>
|
||||
@@ -93,110 +73,110 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { InitTaskField } from "./data";
|
||||
/* global defineEmits */
|
||||
const emits = defineEmits(["close"]);
|
||||
const profileStore = useProfileStore();
|
||||
const selectorStore = useSelectorStore();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const { t } = useI18n();
|
||||
const endpointName = ref<string>("");
|
||||
const monitorTime = ref<string>(InitTaskField.monitorTimeEn[0].value);
|
||||
const monitorDuration = ref<string>(InitTaskField.monitorDuration[0].value);
|
||||
const time = ref<Date>(appStore.durationRow.start);
|
||||
const minThreshold = ref<number>(0);
|
||||
const dumpPeriod = ref<string>(InitTaskField.dumpPeriod[0].value);
|
||||
const maxSamplingCount = ref<string>(InitTaskField.maxSamplingCount[0].value);
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { InitTaskField } from "./data";
|
||||
/* global defineEmits */
|
||||
const emits = defineEmits(["close"]);
|
||||
const profileStore = useProfileStore();
|
||||
const selectorStore = useSelectorStore();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const { t } = useI18n();
|
||||
const endpointName = ref<string>("");
|
||||
const monitorTime = ref<string>(InitTaskField.monitorTimeEn[0].value);
|
||||
const monitorDuration = ref<string>(InitTaskField.monitorDuration[0].value);
|
||||
const time = ref<Date>(appStore.durationRow.start);
|
||||
const minThreshold = ref<number>(0);
|
||||
const dumpPeriod = ref<string>(InitTaskField.dumpPeriod[0].value);
|
||||
const maxSamplingCount = ref<string>(InitTaskField.maxSamplingCount[0].value);
|
||||
|
||||
async function searchEndpoints(keyword: string) {
|
||||
if (!selectorStore.currentService) {
|
||||
return;
|
||||
async function searchEndpoints(keyword: string) {
|
||||
if (!selectorStore.currentService) {
|
||||
return;
|
||||
}
|
||||
const service = selectorStore.currentService.id;
|
||||
const res = await profileStore.getEndpoints(service, keyword);
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
}
|
||||
endpointName.value = profileStore.taskEndpoints[0].value;
|
||||
}
|
||||
const service = selectorStore.currentService.id;
|
||||
const res = await profileStore.getEndpoints(service, keyword);
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
function changeMonitorTime(opt: string) {
|
||||
monitorTime.value = opt;
|
||||
}
|
||||
endpointName.value = profileStore.taskEndpoints[0].value;
|
||||
}
|
||||
|
||||
function changeMonitorTime(opt: string) {
|
||||
monitorTime.value = opt;
|
||||
}
|
||||
|
||||
function changeMonitorDuration(val: string) {
|
||||
monitorDuration.value = val;
|
||||
}
|
||||
|
||||
function changeDumpPeriod(val: string) {
|
||||
dumpPeriod.value = val;
|
||||
}
|
||||
|
||||
function changeMaxSamplingCount(opt: any[]) {
|
||||
maxSamplingCount.value = opt[0].value;
|
||||
}
|
||||
|
||||
function changeEndpoint(opt: any[]) {
|
||||
endpointName.value = opt[0].value;
|
||||
}
|
||||
|
||||
async function createTask() {
|
||||
emits("close");
|
||||
const date = monitorTime.value === "0" ? new Date() : time.value;
|
||||
const params = {
|
||||
serviceId: selectorStore.currentService.id,
|
||||
endpointName: endpointName.value,
|
||||
startTime: date.getTime(),
|
||||
duration: Number(monitorDuration.value),
|
||||
minDurationThreshold: Number(minThreshold.value),
|
||||
dumpPeriod: Number(dumpPeriod.value),
|
||||
maxSamplingCount: Number(maxSamplingCount.value),
|
||||
};
|
||||
const res = await profileStore.createTask(params);
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
function changeMonitorDuration(val: string) {
|
||||
monitorDuration.value = val;
|
||||
}
|
||||
const { tip } = res.data;
|
||||
if (tip) {
|
||||
ElMessage.error(tip);
|
||||
return;
|
||||
|
||||
function changeDumpPeriod(val: string) {
|
||||
dumpPeriod.value = val;
|
||||
}
|
||||
|
||||
function changeMaxSamplingCount(opt: any[]) {
|
||||
maxSamplingCount.value = opt[0].value;
|
||||
}
|
||||
|
||||
function changeEndpoint(opt: any[]) {
|
||||
endpointName.value = opt[0].value;
|
||||
}
|
||||
|
||||
async function createTask() {
|
||||
emits("close");
|
||||
const date = monitorTime.value === "0" ? new Date() : time.value;
|
||||
const params = {
|
||||
serviceId: selectorStore.currentService.id,
|
||||
endpointName: endpointName.value,
|
||||
startTime: date.getTime(),
|
||||
duration: Number(monitorDuration.value),
|
||||
minDurationThreshold: Number(minThreshold.value),
|
||||
dumpPeriod: Number(dumpPeriod.value),
|
||||
maxSamplingCount: Number(maxSamplingCount.value),
|
||||
};
|
||||
const res = await profileStore.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");
|
||||
}
|
||||
function changeTimeRange(val: Date) {
|
||||
time.value = val;
|
||||
}
|
||||
ElMessage.success("Task created successfully");
|
||||
}
|
||||
function changeTimeRange(val: Date) {
|
||||
time.value = val;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.profile-task {
|
||||
margin: 0 auto;
|
||||
width: 400px;
|
||||
}
|
||||
.profile-task {
|
||||
margin: 0 auto;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 12px;
|
||||
}
|
||||
.date {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.label {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.profile-input {
|
||||
width: 300px;
|
||||
}
|
||||
.profile-input {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.create-task-btn {
|
||||
width: 300px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
.create-task-btn {
|
||||
width: 300px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
@@ -20,12 +20,7 @@ limitations under the License. -->
|
||||
{{ t("noData") }}
|
||||
</div>
|
||||
<table class="profile-t">
|
||||
<tr
|
||||
class="profile-tr cp"
|
||||
v-for="(i, index) in profileStore.segmentList"
|
||||
@click="selectTrace(i)"
|
||||
:key="index"
|
||||
>
|
||||
<tr class="profile-tr cp" v-for="(i, index) in profileStore.segmentList" @click="selectTrace(i)" :key="index">
|
||||
<td
|
||||
class="profile-td"
|
||||
:class="{
|
||||
@@ -52,103 +47,103 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import { Trace } from "@/types/trace";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { dateFormat } from "@/utils/dateFormat";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import type { Trace } from "@/types/trace";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { dateFormat } from "@/utils/dateFormat";
|
||||
|
||||
const { t } = useI18n();
|
||||
const profileStore = useProfileStore();
|
||||
const selectedKey = ref<string>("");
|
||||
const { t } = useI18n();
|
||||
const profileStore = useProfileStore();
|
||||
const selectedKey = ref<string>("");
|
||||
|
||||
async function selectTrace(item: Trace) {
|
||||
profileStore.setCurrentSegment(item);
|
||||
selectedKey.value = item.segmentId;
|
||||
const res = await profileStore.getSegmentSpans({ segmentId: item.segmentId });
|
||||
async function selectTrace(item: Trace) {
|
||||
profileStore.setCurrentSegment(item);
|
||||
selectedKey.value = item.segmentId;
|
||||
const res = await profileStore.getSegmentSpans({ segmentId: item.segmentId });
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.profile-trace-wrapper {
|
||||
width: 300px;
|
||||
height: 50%;
|
||||
overflow: auto;
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.profile-t-wrapper {
|
||||
.profile-trace-wrapper {
|
||||
width: 300px;
|
||||
height: 50%;
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.profile-t-loading {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
margin-top: 40px;
|
||||
line-height: 88px;
|
||||
overflow: hidden;
|
||||
.no-data {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
.profile-t-wrapper {
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.profile-t-loading {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
margin-top: 40px;
|
||||
line-height: 88px;
|
||||
overflow: hidden;
|
||||
|
||||
.icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-t {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.profile-tr {
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
}
|
||||
|
||||
.profile-td {
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
||||
|
||||
&.selected {
|
||||
background-color: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-t-tool {
|
||||
padding: 5px 10px;
|
||||
font-weight: bold;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.07);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
||||
background: #f3f4f9;
|
||||
}
|
||||
|
||||
.log-item {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.profile-btn {
|
||||
color: #3d444f;
|
||||
padding: 1px 3px;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-t {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
.profile-segment {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
|
||||
.profile-tr {
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
}
|
||||
|
||||
.profile-td {
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
||||
|
||||
&.selected {
|
||||
background-color: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-t-tool {
|
||||
padding: 5px 10px;
|
||||
font-weight: bold;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.07);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
||||
background: #f3f4f9;
|
||||
}
|
||||
|
||||
.log-item {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.profile-btn {
|
||||
color: #3d444f;
|
||||
padding: 1px 3px;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-segment {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
</style>
|
||||
|
@@ -38,10 +38,7 @@ limitations under the License. -->
|
||||
<div class="profile-table">
|
||||
<Table
|
||||
:data="profileStore.segmentSpans"
|
||||
:traceId="
|
||||
profileStore.currentSegment.traceIds &&
|
||||
profileStore.currentSegment.traceIds[0]
|
||||
"
|
||||
:traceId="profileStore.currentSegment.traceIds && profileStore.currentSegment.traceIds[0]"
|
||||
:showBtnDetail="true"
|
||||
headerType="profile"
|
||||
@select="selectSpan"
|
||||
@@ -50,132 +47,132 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import Table from "../../trace/components/Table/Index.vue";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import Selector from "@/components/Selector.vue";
|
||||
import { Span } from "@/types/trace";
|
||||
import { Option } from "@/types/app";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ProfileMode } from "./data";
|
||||
import { ref, computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import Table from "../../trace/components/Table/Index.vue";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import Selector from "@/components/Selector.vue";
|
||||
import type { Span } from "@/types/trace";
|
||||
import type { Option } from "@/types/app";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { ProfileMode } from "./data";
|
||||
|
||||
/* global defineEmits*/
|
||||
const emits = defineEmits(["loading"]);
|
||||
const { t } = useI18n();
|
||||
const profileStore = useProfileStore();
|
||||
const mode = ref<string>("include");
|
||||
const message = ref<string>("");
|
||||
const timeRange = ref<Array<{ start: number; end: number }>>([]);
|
||||
const traceId = ref<string>("");
|
||||
const traceIds = computed(() =>
|
||||
(profileStore.currentSegment.traceIds || []).map((id: string) => ({
|
||||
label: id,
|
||||
value: id,
|
||||
}))
|
||||
);
|
||||
/* global defineEmits*/
|
||||
const emits = defineEmits(["loading"]);
|
||||
const { t } = useI18n();
|
||||
const profileStore = useProfileStore();
|
||||
const mode = ref<string>("include");
|
||||
const message = ref<string>("");
|
||||
const timeRange = ref<Array<{ start: number; end: number }>>([]);
|
||||
const traceId = ref<string>("");
|
||||
const traceIds = computed(() =>
|
||||
(profileStore.currentSegment.traceIds || []).map((id: string) => ({
|
||||
label: id,
|
||||
value: id,
|
||||
})),
|
||||
);
|
||||
|
||||
function selectSpan(span: Span) {
|
||||
profileStore.setCurrentSpan(span);
|
||||
}
|
||||
|
||||
function spanModeChange(item: Option[]) {
|
||||
mode.value = item[0].value;
|
||||
updateTimeRange();
|
||||
}
|
||||
|
||||
function changeTraceId(opt: Option[]) {
|
||||
traceId.value = opt[0].value;
|
||||
}
|
||||
|
||||
async function analyzeProfile() {
|
||||
emits("loading", true);
|
||||
updateTimeRange();
|
||||
const res = await profileStore.getProfileAnalyze({
|
||||
segmentId: profileStore.currentSegment.segmentId,
|
||||
timeRanges: timeRange.value,
|
||||
});
|
||||
emits("loading", false);
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
function selectSpan(span: Span) {
|
||||
profileStore.setCurrentSpan(span);
|
||||
}
|
||||
if (res.tip) {
|
||||
message.value = res.tip;
|
||||
|
||||
function spanModeChange(item: Option[]) {
|
||||
mode.value = item[0].value;
|
||||
updateTimeRange();
|
||||
}
|
||||
}
|
||||
|
||||
function updateTimeRange() {
|
||||
if (mode.value === "include") {
|
||||
timeRange.value = [
|
||||
{
|
||||
start: profileStore.currentSpan.startTime,
|
||||
end: profileStore.currentSpan.endTime,
|
||||
},
|
||||
];
|
||||
} else {
|
||||
const { children, startTime, endTime } = profileStore.currentSpan;
|
||||
let dateRange = [];
|
||||
function changeTraceId(opt: Option[]) {
|
||||
traceId.value = opt[0].value;
|
||||
}
|
||||
|
||||
if (!children || !children.length) {
|
||||
async function analyzeProfile() {
|
||||
emits("loading", true);
|
||||
updateTimeRange();
|
||||
const res = await profileStore.getProfileAnalyze({
|
||||
segmentId: profileStore.currentSegment.segmentId,
|
||||
timeRanges: timeRange.value,
|
||||
});
|
||||
emits("loading", false);
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
if (res.tip) {
|
||||
message.value = res.tip;
|
||||
}
|
||||
}
|
||||
|
||||
function updateTimeRange() {
|
||||
if (mode.value === "include") {
|
||||
timeRange.value = [
|
||||
{
|
||||
start: startTime,
|
||||
end: endTime,
|
||||
start: profileStore.currentSpan.startTime,
|
||||
end: profileStore.currentSpan.endTime,
|
||||
},
|
||||
];
|
||||
return;
|
||||
}
|
||||
for (const item of children) {
|
||||
dateRange.push(
|
||||
{
|
||||
start: startTime,
|
||||
end: item.startTime,
|
||||
},
|
||||
{
|
||||
start: item.endTime,
|
||||
end: endTime,
|
||||
}
|
||||
);
|
||||
}
|
||||
dateRange = dateRange.reduce((prev: any[], cur) => {
|
||||
let isUpdate = false;
|
||||
for (const item of prev) {
|
||||
if (cur.start <= item.end && item.start <= cur.start) {
|
||||
isUpdate = true;
|
||||
item.start = item.start < cur.start ? cur.start : item.start;
|
||||
item.end = item.end < cur.end ? item.end : cur.end;
|
||||
}
|
||||
} else {
|
||||
const { children, startTime, endTime } = profileStore.currentSpan;
|
||||
let dateRange = [];
|
||||
|
||||
if (!children || !children.length) {
|
||||
timeRange.value = [
|
||||
{
|
||||
start: startTime,
|
||||
end: endTime,
|
||||
},
|
||||
];
|
||||
return;
|
||||
}
|
||||
if (!isUpdate) {
|
||||
prev.push(cur);
|
||||
for (const item of children) {
|
||||
dateRange.push(
|
||||
{
|
||||
start: startTime,
|
||||
end: item.startTime,
|
||||
},
|
||||
{
|
||||
start: item.endTime,
|
||||
end: endTime,
|
||||
},
|
||||
);
|
||||
}
|
||||
return prev;
|
||||
}, []);
|
||||
timeRange.value = dateRange.filter((item: any) => item.start !== item.end);
|
||||
dateRange = dateRange.reduce((prev: any[], cur) => {
|
||||
let isUpdate = false;
|
||||
for (const item of prev) {
|
||||
if (cur.start <= item.end && item.start <= cur.start) {
|
||||
isUpdate = true;
|
||||
item.start = item.start < cur.start ? cur.start : item.start;
|
||||
item.end = item.end < cur.end ? item.end : cur.end;
|
||||
}
|
||||
}
|
||||
if (!isUpdate) {
|
||||
prev.push(cur);
|
||||
}
|
||||
return prev;
|
||||
}, []);
|
||||
timeRange.value = dateRange.filter((item: any) => item.start !== item.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.profile-trace-dashboard {
|
||||
padding: 5px;
|
||||
flex-shrink: 0;
|
||||
height: 50%;
|
||||
width: 100%;
|
||||
min-width: 800px;
|
||||
}
|
||||
.profile-trace-dashboard {
|
||||
padding: 5px;
|
||||
flex-shrink: 0;
|
||||
height: 50%;
|
||||
width: 100%;
|
||||
min-width: 800px;
|
||||
}
|
||||
|
||||
.profile-table {
|
||||
height: calc(100% - 30px);
|
||||
overflow: auto;
|
||||
}
|
||||
.profile-table {
|
||||
height: calc(100% - 30px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.profile-trace-detail-wrapper {
|
||||
padding: 5px 0;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
width: 100%;
|
||||
}
|
||||
.profile-trace-detail-wrapper {
|
||||
padding: 5px 0;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.profile-trace-detail-ids {
|
||||
width: 300px;
|
||||
}
|
||||
.profile-trace-detail-ids {
|
||||
width: 300px;
|
||||
}
|
||||
</style>
|
||||
|
@@ -36,93 +36,88 @@ limitations under the License. -->
|
||||
</div>
|
||||
<div class="dump-count">Dump Count</div>
|
||||
</div>
|
||||
<TableItem
|
||||
:thread="thread"
|
||||
v-for="(item, index) in tableData"
|
||||
:data="item"
|
||||
:key="'key' + index"
|
||||
/>
|
||||
<TableItem :thread="thread" v-for="(item, index) in tableData" :data="item" :key="'key' + index" />
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import { ref, onMounted } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import TableItem from "./Item.vue";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import { ref, onMounted } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import TableItem from "./Item.vue";
|
||||
|
||||
/* global defineProps */
|
||||
defineProps({
|
||||
tableData: { type: Array as PropType<any>, default: () => [] },
|
||||
highlightTop: { type: Boolean, default: false },
|
||||
});
|
||||
const dragger = ref<any>(null);
|
||||
const thread = ref<number>(500);
|
||||
const profileStore = useProfileStore();
|
||||
/* global defineProps */
|
||||
defineProps({
|
||||
tableData: { type: Array as PropType<any>, default: () => [] },
|
||||
highlightTop: { type: Boolean, default: false },
|
||||
});
|
||||
const dragger = ref<any>(null);
|
||||
const thread = ref<number>(500);
|
||||
const profileStore = useProfileStore();
|
||||
|
||||
onMounted(() => {
|
||||
dragger.value.onmousedown = (event: any) => {
|
||||
const diffX = event.clientX;
|
||||
const copy = thread.value;
|
||||
document.onmousemove = (documentEvent) => {
|
||||
const moveX = documentEvent.clientX - diffX;
|
||||
thread.value = copy + moveX;
|
||||
onMounted(() => {
|
||||
dragger.value.onmousedown = (event: any) => {
|
||||
const diffX = event.clientX;
|
||||
const copy = thread.value;
|
||||
document.onmousemove = (documentEvent) => {
|
||||
const moveX = documentEvent.clientX - diffX;
|
||||
thread.value = copy + moveX;
|
||||
};
|
||||
document.onmouseup = () => {
|
||||
document.onmousemove = null;
|
||||
document.onmouseup = null;
|
||||
};
|
||||
};
|
||||
document.onmouseup = () => {
|
||||
document.onmousemove = null;
|
||||
document.onmouseup = null;
|
||||
};
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
function updateHighlightTop() {
|
||||
profileStore.setHighlightTop();
|
||||
}
|
||||
function updateHighlightTop() {
|
||||
profileStore.setHighlightTop();
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "./profile.scss";
|
||||
@import "./profile.scss";
|
||||
|
||||
.dragger {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.profile {
|
||||
font-size: 12px;
|
||||
height: 100%;
|
||||
|
||||
.profile-set-btn {
|
||||
font-size: 12px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
width: 57px;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 3px;
|
||||
padding: 0 3px;
|
||||
.dragger {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-header {
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.profile {
|
||||
font-size: 12px;
|
||||
height: 100%;
|
||||
|
||||
.profile-header div {
|
||||
display: inline-block;
|
||||
padding: 0 4px;
|
||||
border-right: 1px dotted silver;
|
||||
line-height: 30px;
|
||||
background-color: #f3f4f9;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.profile-set-btn {
|
||||
font-size: 12px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
width: 57px;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 3px;
|
||||
padding: 0 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-header {
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.profile-header div {
|
||||
display: inline-block;
|
||||
padding: 0 4px;
|
||||
border-right: 1px dotted silver;
|
||||
line-height: 30px;
|
||||
background-color: #f3f4f9;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
|
@@ -21,89 +21,86 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ref, onMounted, watch } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import Container from "./Container.vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ref, onMounted, watch } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import Container from "./Container.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
/* global defineProps */
|
||||
const props = defineProps({
|
||||
data: { type: Array as PropType<any>, default: () => [] },
|
||||
highlightTop: { type: Boolean, default: false },
|
||||
});
|
||||
const tableData = ref<any>([]);
|
||||
const { t } = useI18n();
|
||||
/* global defineProps */
|
||||
const props = defineProps({
|
||||
data: { type: Array as PropType<any>, default: () => [] },
|
||||
highlightTop: { type: Boolean, default: false },
|
||||
});
|
||||
const tableData = ref<any>([]);
|
||||
|
||||
onMounted(() => {
|
||||
tableData.value = processTree();
|
||||
});
|
||||
function processTree() {
|
||||
if (!props.data.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const durationChildExcluded = props.data
|
||||
.map((d: any) => {
|
||||
return d.elements.map((item: any) => item.durationChildExcluded);
|
||||
})
|
||||
.flat(1);
|
||||
function compare(val: number, val1: number) {
|
||||
return val1 - val;
|
||||
}
|
||||
const topDur = durationChildExcluded
|
||||
.sort(compare)
|
||||
.filter((item: any, index: number) => index < 10 && item !== 0);
|
||||
const trees = [];
|
||||
|
||||
for (const item of props.data) {
|
||||
const newArr = sortArr(item.elements, topDur);
|
||||
trees.push(...newArr);
|
||||
}
|
||||
|
||||
return trees;
|
||||
}
|
||||
|
||||
function sortArr(arr: any[], topDur: any) {
|
||||
const copyArr = JSON.parse(JSON.stringify(arr));
|
||||
const obj: any = {};
|
||||
const res = [];
|
||||
for (const item of copyArr) {
|
||||
obj[item.id] = item;
|
||||
}
|
||||
for (const item of copyArr) {
|
||||
item.topDur =
|
||||
topDur.includes(item.durationChildExcluded) && props.highlightTop;
|
||||
if (item.parentId === "0") {
|
||||
res.push(item);
|
||||
onMounted(() => {
|
||||
tableData.value = processTree();
|
||||
});
|
||||
function processTree() {
|
||||
if (!props.data.length) {
|
||||
return [];
|
||||
}
|
||||
for (const key in obj) {
|
||||
if (item.id === obj[key].parentId) {
|
||||
if (item.children) {
|
||||
item.children.push(obj[key]);
|
||||
} else {
|
||||
item.children = [obj[key]];
|
||||
|
||||
const durationChildExcluded = props.data
|
||||
.map((d: any) => {
|
||||
return d.elements.map((item: any) => item.durationChildExcluded);
|
||||
})
|
||||
.flat(1);
|
||||
function compare(val: number, val1: number) {
|
||||
return val1 - val;
|
||||
}
|
||||
const topDur = durationChildExcluded.sort(compare).filter((item: any, index: number) => index < 10 && item !== 0);
|
||||
const trees = [];
|
||||
|
||||
for (const item of props.data) {
|
||||
const newArr = sortArr(item.elements, topDur);
|
||||
trees.push(...newArr);
|
||||
}
|
||||
|
||||
return trees;
|
||||
}
|
||||
|
||||
function sortArr(arr: any[], topDur: any) {
|
||||
const copyArr = JSON.parse(JSON.stringify(arr));
|
||||
const obj: any = {};
|
||||
const res = [];
|
||||
for (const item of copyArr) {
|
||||
obj[item.id] = item;
|
||||
}
|
||||
for (const item of copyArr) {
|
||||
item.topDur = topDur.includes(item.durationChildExcluded) && props.highlightTop;
|
||||
if (item.parentId === "0") {
|
||||
res.push(item);
|
||||
}
|
||||
for (const key in obj) {
|
||||
if (item.id === obj[key].parentId) {
|
||||
if (item.children) {
|
||||
item.children.push(obj[key]);
|
||||
} else {
|
||||
item.children = [obj[key]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.data, props.highlightTop],
|
||||
() => {
|
||||
if (!props.data.length) {
|
||||
tableData.value = [];
|
||||
return;
|
||||
}
|
||||
tableData.value = processTree();
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => [props.data, props.highlightTop],
|
||||
() => {
|
||||
if (!props.data.length) {
|
||||
tableData.value = [];
|
||||
return;
|
||||
}
|
||||
tableData.value = processTree();
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.profile-detail-chart-table {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.profile-detail-chart-table {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
@@ -14,10 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
:class="['profile-item', 'level' + data.parentId]"
|
||||
:style="{ color: data.topDur ? '#448dfe' : '#3d444f' }"
|
||||
>
|
||||
<div :class="['profile-item', 'level' + data.parentId]" :style="{ color: data.topDur ? '#448dfe' : '#3d444f' }">
|
||||
<div
|
||||
:class="['thread', 'level' + data.parentId]"
|
||||
:style="{
|
||||
@@ -42,112 +39,104 @@ limitations under the License. -->
|
||||
<div class="exec-ms">{{ data.durationChildExcluded }}</div>
|
||||
<div class="dump-count">{{ data.count }}</div>
|
||||
</div>
|
||||
<div
|
||||
v-show="data.children && data.children.length && displayChildren"
|
||||
class="children-trace"
|
||||
>
|
||||
<table-item
|
||||
:thread="thread"
|
||||
v-for="(item, index) in data.children"
|
||||
:key="index"
|
||||
:data="item"
|
||||
/>
|
||||
<div v-show="data.children && data.children.length && displayChildren" class="children-trace">
|
||||
<table-item :thread="thread" v-for="(item, index) in data.children" :key="index" :data="item" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { ref, defineComponent, toRefs } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { ref, defineComponent, toRefs } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
const props = {
|
||||
data: { type: Object as PropType<any>, default: () => ({}) },
|
||||
thread: { type: Number, default: 0 },
|
||||
};
|
||||
export default defineComponent({
|
||||
name: "TableItem",
|
||||
props,
|
||||
setup(props) {
|
||||
const displayChildren = ref<boolean>(true);
|
||||
function toggle() {
|
||||
displayChildren.value = !displayChildren.value;
|
||||
}
|
||||
return { toggle, displayChildren, ...toRefs(props) };
|
||||
},
|
||||
});
|
||||
const props = {
|
||||
data: { type: Object as PropType<any>, default: () => ({}) },
|
||||
thread: { type: Number, default: 0 },
|
||||
};
|
||||
export default defineComponent({
|
||||
name: "TableItem",
|
||||
props,
|
||||
setup(props) {
|
||||
const displayChildren = ref<boolean>(true);
|
||||
function toggle() {
|
||||
displayChildren.value = !displayChildren.value;
|
||||
}
|
||||
return { toggle, displayChildren, ...toRefs(props) };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "./profile.scss";
|
||||
@import "./profile.scss";
|
||||
|
||||
.profile-item.level0 {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
color: #448dfe;
|
||||
|
||||
&:hover {
|
||||
.profile-item.level0 {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
color: #448dfe;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
color: #448dfe;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
background: #448dfe;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
background: #448dfe;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-item {
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.profile-item.selected {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.profile-item:not(.level0):hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.profile-item > div {
|
||||
display: inline-block;
|
||||
padding: 0 5px;
|
||||
border: 1px solid transparent;
|
||||
border-right: 1px dotted silver;
|
||||
overflow: hidden;
|
||||
line-height: 30px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.profile-item > div.method {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.profile-item div.exec-percent {
|
||||
width: 10%;
|
||||
height: 30px;
|
||||
padding: 0 8px;
|
||||
|
||||
.outer-progress_bar {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
background: rgb(63, 177, 227);
|
||||
.profile-item {
|
||||
position: relative;
|
||||
margin-top: 11px;
|
||||
border: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.inner-progress_bar {
|
||||
position: absolute;
|
||||
background: rgb(110, 64, 170);
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
left: 0;
|
||||
border: none;
|
||||
top: 1px;
|
||||
.profile-item.selected {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.profile-item:not(.level0):hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.profile-item > div {
|
||||
display: inline-block;
|
||||
padding: 0 5px;
|
||||
border: 1px solid transparent;
|
||||
border-right: 1px dotted silver;
|
||||
overflow: hidden;
|
||||
line-height: 30px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.profile-item > div.method {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.profile-item div.exec-percent {
|
||||
width: 10%;
|
||||
height: 30px;
|
||||
padding: 0 8px;
|
||||
|
||||
.outer-progress_bar {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
background: rgb(63, 177, 227);
|
||||
position: relative;
|
||||
margin-top: 11px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.inner-progress_bar {
|
||||
position: absolute;
|
||||
background: rgb(110, 64, 170);
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
left: 0;
|
||||
border: none;
|
||||
top: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -21,12 +21,7 @@ limitations under the License. -->
|
||||
{{ t("noData") }}
|
||||
</div>
|
||||
<table class="profile-t">
|
||||
<tr
|
||||
class="profile-tr cp"
|
||||
v-for="(i, index) in profileStore.taskList"
|
||||
@click="changeTask(i)"
|
||||
:key="index"
|
||||
>
|
||||
<tr class="profile-tr cp" v-for="(i, index) in profileStore.taskList" @click="changeTask(i)" :key="index">
|
||||
<td
|
||||
class="profile-td"
|
||||
:class="{
|
||||
@@ -53,12 +48,7 @@ limitations under the License. -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog
|
||||
v-model="viewDetail"
|
||||
:destroy-on-close="true"
|
||||
fullscreen
|
||||
@closed="viewDetail = false"
|
||||
>
|
||||
<el-dialog v-model="viewDetail" :destroy-on-close="true" fullscreen @closed="viewDetail = false">
|
||||
<div class="profile-detail flex-v">
|
||||
<div>
|
||||
<h5 class="mb-10">{{ t("task") }}.</h5>
|
||||
@@ -82,9 +72,7 @@ limitations under the License. -->
|
||||
</div>
|
||||
<div class="mb-10 clear item">
|
||||
<span class="g-sm-4 grey">{{ t("minThreshold") }}:</span>
|
||||
<span class="g-sm-8 wba">
|
||||
{{ selectedTask.minDurationThreshold }} ms
|
||||
</span>
|
||||
<span class="g-sm-8 wba"> {{ selectedTask.minDurationThreshold }} ms </span>
|
||||
</div>
|
||||
<div class="mb-10 clear item">
|
||||
<span class="g-sm-4 grey">{{ t("dumpPeriod") }}:</span>
|
||||
@@ -96,17 +84,8 @@ limitations under the License. -->
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h5
|
||||
class="mb-10 mt-10"
|
||||
v-show="selectedTask.logs && selectedTask.logs.length"
|
||||
>
|
||||
{{ t("logs") }}.
|
||||
</h5>
|
||||
<div
|
||||
class="log-item"
|
||||
v-for="(i, index) in Object.keys(instanceLogs)"
|
||||
:key="index"
|
||||
>
|
||||
<h5 class="mb-10 mt-10" v-show="selectedTask.logs && selectedTask.logs.length"> {{ t("logs") }}. </h5>
|
||||
<div class="log-item" v-for="(i, index) in Object.keys(instanceLogs)" :key="index">
|
||||
<div class="mb-10 sm">
|
||||
<span class="mr-10 grey">{{ t("instance") }}:</span>
|
||||
<span>{{ i }}</span>
|
||||
@@ -123,127 +102,123 @@ limitations under the License. -->
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import { TaskLog, TaskListItem } from "@/types/profile";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { dateFormat } from "@/utils/dateFormat";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useProfileStore } from "@/store/modules/profile";
|
||||
import type { TaskLog, TaskListItem } from "@/types/profile";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { dateFormat } from "@/utils/dateFormat";
|
||||
|
||||
const { t } = useI18n();
|
||||
const profileStore = useProfileStore();
|
||||
const selectorStore = useSelectorStore();
|
||||
const viewDetail = ref<boolean>(false);
|
||||
const service = ref<string>("");
|
||||
const selectedTask = ref<TaskListItem | Record<string, never>>({});
|
||||
const instanceLogs = ref<TaskLog | any>({});
|
||||
const { t } = useI18n();
|
||||
const profileStore = useProfileStore();
|
||||
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) {
|
||||
profileStore.setCurrentSegment({});
|
||||
selectedTask.value = item;
|
||||
const res = await profileStore.getSegmentList({ taskID: item.id });
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
|
||||
async function viewTask(e: Event, item: TaskListItem) {
|
||||
window.event ? (window.event.cancelBubble = true) : e.stopPropagation();
|
||||
viewDetail.value = true;
|
||||
selectedTask.value = item;
|
||||
service.value = (
|
||||
selectorStore.services.filter((s: any) => s.id === item.serviceId)[0] || {}
|
||||
).label;
|
||||
const res = await profileStore.getTaskLogs({ taskID: item.id });
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
}
|
||||
item.logs = profileStore.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 },
|
||||
];
|
||||
async function changeTask(item: TaskListItem) {
|
||||
profileStore.setCurrentSegment({});
|
||||
selectedTask.value = item;
|
||||
const res = await profileStore.getSegmentList({ taskID: item.id });
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
selectedTask.value = item;
|
||||
}
|
||||
|
||||
async function viewTask(e: Event, item: TaskListItem) {
|
||||
window.event ? (window.event.cancelBubble = true) : e.stopPropagation();
|
||||
viewDetail.value = true;
|
||||
selectedTask.value = item;
|
||||
service.value = (selectorStore.services.filter((s: any) => s.id === item.serviceId)[0] || {}).label;
|
||||
const res = await profileStore.getTaskLogs({ taskID: item.id });
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
}
|
||||
item.logs = profileStore.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 }];
|
||||
}
|
||||
}
|
||||
selectedTask.value = 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 rgba(0, 0, 0, 0.07);
|
||||
|
||||
&.selected {
|
||||
background-color: #ededed;
|
||||
.profile-task-list {
|
||||
width: 300px;
|
||||
height: calc((100% - 60px) / 2);
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.profile-t-wrapper {
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.profile-t {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.profile-tr {
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
.item span {
|
||||
height: 21px;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-segment {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
.profile-td {
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
||||
|
||||
.profile-t-tool {
|
||||
padding: 5px 10px;
|
||||
font-weight: bold;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.07);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
||||
background: #f3f4f9;
|
||||
}
|
||||
&.selected {
|
||||
background-color: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
.log-item {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.no-data {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.profile-btn {
|
||||
color: #3d444f;
|
||||
padding: 1px 3px;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
float: right;
|
||||
}
|
||||
.profile-t-wrapper {
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.profile-t {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.profile-tr {
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
}
|
||||
|
||||
.profile-segment {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
|
||||
.profile-t-tool {
|
||||
padding: 5px 10px;
|
||||
font-weight: bold;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.07);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
||||
background: #f3f4f9;
|
||||
}
|
||||
|
||||
.log-item {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.profile-btn {
|
||||
color: #3d444f;
|
||||
padding: 1px 3px;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
float: right;
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user