build: migrate the build tool from vue-cli to vite4 (#208)

This commit is contained in:
Fine0830
2022-12-17 14:07:03 +08:00
committed by GitHub
parent 1e0c253488
commit 44dcb1e7f6
214 changed files with 27014 additions and 54234 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>