mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-15 01:23:48 +00:00
Merge pull request #8 from pemeraldy/mod/filters-layout
Mod/filters layout
This commit is contained in:
commit
44f3763a54
@ -37,7 +37,7 @@ limitations under the License. -->
|
|||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch } from "vue";
|
import { ref, watch, onMounted } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
|
|
||||||
interface Option {
|
interface Option {
|
||||||
@ -95,4 +95,7 @@ watch(
|
|||||||
.el-input__inner {
|
.el-input__inner {
|
||||||
border-radius: unset !important;
|
border-radius: unset !important;
|
||||||
}
|
}
|
||||||
|
.el-input.el-input--small.el-input--suffix {
|
||||||
|
height: 18px !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -27,7 +27,8 @@ async function query(param: {
|
|||||||
{
|
{
|
||||||
cancelToken: cancelToken(),
|
cancelToken: cancelToken(),
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Basic c2t5d2Fsa2luZzpza3l3YWxraW5n",
|
Authorization:
|
||||||
|
"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJkZXZlbG9wZXJfaWQiOiJzeXN0ZW0iLCJjcmVhdGVkX2F0IjoxNjIyNDIxMzY0ODY4LCJleHBpcmVzX2F0IjoxNjUzOTU3MzY0ODY4LCJpYXQiOjE2MjI0MjEzNjR9.ZVHtxQkfCF7KM_dyDOgawbwpEAsmnCWB4c8I52svPvVc-SlzkEe0SYrNufNPniYZeM3IF0Gbojl_DSk2KleAz9CLRO3zfegciXKeEEvGjsNOqfQjgU5yZtBWmTimVXq5QoZMEGuAojACaf-m4J0H7o4LQNGwrDVA-noXVE0Eu84A5HxkjrRuFlQWv3fzqSRC_-lI0zRKuFGD-JkIfJ9b_wP_OjBWT6nmqkZn_JmK7UwniTUJjocszSA2Ma3XLx2xVPzBcz00QWyjhIyiftxNQzgqLl1XDVkRtzXUIrHnFCR8BcgR_PsqTBn5nH7aCp16zgmkkbOpmJXlNpDSVz9zUY4NOrB1jTzDB190COrfCXddb7JO6fmpet9_Zd3kInJx4XsT3x7JfBSWr9FBqFoUmNkgIWjkbN1TpwMyizXASp1nOmwJ64FDIbSpfpgUAqfSWXKZYhSisfnBLEyHCjMSPzVmDh949w-W1wU9q5nGFtrx6PTOxK_WKOiWU8_oeTjL0pD8pKXqJMaLW-OIzfrl3kzQNuF80YT-nxmNtp5PrcxehprlPmqSB_dyTHccsO3l63d8y9hiIzfRUgUjTJbktFn5t41ADARMs_0WMpIGZJyxcVssstt4J1Gj8WUFOdqPsIKigJZMn3yshC5S-KY-7S0dVd0VXgvpPqmpb9Q9Uho",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -56,7 +56,8 @@ class Graphql {
|
|||||||
{
|
{
|
||||||
cancelToken: cancelToken(),
|
cancelToken: cancelToken(),
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Basic c2t5d2Fsa2luZzpza3l3YWxraW5n",
|
Authorization:
|
||||||
|
"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJkZXZlbG9wZXJfaWQiOiJzeXN0ZW0iLCJjcmVhdGVkX2F0IjoxNjIyNDIxMzY0ODY4LCJleHBpcmVzX2F0IjoxNjUzOTU3MzY0ODY4LCJpYXQiOjE2MjI0MjEzNjR9.ZVHtxQkfCF7KM_dyDOgawbwpEAsmnCWB4c8I52svPvVc-SlzkEe0SYrNufNPniYZeM3IF0Gbojl_DSk2KleAz9CLRO3zfegciXKeEEvGjsNOqfQjgU5yZtBWmTimVXq5QoZMEGuAojACaf-m4J0H7o4LQNGwrDVA-noXVE0Eu84A5HxkjrRuFlQWv3fzqSRC_-lI0zRKuFGD-JkIfJ9b_wP_OjBWT6nmqkZn_JmK7UwniTUJjocszSA2Ma3XLx2xVPzBcz00QWyjhIyiftxNQzgqLl1XDVkRtzXUIrHnFCR8BcgR_PsqTBn5nH7aCp16zgmkkbOpmJXlNpDSVz9zUY4NOrB1jTzDB190COrfCXddb7JO6fmpet9_Zd3kInJx4XsT3x7JfBSWr9FBqFoUmNkgIWjkbN1TpwMyizXASp1nOmwJ64FDIbSpfpgUAqfSWXKZYhSisfnBLEyHCjMSPzVmDh949w-W1wU9q5nGFtrx6PTOxK_WKOiWU8_oeTjL0pD8pKXqJMaLW-OIzfrl3kzQNuF80YT-nxmNtp5PrcxehprlPmqSB_dyTHccsO3l63d8y9hiIzfRUgUjTJbktFn5t41ADARMs_0WMpIGZJyxcVssstt4J1Gj8WUFOdqPsIKigJZMn3yshC5S-KY-7S0dVd0VXgvpPqmpb9Q9Uho",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -269,6 +269,7 @@ const msg = {
|
|||||||
contentType: "Content Type",
|
contentType: "Content Type",
|
||||||
content: "Content",
|
content: "Content",
|
||||||
viewLogs: "View Logs",
|
viewLogs: "View Logs",
|
||||||
|
back: "Back",
|
||||||
logsTagsTip: `Only tags defined in the core/default/searchableLogsTags are searchable.
|
logsTagsTip: `Only tags defined in the core/default/searchableLogsTags are searchable.
|
||||||
Check more details on the Configuration Vocabulary page`,
|
Check more details on the Configuration Vocabulary page`,
|
||||||
keywordsOfContentLogTips:
|
keywordsOfContentLogTips:
|
||||||
|
@ -40,6 +40,8 @@ interface DashboardState {
|
|||||||
showTopology: boolean;
|
showTopology: boolean;
|
||||||
fullView: boolean;
|
fullView: boolean;
|
||||||
currentTabItems: LayoutConfig[];
|
currentTabItems: LayoutConfig[];
|
||||||
|
showTraceTools: boolean;
|
||||||
|
showLogTools: boolean;
|
||||||
dashboards: DashboardItem[];
|
dashboards: DashboardItem[];
|
||||||
currentDashboard: Nullable<DashboardItem>;
|
currentDashboard: Nullable<DashboardItem>;
|
||||||
editMode: boolean;
|
editMode: boolean;
|
||||||
@ -57,6 +59,8 @@ export const dashboardStore = defineStore({
|
|||||||
durationTime: useAppStoreWithOut().durationTime,
|
durationTime: useAppStoreWithOut().durationTime,
|
||||||
selectorStore: useSelectorStore(),
|
selectorStore: useSelectorStore(),
|
||||||
showTopology: false,
|
showTopology: false,
|
||||||
|
showLogTools: false,
|
||||||
|
showTraceTools: false,
|
||||||
fullView: false,
|
fullView: false,
|
||||||
currentTabItems: [],
|
currentTabItems: [],
|
||||||
dashboards: [],
|
dashboards: [],
|
||||||
@ -260,6 +264,12 @@ export const dashboardStore = defineStore({
|
|||||||
setEntity(type: string) {
|
setEntity(type: string) {
|
||||||
this.entity = type;
|
this.entity = type;
|
||||||
},
|
},
|
||||||
|
setTraceTools(show: boolean) {
|
||||||
|
this.showTraceTools = show;
|
||||||
|
},
|
||||||
|
setLogTools(show: boolean) {
|
||||||
|
this.showLogTools = show;
|
||||||
|
},
|
||||||
setTopology(show: boolean) {
|
setTopology(show: boolean) {
|
||||||
this.showTopology = show;
|
this.showTopology = show;
|
||||||
},
|
},
|
||||||
|
@ -29,6 +29,9 @@ interface TraceState {
|
|||||||
instances: Instance[];
|
instances: Instance[];
|
||||||
endpoints: Endpoint[];
|
endpoints: Endpoint[];
|
||||||
traceList: Trace[];
|
traceList: Trace[];
|
||||||
|
activeFilter: string;
|
||||||
|
displayMode: string;
|
||||||
|
currentView: string;
|
||||||
traceTotal: number;
|
traceTotal: number;
|
||||||
traceSpans: Span[];
|
traceSpans: Span[];
|
||||||
currentTrace: Trace | any;
|
currentTrace: Trace | any;
|
||||||
@ -48,6 +51,9 @@ export const traceStore = defineStore({
|
|||||||
services: [{ value: "0", label: "All" }],
|
services: [{ value: "0", label: "All" }],
|
||||||
instances: [{ value: "0", label: "All" }],
|
instances: [{ value: "0", label: "All" }],
|
||||||
endpoints: [{ value: "0", label: "All" }],
|
endpoints: [{ value: "0", label: "All" }],
|
||||||
|
displayMode: "List",
|
||||||
|
currentView: "traceList",
|
||||||
|
activeFilter: "",
|
||||||
traceList: [],
|
traceList: [],
|
||||||
traceSpans: [],
|
traceSpans: [],
|
||||||
traceTotal: 0,
|
traceTotal: 0,
|
||||||
@ -67,6 +73,16 @@ export const traceStore = defineStore({
|
|||||||
setTraceCondition(data: any) {
|
setTraceCondition(data: any) {
|
||||||
this.condition = { ...this.condition, ...data };
|
this.condition = { ...this.condition, ...data };
|
||||||
},
|
},
|
||||||
|
setDisplayMode(data: string) {
|
||||||
|
this.displayMode = data;
|
||||||
|
},
|
||||||
|
setCurrentView(data: string) {
|
||||||
|
this.currentView = data;
|
||||||
|
},
|
||||||
|
setActiveFilter(data: string) {
|
||||||
|
if (!data) this.activeFilter = "";
|
||||||
|
this.activeFilter = data;
|
||||||
|
},
|
||||||
setCurrentTrace(trace: Trace) {
|
setCurrentTrace(trace: Trace) {
|
||||||
this.currentTrace = trace;
|
this.currentTrace = trace;
|
||||||
},
|
},
|
||||||
|
3
src/types/components.d.ts
vendored
3
src/types/components.d.ts
vendored
@ -1,6 +1,7 @@
|
|||||||
// generated by unplugin-vue-components
|
// generated by unplugin-vue-components
|
||||||
// We suggest you to commit this file into source control
|
// We suggest you to commit this file into source control
|
||||||
// Read more: https://github.com/vuejs/vue-next/pull/3399
|
// Read more: https://github.com/vuejs/vue-next/pull/3399
|
||||||
|
import '@vue/runtime-core'
|
||||||
|
|
||||||
declare module '@vue/runtime-core' {
|
declare module '@vue/runtime-core' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
@ -45,4 +46,4 @@ declare module '@vue/runtime-core' {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { }
|
export {}
|
||||||
|
@ -14,12 +14,10 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="flex-h" :class="{ light: theme === 'light' }">
|
<div class="flex-h" :class="{ light: theme === 'light' }">
|
||||||
<div class="mr-5">
|
<div class="flex-h items-center mr-5">
|
||||||
<span class="sm grey" v-show="theme === 'dark'">{{ t("tags") }}: </span>
|
<span class="sm grey" v-show="theme === 'dark'">{{ t("tags") }}: </span>
|
||||||
<span
|
<span v-if="tagsList.length" class="trace-tags">
|
||||||
class="trace-tags"
|
<!-- :style="type === 'LOG' ? `min-width: 122px;` : ''" -->
|
||||||
:style="type === 'LOG' ? `min-width: 122px;` : ''"
|
|
||||||
>
|
|
||||||
<span class="selected" v-for="(item, index) in tagsList" :key="index">
|
<span class="selected" v-for="(item, index) in tagsList" :key="index">
|
||||||
<span>{{ item }}</span>
|
<span>{{ item }}</span>
|
||||||
<span class="remove-icon" @click="removeTags(index)">×</span>
|
<span class="remove-icon" @click="removeTags(index)">×</span>
|
||||||
@ -34,6 +32,7 @@ limitations under the License. -->
|
|||||||
/>
|
/>
|
||||||
<span class="tags-tip">
|
<span class="tags-tip">
|
||||||
<a
|
<a
|
||||||
|
v-if="false"
|
||||||
target="blank"
|
target="blank"
|
||||||
href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
|
href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
|
||||||
>
|
>
|
||||||
@ -54,17 +53,18 @@ limitations under the License. -->
|
|||||||
<Icon class="icon-help mr-5" iconName="help" size="middle" />
|
<Icon class="icon-help mr-5" iconName="help" size="middle" />
|
||||||
</span>
|
</span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<b v-if="type !== 'LOG'">{{ t("noticeTag") }}</b>
|
<!-- <b v-if="type !== 'LOG'">{{ t("noticeTag") }}</b> -->
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref, defineExpose } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
/*global defineEmits, defineProps */
|
/*global defineEmits, defineProps */
|
||||||
const emit = defineEmits(["update"]);
|
const emit = defineEmits(["update"]);
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
type: { type: String, default: "TRACE" },
|
type: { type: String, default: "TRACE" },
|
||||||
});
|
});
|
||||||
@ -73,6 +73,13 @@ const theme = ref<string>("dark");
|
|||||||
const tags = ref<string>("");
|
const tags = ref<string>("");
|
||||||
const tagsList = ref<string[]>([]);
|
const tagsList = ref<string[]>([]);
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
tagsList,
|
||||||
|
emptyTags
|
||||||
|
})
|
||||||
|
function emptyTags (){
|
||||||
|
tagsList.value = []
|
||||||
|
}
|
||||||
function removeTags(index: number) {
|
function removeTags(index: number) {
|
||||||
tagsList.value.splice(index, 1);
|
tagsList.value.splice(index, 1);
|
||||||
updateTags();
|
updateTags();
|
||||||
@ -97,6 +104,9 @@ function updateTags() {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
.trace-tags {
|
.trace-tags {
|
||||||
padding: 1px 5px 0 0;
|
padding: 1px 5px 0 0;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
@ -29,18 +29,17 @@ limitations under the License. -->
|
|||||||
<span>{{ t("delete") }}</span>
|
<span>{{ t("delete") }}</span>
|
||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<div class="header">
|
<!-- <div class="header">
|
||||||
<Header />
|
</div> -->
|
||||||
</div>
|
|
||||||
<div class="log">
|
<div class="log">
|
||||||
<List />
|
<List />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { onBeforeUnmount, onMounted } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import Header from "../related/log/Header.vue";
|
|
||||||
import List from "../related/log/List.vue";
|
import List from "../related/log/List.vue";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
@ -57,6 +56,12 @@ const dashboardStore = useDashboardStore();
|
|||||||
function removeWidget() {
|
function removeWidget() {
|
||||||
dashboardStore.removeControls(props.data);
|
dashboardStore.removeControls(props.data);
|
||||||
}
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
dashboardStore.setLogTools(true);
|
||||||
|
});
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
dashboardStore.setLogTools(false);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.log-wrapper {
|
.log-wrapper {
|
||||||
|
@ -147,14 +147,7 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import { ref, watch, onMounted, onBeforeUnmount, defineComponent, toRefs } from "vue";
|
||||||
ref,
|
|
||||||
watch,
|
|
||||||
onMounted,
|
|
||||||
onBeforeUnmount,
|
|
||||||
defineComponent,
|
|
||||||
toRefs,
|
|
||||||
} from "vue";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { LayoutConfig } from "@/types/dashboard";
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
@ -194,9 +187,7 @@ export default defineComponent({
|
|||||||
const currentItem = ref<number>(0);
|
const currentItem = ref<number>(0);
|
||||||
const isScrolling = ref(false);
|
const isScrolling = ref(false);
|
||||||
|
|
||||||
const l = dashboardStore.layout.findIndex(
|
const l = dashboardStore.layout.findIndex((d: LayoutConfig) => d.i === props.data.i);
|
||||||
(d: LayoutConfig) => d.i === props.data.i
|
|
||||||
);
|
|
||||||
if (dashboardStore.layout[l].children.length) {
|
if (dashboardStore.layout[l].children.length) {
|
||||||
dashboardStore.setCurrentTabItems(
|
dashboardStore.setCurrentTabItems(
|
||||||
dashboardStore.layout[l].children[activeTabIndex.value].children
|
dashboardStore.layout[l].children[activeTabIndex.value].children
|
||||||
@ -314,9 +305,7 @@ export default defineComponent({
|
|||||||
function clickTabGrid(e: Event, item: LayoutConfig) {
|
function clickTabGrid(e: Event, item: LayoutConfig) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
activeTabWidget.value = item.i;
|
activeTabWidget.value = item.i;
|
||||||
dashboardStore.activeGridItem(
|
dashboardStore.activeGridItem(`${props.data.i}-${activeTabIndex.value}-${item.i}`);
|
||||||
`${props.data.i}-${activeTabIndex.value}-${item.i}`
|
|
||||||
);
|
|
||||||
handleClick(e);
|
handleClick(e);
|
||||||
}
|
}
|
||||||
function layoutUpdatedEvent() {
|
function layoutUpdatedEvent() {
|
||||||
@ -484,7 +473,9 @@ export default defineComponent({
|
|||||||
color: #409eff;
|
color: #409eff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.tab-header .tabs .span.active {
|
||||||
|
color: red !important;
|
||||||
|
}
|
||||||
.operations {
|
.operations {
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -29,22 +29,19 @@ limitations under the License. -->
|
|||||||
<span>{{ t("delete") }}</span>
|
<span>{{ t("delete") }}</span>
|
||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<div class="header">
|
|
||||||
<Filter />
|
|
||||||
</div>
|
|
||||||
<div class="trace flex-h">
|
<div class="trace flex-h">
|
||||||
<TraceList />
|
<TraceList @show:trace="showTraceDetails" v-if="traceListActive" />
|
||||||
<TraceDetail />
|
<TraceDetail @show:list="showTraceList" v-if="!traceListActive" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from "vue";
|
import type { PropType, computed, onMounted, onBeforeUnmount } from "vue";
|
||||||
import Filter from "../related/trace/Filter.vue";
|
|
||||||
import TraceList from "../related/trace/TraceList.vue";
|
import TraceList from "../related/trace/TraceList.vue";
|
||||||
import TraceDetail from "../related/trace/Detail.vue";
|
import TraceDetail from "../related/trace/Detail.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import { useTraceStore } from "@/store/modules/trace";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -56,9 +53,26 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
const traceStore = useTraceStore();
|
||||||
|
const traceListActive = computed(() => {
|
||||||
|
return traceStore.currentView === "traceList";
|
||||||
|
});
|
||||||
function removeWidget() {
|
function removeWidget() {
|
||||||
dashboardStore.removeControls(props.data);
|
dashboardStore.removeControls(props.data);
|
||||||
}
|
}
|
||||||
|
function showTraceDetails() {
|
||||||
|
traceStore.currentView === "traceDetails";
|
||||||
|
}
|
||||||
|
function showTraceList() {
|
||||||
|
traceStore.currentView === "traceList";
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
dashboardStore.setTraceTools(true);
|
||||||
|
});
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
dashboardStore.setTraceTools(false);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.trace-wrapper {
|
.trace-wrapper {
|
||||||
@ -95,6 +109,7 @@ function removeWidget() {
|
|||||||
|
|
||||||
.trace {
|
.trace {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -15,115 +15,182 @@ limitations under the License. -->
|
|||||||
<template>
|
<template>
|
||||||
<div class="dashboard-tool flex-h">
|
<div class="dashboard-tool flex-h">
|
||||||
<div class="flex-h">
|
<div class="flex-h">
|
||||||
<div class="selectors-item" v-if="key !== 10">
|
<div class="flex-h">
|
||||||
<span class="label">$Service</span>
|
<div
|
||||||
<Selector
|
class="selectors-item"
|
||||||
v-model="states.currentService"
|
v-if="key !== 10 && currentTraceView === 'traceList'"
|
||||||
:options="selectorStore.services"
|
>
|
||||||
size="small"
|
<el-tooltip
|
||||||
placeholder="Select a service"
|
class="box-item"
|
||||||
@change="changeService"
|
effect="dark"
|
||||||
class="selectors"
|
content="Services"
|
||||||
/>
|
placement="top-start"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
v-if="!selectedSelector.length || selectedSelector === '$service'"
|
||||||
|
@click="setSelectedSelector('$service')"
|
||||||
|
class="tool-btn"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<Icon size="sm" iconName="playlist_add" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<Selector
|
||||||
|
v-if="selectedSelector === '$service'"
|
||||||
|
style="margin-left: 20px"
|
||||||
|
v-model="states.currentService"
|
||||||
|
:options="selectorStore.services"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a service"
|
||||||
|
@change="changeService"
|
||||||
|
class="selectors"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
style="margin-left: 4px"
|
||||||
|
v-if="selectedSelector === '$service'"
|
||||||
|
class="search-btn tool-btn"
|
||||||
|
size="small"
|
||||||
|
type="danger"
|
||||||
|
@click="closeSelector"
|
||||||
|
>
|
||||||
|
<Icon iconSize="sm" iconName="cancel" />
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="selectors-item"
|
||||||
|
v-if="(key === 3 || key === 4) && currentTraceView === 'traceList'"
|
||||||
|
>
|
||||||
|
<el-tooltip
|
||||||
|
v-if="!selectedSelector.length || selectedSelector === '$endpoint'"
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="Endpoint"
|
||||||
|
placement="top-start"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
style="margin-left: 4px"
|
||||||
|
@click="setSelectedSelector('$endpoint')"
|
||||||
|
class="tool-btn"
|
||||||
|
>
|
||||||
|
<Icon size="sm" iconName="view" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<Selector
|
||||||
|
v-if="selectedSelector === '$endpoint'"
|
||||||
|
style="margin-left: 20px"
|
||||||
|
v-model="states.currentPod"
|
||||||
|
:options="selectorStore.pods"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a data"
|
||||||
|
@change="changePods"
|
||||||
|
@query="searchPods"
|
||||||
|
class="selectorPod"
|
||||||
|
:isRemote="
|
||||||
|
['EndpointRelation', 'Endpoint'].includes(dashboardStore.entity)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
style="margin-left: 4px"
|
||||||
|
v-if="selectedSelector === '$endpoint'"
|
||||||
|
class="search-btn"
|
||||||
|
size="small"
|
||||||
|
type="danger"
|
||||||
|
@click="closeSelector"
|
||||||
|
>
|
||||||
|
<Icon iconSize="sm" iconName="cancel" />
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="selectors-item" v-if="key === 2 || key === 4">
|
||||||
|
<span class="label">$DestinationService</span>
|
||||||
|
<Selector
|
||||||
|
v-model="states.currentDestService"
|
||||||
|
:options="selectorStore.destServices"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a service"
|
||||||
|
@change="changeDestService"
|
||||||
|
class="selectors"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="selectors-item" v-if="key === 4">
|
||||||
|
<span class="label">
|
||||||
|
{{
|
||||||
|
dashboardStore.entity === "EndpointRelation"
|
||||||
|
? "$DestinationEndpoint"
|
||||||
|
: "$DestinationServiceInstance"
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
<Selector
|
||||||
|
v-model="states.currentDestPod"
|
||||||
|
:options="selectorStore.destPods"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a data"
|
||||||
|
@change="changeDestPods"
|
||||||
|
class="selectorPod"
|
||||||
|
@query="searchDestPods"
|
||||||
|
:isRemote="dashboardStore.entity === 'EndpointRelation'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="key === 3 || key === 4">
|
<div
|
||||||
<span class="label">
|
class="flex-h tools"
|
||||||
{{
|
v-loading="loading"
|
||||||
["EndpointRelation", "Endpoint"].includes(dashboardStore.entity)
|
v-if="$route.query['portal'] !== 'true'"
|
||||||
? "$Endpoint"
|
>
|
||||||
: "$ServiceInstance"
|
<div class="tool-icons flex-h" v-if="dashboardStore.editMode">
|
||||||
}}
|
<el-dropdown content="Controls" placement="bottom">
|
||||||
</span>
|
<i>
|
||||||
<Selector
|
<Icon class="icon-btn" size="sm" iconName="control" />
|
||||||
v-model="states.currentPod"
|
</i>
|
||||||
:options="selectorStore.pods"
|
<template #dropdown>
|
||||||
size="small"
|
<el-dropdown-menu>
|
||||||
placeholder="Select a data"
|
<el-dropdown-item
|
||||||
@change="changePods"
|
@click="clickIcons(t)"
|
||||||
@query="searchPods"
|
v-for="(t, index) in toolIcons"
|
||||||
class="selectorPod"
|
:key="index"
|
||||||
:isRemote="
|
:title="t.content"
|
||||||
['EndpointRelation', 'Endpoint'].includes(dashboardStore.entity)
|
>
|
||||||
"
|
<Icon class="mr-5" size="middle" :iconName="t.name" />
|
||||||
/>
|
<span>{{ t.content }}</span>
|
||||||
</div>
|
</el-dropdown-item>
|
||||||
<div class="selectors-item" v-if="key === 2 || key === 4">
|
</el-dropdown-menu>
|
||||||
<span class="label">$DestinationService</span>
|
</template>
|
||||||
<Selector
|
</el-dropdown>
|
||||||
v-model="states.currentDestService"
|
<el-tooltip content="Apply" placement="bottom" effect="light">
|
||||||
:options="selectorStore.destServices"
|
<i @click="applyDashboard">
|
||||||
size="small"
|
<Icon class="icon-btn" size="sm" iconName="save" />
|
||||||
placeholder="Select a service"
|
</i>
|
||||||
@change="changeDestService"
|
</el-tooltip>
|
||||||
class="selectors"
|
</div>
|
||||||
/>
|
<div class="switch">
|
||||||
</div>
|
<el-switch
|
||||||
<div class="selectors-item" v-if="key === 4">
|
v-model="dashboardStore.editMode"
|
||||||
<span class="label">
|
active-text="Edit"
|
||||||
{{
|
inactive-text="View"
|
||||||
dashboardStore.entity === "EndpointRelation"
|
size="small"
|
||||||
? "$DestinationEndpoint"
|
inline-prompt
|
||||||
: "$DestinationServiceInstance"
|
active-color="#409eff"
|
||||||
}}
|
inactive-color="#999"
|
||||||
</span>
|
@change="changeMode"
|
||||||
<Selector
|
/>
|
||||||
v-model="states.currentDestPod"
|
</div>
|
||||||
:options="selectorStore.destPods"
|
|
||||||
size="small"
|
|
||||||
placeholder="Select a data"
|
|
||||||
@change="changeDestPods"
|
|
||||||
class="selectorPod"
|
|
||||||
@query="searchDestPods"
|
|
||||||
:isRemote="dashboardStore.entity === 'EndpointRelation'"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-h tools" v-loading="loading" v-if="$route.query['portal'] !== 'true'">
|
|
||||||
<div class="tool-icons flex-h" v-if="dashboardStore.editMode">
|
|
||||||
<el-dropdown content="Controls" placement="bottom">
|
|
||||||
<i>
|
|
||||||
<Icon class="icon-btn" size="sm" iconName="control" />
|
|
||||||
</i>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item
|
|
||||||
@click="clickIcons(t)"
|
|
||||||
v-for="(t, index) in toolIcons"
|
|
||||||
:key="index"
|
|
||||||
:title="t.content"
|
|
||||||
>
|
|
||||||
<Icon class="mr-5" size="middle" :iconName="t.name" />
|
|
||||||
<span>{{ t.content }}</span>
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
<el-tooltip content="Apply" placement="bottom" effect="light">
|
|
||||||
<i @click="applyDashboard">
|
|
||||||
<Icon class="icon-btn" size="sm" iconName="save" />
|
|
||||||
</i>
|
|
||||||
</el-tooltip>
|
|
||||||
</div>
|
|
||||||
<div class="switch">
|
|
||||||
<el-switch
|
|
||||||
v-model="dashboardStore.editMode"
|
|
||||||
active-text="Edit"
|
|
||||||
inactive-text="View"
|
|
||||||
size="small"
|
|
||||||
inline-prompt
|
|
||||||
active-color="#409eff"
|
|
||||||
inactive-color="#999"
|
|
||||||
@change="changeMode"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Header v-if="showLogHeader" />
|
||||||
|
<TraceDetailsTools
|
||||||
|
v-if="showTraceHeader && currentTraceView === 'traceDetails'"
|
||||||
|
/>
|
||||||
|
<Filter v-if="showTraceHeader && currentTraceView === 'traceList'" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import Filter from "../related/trace/Filter.vue";
|
||||||
|
import Header from "../related/log/Header.vue";
|
||||||
|
|
||||||
import { reactive, ref, computed, watch } from "vue";
|
import { reactive, ref, computed, watch } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { useTraceStore } from "@/store/modules/trace";
|
||||||
import {
|
import {
|
||||||
EntityType,
|
EntityType,
|
||||||
AllTools,
|
AllTools,
|
||||||
@ -138,13 +205,17 @@ import { useSelectorStore } from "@/store/modules/selectors";
|
|||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import TraceDetailsTools from "./component/TraceDetailsTools";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
|
const traceStore = useTraceStore();
|
||||||
const params = useRoute().params;
|
const params = useRoute().params;
|
||||||
|
const selectedSelector = ref<string>("");
|
||||||
|
const showTraceHeader = computed(() => dashboardStore.showTraceTools);
|
||||||
|
const showLogHeader = computed(() => dashboardStore.showLogTools);
|
||||||
|
const currentTraceView = computed(() => traceStore.currentView);
|
||||||
const { query } = useRoute();
|
const { query } = useRoute();
|
||||||
dashboardStore.setViewMode(query["fullview"] === "true");
|
dashboardStore.setViewMode(query["fullview"] === "true");
|
||||||
|
|
||||||
@ -176,6 +247,12 @@ const key = computed(() => {
|
|||||||
return (type && type.key) || 0;
|
return (type && type.key) || 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function setSelectedSelector(selector: string) {
|
||||||
|
selectedSelector.value = selector;
|
||||||
|
}
|
||||||
|
function closeSelector() {
|
||||||
|
selectedSelector.value = "";
|
||||||
|
}
|
||||||
setCurrentDashboard();
|
setCurrentDashboard();
|
||||||
appStore.setEventStack([initSelector]);
|
appStore.setEventStack([initSelector]);
|
||||||
initSelector();
|
initSelector();
|
||||||
@ -362,6 +439,7 @@ async function getServices() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function changeService(service: any) {
|
async function changeService(service: any) {
|
||||||
|
selectedSelector.value = "";
|
||||||
if (service[0]) {
|
if (service[0]) {
|
||||||
states.currentService = service[0].value;
|
states.currentService = service[0].value;
|
||||||
selectorStore.setCurrentService(service[0]);
|
selectorStore.setCurrentService(service[0]);
|
||||||
@ -381,6 +459,7 @@ function changeDestService(service: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function changePods(pod: any) {
|
function changePods(pod: any) {
|
||||||
|
selectedSelector.value = "";
|
||||||
if (pod[0]) {
|
if (pod[0]) {
|
||||||
selectorStore.setCurrentPod(pod[0]);
|
selectorStore.setCurrentPod(pod[0]);
|
||||||
} else {
|
} else {
|
||||||
@ -636,6 +715,7 @@ watch(
|
|||||||
background: rgb(240, 242, 245);
|
background: rgb(240, 242, 245);
|
||||||
border-bottom: 1px solid #dfe4e8;
|
border-bottom: 1px solid #dfe4e8;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.switch {
|
.switch {
|
||||||
@ -682,4 +762,11 @@ watch(
|
|||||||
.selectorPod {
|
.selectorPod {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tool-btn {
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
.el-input__wrapper {
|
||||||
|
height: 18px !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
339
src/views/dashboard/panel/component/TraceDetailsTools.vue
Normal file
339
src/views/dashboard/panel/component/TraceDetailsTools.vue
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="trace-detail-wrapper flex-h"
|
||||||
|
v-if="traceStore.currentTrace.endpointNames"
|
||||||
|
>
|
||||||
|
<div class="mb-0 mt-0">
|
||||||
|
<Icon
|
||||||
|
icon="clear"
|
||||||
|
v-if="traceStore.currentTrace.isError"
|
||||||
|
class="red mr-5 sm"
|
||||||
|
/>
|
||||||
|
<div class="trace-log-btn">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="Back"
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
class="mr-10 filter-btn"
|
||||||
|
type="primary"
|
||||||
|
@click="showTraceList"
|
||||||
|
>
|
||||||
|
<Icon iconSize="sm" iconName="chevron-left" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
:content="t('viewLogs')"
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
class="mr-10 filter-btn"
|
||||||
|
type="primary"
|
||||||
|
@click="searchTraceLogs"
|
||||||
|
>
|
||||||
|
<Icon iconSize="sm" iconName="folder_open" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
<el-dialog
|
||||||
|
v-model="showTraceLogs"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
fullscreen
|
||||||
|
@closed="showTraceLogs = false"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<el-pagination
|
||||||
|
v-model:currentPage="pageNum"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
:small="true"
|
||||||
|
:total="traceStore.traceSpanLogsTotal"
|
||||||
|
@current-change="turnLogsPage"
|
||||||
|
/>
|
||||||
|
<LogTable
|
||||||
|
:tableData="traceStore.traceSpanLogs || []"
|
||||||
|
:type="`service`"
|
||||||
|
:noLink="true"
|
||||||
|
>
|
||||||
|
<div class="log-tips" v-if="!traceStore.traceSpanLogs.length">
|
||||||
|
{{ t("noData") }}
|
||||||
|
</div>
|
||||||
|
</LogTable>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
<div class="mb- blue sm">
|
||||||
|
<span class="vm">{{ traceStore.currentTrace.endpointNames[0] }}</span>
|
||||||
|
<Selector
|
||||||
|
size="small"
|
||||||
|
:value="
|
||||||
|
traceStore.currentTrace.traceIds &&
|
||||||
|
traceStore.currentTrace.traceIds[0] &&
|
||||||
|
traceStore.currentTrace.traceIds[0].value
|
||||||
|
"
|
||||||
|
:options="traceStore.currentTrace.traceIds"
|
||||||
|
@change="changeTraceId"
|
||||||
|
class="trace-detail-ids"
|
||||||
|
/>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="Copy Ids"
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
class="mr-10 copy-btn"
|
||||||
|
type="primary"
|
||||||
|
@click="handleClick(traceStore.currentTrace.traceIds)"
|
||||||
|
>
|
||||||
|
<Icon iconSize="sm" iconName="review-list" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="flex-h item">
|
||||||
|
<div>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
:content="t('list')"
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
class="filter-btn"
|
||||||
|
size="small"
|
||||||
|
:class="{ ghost: displayMode === 'List' }"
|
||||||
|
@click="changeDisplayMode('List')"
|
||||||
|
>
|
||||||
|
<Icon class="mr-5" size="sm" iconName="list-bulleted" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
:content="t('tree')"
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
class="filter-btn"
|
||||||
|
size="small"
|
||||||
|
:class="{ ghost: displayMode === 'Tree' }"
|
||||||
|
@click="changeDisplayMode('Tree')"
|
||||||
|
>
|
||||||
|
<Icon class="mr-5" size="sm" iconName="issue-child" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
:content="t('table')"
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
class="filter-btn"
|
||||||
|
size="small"
|
||||||
|
:class="{ ghost: displayMode === 'Table' }"
|
||||||
|
@click="changeDisplayMode('Table')"
|
||||||
|
>
|
||||||
|
<Icon class="mr-5" size="sm" iconName="table" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
:content="t('statistics')"
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
class="filter-btn"
|
||||||
|
size="small"
|
||||||
|
:class="{ ghost: displayMode === 'Statistics' }"
|
||||||
|
@click="changeDisplayMode('Statistics')"
|
||||||
|
>
|
||||||
|
<Icon class="mr-5" size="sm" iconName="statistics-bulleted" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="no-data" v-else>t("noData")</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { ref, computed, defineComponent } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useTraceStore } from "@/store/modules/trace";
|
||||||
|
import { Option } from "@/types/app";
|
||||||
|
import copy from "@/utils/copy";
|
||||||
|
import LogTable from "@/views/dashboard/related/components/LogTable/Index.vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "TraceDetailsTools",
|
||||||
|
components: {
|
||||||
|
LogTable,
|
||||||
|
},
|
||||||
|
setup(props, ctx) {
|
||||||
|
const { t } = useI18n();
|
||||||
|
const traceStore = useTraceStore();
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const traceId = ref<string>("");
|
||||||
|
const displayMode = computed(() => {
|
||||||
|
return traceStore.displayMode;
|
||||||
|
});
|
||||||
|
const pageNum = ref<number>(1);
|
||||||
|
const pageSize = 10;
|
||||||
|
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
||||||
|
dayjs(date).format(pattern);
|
||||||
|
const showTraceLogs = ref<boolean>(false);
|
||||||
|
|
||||||
|
function showTraceList() {
|
||||||
|
traceStore.setCurrentView("traceList");
|
||||||
|
}
|
||||||
|
function handleClick(ids: string[] | any) {
|
||||||
|
let copyValue = null;
|
||||||
|
if (ids.length === 1) {
|
||||||
|
copyValue = ids[0].value;
|
||||||
|
} else {
|
||||||
|
copyValue = ids.map((trace: any) => trace.value).join(",");
|
||||||
|
}
|
||||||
|
copy(copyValue);
|
||||||
|
}
|
||||||
|
function changeDisplayMode(mode: string) {
|
||||||
|
traceStore.displayMode = mode;
|
||||||
|
}
|
||||||
|
async function changeTraceId(opt: Option[] | any) {
|
||||||
|
traceId.value = opt[0].value;
|
||||||
|
loading.value = true;
|
||||||
|
const res = await traceStore.getTraceSpans({ traceId: opt[0].value });
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function searchTraceLogs() {
|
||||||
|
showTraceLogs.value = true;
|
||||||
|
const res = await traceStore.getSpanLogs({
|
||||||
|
condition: {
|
||||||
|
relatedTrace: {
|
||||||
|
traceId: traceId.value || traceStore.currentTrace.traceIds[0].value,
|
||||||
|
},
|
||||||
|
paging: { pageNum: pageNum.value, pageSize, needTotal: true },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function turnLogsPage(page: number) {
|
||||||
|
pageNum.value = page;
|
||||||
|
searchTraceLogs();
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
showTraceList,
|
||||||
|
changeDisplayMode,
|
||||||
|
traceStore,
|
||||||
|
displayMode,
|
||||||
|
dateFormat,
|
||||||
|
changeTraceId,
|
||||||
|
handleClick,
|
||||||
|
t,
|
||||||
|
searchTraceLogs,
|
||||||
|
showTraceLogs,
|
||||||
|
turnLogsPage,
|
||||||
|
pageSize,
|
||||||
|
pageNum,
|
||||||
|
loading,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.trace-detail {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-chart {
|
||||||
|
height: calc(100% - 100px);
|
||||||
|
overflow: auto;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
.trace-chart.full-view {
|
||||||
|
height: calc(100% - 1px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-detail-wrapper {
|
||||||
|
font-size: 12px;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.grey {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #448dfe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost {
|
||||||
|
cursor: pointer;
|
||||||
|
background: rgba(4, 147, 114, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-detail-ids {
|
||||||
|
background-color: rgba(0, 0, 0, 0);
|
||||||
|
outline: 0;
|
||||||
|
border-style: unset;
|
||||||
|
color: inherit;
|
||||||
|
border: 1px solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-log-btn {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0px 7px;
|
||||||
|
background-color: #40454e;
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data {
|
||||||
|
padding-top: 50px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.vm {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
.filter-btn {
|
||||||
|
height: 18px;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
.copy-btn {
|
||||||
|
height: 18px;
|
||||||
|
width: 10px;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -13,114 +13,192 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="flex-h row">
|
<div class="flex-h log-wrapper">
|
||||||
<div class="mr-5" v-if="dashboardStore.entity === EntityType[1].value">
|
<div v-if="!currentSearchTerm.length" class="flex-h items-center">
|
||||||
<span class="grey mr-5">{{ t("service") }}:</span>
|
<div v-for="(item, index) in arrayOfFilters" :key="index">
|
||||||
<Selector
|
<el-tooltip
|
||||||
size="small"
|
class="box-item"
|
||||||
:value="state.service.value"
|
effect="dark"
|
||||||
:options="logStore.services"
|
:content="item.description"
|
||||||
placeholder="Select a service"
|
placement="bottom-start"
|
||||||
@change="changeField('service', $event)"
|
>
|
||||||
/>
|
<el-button
|
||||||
|
type="success"
|
||||||
|
:class="[activeTerms.includes(item.name) ? 'active-toggle' : '']"
|
||||||
|
class="toggle-btn mx-3"
|
||||||
|
v-show="item.isVisible"
|
||||||
|
@click="setSearchTerm(item.name)"
|
||||||
|
>
|
||||||
|
<Icon iconSize="sm" :iconName="item.iconName" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mr-5" v-if="dashboardStore.entity !== EntityType[3].value">
|
<div class="flex-h items-center">
|
||||||
<span class="grey mr-5">
|
<div class="flex-h items-center" v-if="currentSearchTerm === 'service'">
|
||||||
{{ isBrowser ? t("version") : t("instance") }}:
|
<div
|
||||||
</span>
|
class="mr-5 flex-h items-center"
|
||||||
<Selector
|
v-if="dashboardStore.entity === EntityType[1].value"
|
||||||
size="small"
|
>
|
||||||
:value="state.instance.value"
|
<span class="grey mr-5">{{ t("service") }}:</span>
|
||||||
:options="logStore.instances"
|
<Selector
|
||||||
placeholder="Select a instance"
|
size="small"
|
||||||
@change="changeField('instance', $event)"
|
:value="state.service.value"
|
||||||
/>
|
:options="logStore.services"
|
||||||
|
placeholder="Select a service"
|
||||||
|
@change="changeField('service', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<b v-else>{{ t("service") }} data not available</b>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-h items-center" v-if="currentSearchTerm === 'instance'">
|
||||||
|
<div
|
||||||
|
class="mr-5 items-center flex-h"
|
||||||
|
v-if="
|
||||||
|
dashboardStore.entity !== EntityType[3].value &&
|
||||||
|
currentSearchTerm === 'instance'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span class="grey mr-5">
|
||||||
|
{{ isBrowser ? t("version") : t("instance") }}:
|
||||||
|
</span>
|
||||||
|
<Selector
|
||||||
|
size="small"
|
||||||
|
:value="state.instance.value"
|
||||||
|
:options="logStore.instances"
|
||||||
|
placeholder="Select a instance"
|
||||||
|
@change="changeField('instance', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<b v-else>{{ t("instance") }} data not available</b>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-h items-center" v-if="currentSearchTerm === 'endpoints'">
|
||||||
|
<div
|
||||||
|
class="mr-5 flex-h items-center"
|
||||||
|
v-if="
|
||||||
|
dashboardStore.entity !== EntityType[2].value &&
|
||||||
|
currentSearchTerm === 'endpoints'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span class="grey mr-5"
|
||||||
|
>{{ isBrowser ? t("page") : t("endpoint") }}:</span
|
||||||
|
>
|
||||||
|
<Selector
|
||||||
|
size="small"
|
||||||
|
:value="state.endpoint.value"
|
||||||
|
:options="logStore.endpoints"
|
||||||
|
placeholder="Select a endpoint"
|
||||||
|
@change="changeField('endpoint', $event)"
|
||||||
|
:isRemote="true"
|
||||||
|
@query="searchEndpoints"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<b v-else>{{ t("endpoint") }} data not available</b>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mr-5" v-if="dashboardStore.entity !== EntityType[2].value">
|
<!-- <div class="row tips">
|
||||||
<span class="grey mr-5"
|
<b>{{ t("conditionNotice") }}</b>
|
||||||
>{{ isBrowser ? t("page") : t("endpoint") }}:</span
|
</div> -->
|
||||||
|
<div class="flex-h items-center">
|
||||||
|
<div class="mr-5 flex-h items-center traceId" v-show="!isBrowser">
|
||||||
|
<div class="flex-h items-center" v-if="currentSearchTerm === 'traceId'">
|
||||||
|
<span class="grey mr-5">{{ t("traceID") }}:</span>
|
||||||
|
<el-input v-model="traceId" class="inputs-max" size="small" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<keep-alive>
|
||||||
|
<ConditionTags
|
||||||
|
ref="logTagsComponent"
|
||||||
|
v-if="currentSearchTerm === 'tags'"
|
||||||
|
:type="'LOG'"
|
||||||
|
@update="updateTags"
|
||||||
|
/>
|
||||||
|
</keep-alive>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-h items-center" v-show="!isBrowser">
|
||||||
|
<div
|
||||||
|
class="mr-5 flex-h items-center"
|
||||||
|
v-show="supportQueryLogsByKeywords && currentSearchTerm === 'keywords'"
|
||||||
>
|
>
|
||||||
<Selector
|
<span class="mr-5 grey">{{ t("keywordsOfContent") }}:</span>
|
||||||
size="small"
|
<span class="log-tags">
|
||||||
:value="state.endpoint.value"
|
<span
|
||||||
:options="logStore.endpoints"
|
class="selected"
|
||||||
placeholder="Select a endpoint"
|
v-for="(item, index) in keywordsOfContent"
|
||||||
@change="changeField('endpoint', $event)"
|
:key="`keywordsOfContent${index}`"
|
||||||
:isRemote="true"
|
>
|
||||||
@query="searchEndpoints"
|
<span>{{ item }}</span>
|
||||||
/>
|
<span class="remove-icon" @click="removeContent(index)">×</span>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row tips">
|
|
||||||
<b>{{ t("conditionNotice") }}</b>
|
|
||||||
</div>
|
|
||||||
<div class="flex-h row">
|
|
||||||
<div class="mr-5 traceId" v-show="!isBrowser">
|
|
||||||
<span class="grey mr-5">{{ t("traceID") }}:</span>
|
|
||||||
<el-input v-model="traceId" class="inputs-max" size="small" />
|
|
||||||
</div>
|
|
||||||
<ConditionTags :type="'LOG'" @update="updateTags" />
|
|
||||||
</div>
|
|
||||||
<div class="flex-h" v-show="!isBrowser">
|
|
||||||
<div class="mr-5" v-show="logStore.supportQueryLogsByKeywords">
|
|
||||||
<span class="mr-5 grey">{{ t("keywordsOfContent") }}:</span>
|
|
||||||
<span class="log-tags">
|
|
||||||
<span
|
|
||||||
class="selected"
|
|
||||||
v-for="(item, index) in keywordsOfContent"
|
|
||||||
:key="`keywordsOfContent${index}`"
|
|
||||||
>
|
|
||||||
<span>{{ item }}</span>
|
|
||||||
<span class="remove-icon" @click="removeContent(index)">×</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<el-input
|
|
||||||
size="small"
|
|
||||||
class="inputs-max"
|
|
||||||
:placeholder="t('addKeywordsOfContent')"
|
|
||||||
v-model="contentStr"
|
|
||||||
@change="addLabels('keywordsOfContent')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mr-5" v-show="logStore.supportQueryLogsByKeywords">
|
|
||||||
<span class="grey mr-5"> {{ t("excludingKeywordsOfContent") }}: </span>
|
|
||||||
<span class="log-tags">
|
|
||||||
<span
|
|
||||||
class="selected"
|
|
||||||
v-for="(item, index) in excludingKeywordsOfContent"
|
|
||||||
:key="`excludingKeywordsOfContent${index}`"
|
|
||||||
>
|
|
||||||
<span>{{ item }}</span>
|
|
||||||
<span class="remove-icon" @click="removeExcludeContent(index)">
|
|
||||||
×
|
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
<el-input
|
||||||
<el-input
|
size="small"
|
||||||
class="inputs-max"
|
class="inputs-max"
|
||||||
size="small"
|
:placeholder="t('addKeywordsOfContent')"
|
||||||
:placeholder="t('addExcludingKeywordsOfContent')"
|
v-model="contentStr"
|
||||||
v-model="excludingContentStr"
|
@change="addLabels('keywordsOfContent')"
|
||||||
@change="addLabels('excludingKeywordsOfContent')"
|
/>
|
||||||
/>
|
</div>
|
||||||
<el-tooltip :content="t('keywordsOfContentLogTips')">
|
<div
|
||||||
<span class="log-tips" v-show="!logStore.supportQueryLogsByKeywords">
|
class="mr-5 flex-h items-center"
|
||||||
<Icon icon="help" class="mr-5" />
|
v-show="
|
||||||
|
supportExcludeQueryLogsByKeywords && currentSearchTerm === 'exclude'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span class="grey mr-5"> {{ t("excludingKeywordsOfContent") }}: </span>
|
||||||
|
<span class="log-tags">
|
||||||
|
<span
|
||||||
|
class="selected"
|
||||||
|
v-for="(item, index) in excludingKeywordsOfContent"
|
||||||
|
:key="`excludingKeywordsOfContent${index}`"
|
||||||
|
>
|
||||||
|
<span>{{ item }}</span>
|
||||||
|
<span class="remove-icon" @click="removeExcludeContent(index)">
|
||||||
|
×
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</el-tooltip>
|
<el-input
|
||||||
|
class="inputs-max"
|
||||||
|
size="small"
|
||||||
|
:placeholder="t('addExcludingKeywordsOfContent')"
|
||||||
|
v-model="excludingContentStr"
|
||||||
|
@change="addLabels('excludingKeywordsOfContent')"
|
||||||
|
/>
|
||||||
|
<el-tooltip :content="t('keywordsOfContentLogTips')">
|
||||||
|
<span class="log-tips" v-show="!logStore.supportQueryLogsByKeywords">
|
||||||
|
<Icon icon="help" class="mr-5" />
|
||||||
|
</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Search&cancel buttons -->
|
||||||
|
<div v-if="currentSearchTerm.length" class="flex-h items-center">
|
||||||
|
<el-button
|
||||||
|
class="search-btn toggle-btn"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="searchLogs"
|
||||||
|
>
|
||||||
|
<Icon iconSize="sm" iconName="search" />
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
class="search-btn toggle-btn"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="cancelSearchTerm"
|
||||||
|
>
|
||||||
|
<Icon iconSize="sm" iconName="cancel" />
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-button
|
|
||||||
class="search-btn"
|
|
||||||
size="small"
|
|
||||||
type="primary"
|
|
||||||
@click="searchLogs"
|
|
||||||
>
|
|
||||||
{{ t("search") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, watch } from "vue";
|
import { ref, reactive, watch, computed } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import { useLogStore } from "@/store/modules/log";
|
import { useLogStore } from "@/store/modules/log";
|
||||||
@ -139,6 +217,15 @@ const logStore = useLogStore();
|
|||||||
const traceId = ref<string>("");
|
const traceId = ref<string>("");
|
||||||
const keywordsOfContent = ref<string[]>([]);
|
const keywordsOfContent = ref<string[]>([]);
|
||||||
const excludingKeywordsOfContent = ref<string[]>([]);
|
const excludingKeywordsOfContent = ref<string[]>([]);
|
||||||
|
const supportQueryLogsByKeywords = computed<boolean>(() => {
|
||||||
|
return logStore.supportQueryLogsByKeywords
|
||||||
|
})
|
||||||
|
const supportExcludeQueryLogsByKeywords = computed<boolean>(() => {
|
||||||
|
return logStore.supportQueryLogsByKeywords
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentSearchTerm = ref<string>("");
|
||||||
|
const activeTerms = ref<string[]>([]);
|
||||||
const tagsList = ref<string[]>([]);
|
const tagsList = ref<string[]>([]);
|
||||||
const tagsMap = ref<Option[]>([]);
|
const tagsMap = ref<Option[]>([]);
|
||||||
const contentStr = ref<string>("");
|
const contentStr = ref<string>("");
|
||||||
@ -149,7 +236,57 @@ const state = reactive<any>({
|
|||||||
endpoint: { value: "0", label: "All" },
|
endpoint: { value: "0", label: "All" },
|
||||||
service: { value: "", label: "" },
|
service: { value: "", label: "" },
|
||||||
});
|
});
|
||||||
|
const logTagsComponent = ref<InstanceType<typeof ConditionTags> | null>(null);
|
||||||
|
interface filtersObject {
|
||||||
|
name: string;
|
||||||
|
iconName: string;
|
||||||
|
description: string;
|
||||||
|
isVisible?: boolean | unknown; // one of the situations is dependent on an api call
|
||||||
|
}
|
||||||
|
const arrayOfFilters = ref<filtersObject[]>([
|
||||||
|
{
|
||||||
|
name: "traceId",
|
||||||
|
iconName: "timeline",
|
||||||
|
description: "Trace ID",
|
||||||
|
isVisible: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tags",
|
||||||
|
iconName: "epic",
|
||||||
|
description: "Tags",
|
||||||
|
isVisible: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "keywords",
|
||||||
|
iconName: "library_books",
|
||||||
|
description: "Keywords",
|
||||||
|
isVisible: supportQueryLogsByKeywords,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "exclude",
|
||||||
|
iconName: "issue-child",
|
||||||
|
description: "Exclude keywords",
|
||||||
|
isVisible: supportExcludeQueryLogsByKeywords,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "instance",
|
||||||
|
iconName: "epic",
|
||||||
|
description: "Instance",
|
||||||
|
isVisible: dashboardStore.entity !== EntityType[3].value,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "service",
|
||||||
|
iconName: "settings",
|
||||||
|
description: "Service",
|
||||||
|
isVisible: dashboardStore.entity === EntityType[1].value,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "endpoints",
|
||||||
|
iconName: "timeline",
|
||||||
|
description: "Endpoints",
|
||||||
|
isVisible: dashboardStore.entity !== EntityType[2].value,
|
||||||
|
},
|
||||||
|
]);
|
||||||
init();
|
init();
|
||||||
async function init() {
|
async function init() {
|
||||||
const resp = await logStore.getLogsByKeywords();
|
const resp = await logStore.getLogsByKeywords();
|
||||||
@ -210,7 +347,46 @@ async function getInstances(id?: string) {
|
|||||||
}
|
}
|
||||||
state.instance = logStore.instances[0];
|
state.instance = logStore.instances[0];
|
||||||
}
|
}
|
||||||
|
function addToActiveTerms() {
|
||||||
|
activeTerms.value.push(currentSearchTerm.value);
|
||||||
|
}
|
||||||
|
function removeFromActiveTerms() {
|
||||||
|
activeTerms.value = activeTerms.value.filter(
|
||||||
|
(term) => term !== currentSearchTerm.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function handleActiveSearchTerms() {
|
||||||
|
switch (currentSearchTerm.value) {
|
||||||
|
case "traceId":
|
||||||
|
if (!traceId.value.length) return;
|
||||||
|
addToActiveTerms();
|
||||||
|
break;
|
||||||
|
case "tags":
|
||||||
|
if (!tagsList.value.length) return;
|
||||||
|
addToActiveTerms();
|
||||||
|
break;
|
||||||
|
case "keywords":
|
||||||
|
if (!keywordsOfContent.value.length) return;
|
||||||
|
addToActiveTerms();
|
||||||
|
break;
|
||||||
|
case "exclude":
|
||||||
|
if (!excludingKeywordsOfContent.value.length) return;
|
||||||
|
addToActiveTerms();
|
||||||
|
break;
|
||||||
|
case "instance":
|
||||||
|
addToActiveTerms();
|
||||||
|
break;
|
||||||
|
case "service":
|
||||||
|
addToActiveTerms();
|
||||||
|
break;
|
||||||
|
case "endpoints":
|
||||||
|
addToActiveTerms();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
function searchLogs() {
|
function searchLogs() {
|
||||||
|
handleActiveSearchTerms();
|
||||||
|
currentSearchTerm.value = "";
|
||||||
let endpoint = "",
|
let endpoint = "",
|
||||||
instance = "";
|
instance = "";
|
||||||
if (dashboardStore.entity === EntityType[2].value) {
|
if (dashboardStore.entity === EntityType[2].value) {
|
||||||
@ -293,6 +469,40 @@ function removeExcludeContent(index: number) {
|
|||||||
});
|
});
|
||||||
excludingContentStr.value = "";
|
excludingContentStr.value = "";
|
||||||
}
|
}
|
||||||
|
function setSearchTerm(term: string) {
|
||||||
|
currentSearchTerm.value = term;
|
||||||
|
}
|
||||||
|
function cancelSearchTerm() {
|
||||||
|
switch (currentSearchTerm.value) {
|
||||||
|
case "traceId":
|
||||||
|
traceId.value = "";
|
||||||
|
break;
|
||||||
|
case "tags":
|
||||||
|
tagsList.value = [];
|
||||||
|
tagsMap.value = [];
|
||||||
|
logTagsComponent.value?.emptyTags();
|
||||||
|
break;
|
||||||
|
case "keywords":
|
||||||
|
keywordsOfContent.value = [];
|
||||||
|
break;
|
||||||
|
case "exclude":
|
||||||
|
excludingKeywordsOfContent.value = [];
|
||||||
|
break;
|
||||||
|
case "instance":
|
||||||
|
state.instance = { value: "0", label: "All" };
|
||||||
|
break;
|
||||||
|
case "endpoints":
|
||||||
|
state.endpoint = { value: "0", label: "All" };
|
||||||
|
getEndpoints();
|
||||||
|
break;
|
||||||
|
case "service":
|
||||||
|
state.service = { value: "", label: "" };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
removeFromActiveTerms();
|
||||||
|
currentSearchTerm.value = "";
|
||||||
|
searchLogs()
|
||||||
|
}
|
||||||
watch(
|
watch(
|
||||||
() => selectorStore.currentService,
|
() => selectorStore.currentService,
|
||||||
() => {
|
() => {
|
||||||
@ -320,6 +530,12 @@ watch(
|
|||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
// .log-wrapper {
|
||||||
|
// width: 600px;
|
||||||
|
// padding-left: 40px;
|
||||||
|
// overflow-x: scroll;
|
||||||
|
// align-items: center;
|
||||||
|
// }
|
||||||
.inputs {
|
.inputs {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
}
|
}
|
||||||
@ -378,4 +594,22 @@ watch(
|
|||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* buttons*/
|
||||||
|
.el-button span {
|
||||||
|
font-size: 10px !important;
|
||||||
|
}
|
||||||
|
.toggle-btn {
|
||||||
|
height: 18px;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
.active-toggle.toggle-btn {
|
||||||
|
background: rgba(4, 147, 114, 1) !important;
|
||||||
|
span {
|
||||||
|
color: #275410 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -12,130 +12,10 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="trace-detail" v-loading="loading">
|
<div class="trace-detail" v-loading="loading">
|
||||||
<div
|
<div :class="{ 'full-view': isFullView }" class="trace-chart">
|
||||||
class="trace-detail-wrapper clear"
|
|
||||||
v-if="traceStore.currentTrace.endpointNames"
|
|
||||||
>
|
|
||||||
<h5 class="mb-5 mt-0">
|
|
||||||
<Icon
|
|
||||||
icon="clear"
|
|
||||||
v-if="traceStore.currentTrace.isError"
|
|
||||||
class="red mr-5 sm"
|
|
||||||
/>
|
|
||||||
<span class="vm">{{ traceStore.currentTrace.endpointNames[0] }}</span>
|
|
||||||
<div class="trace-log-btn">
|
|
||||||
<el-button
|
|
||||||
size="small"
|
|
||||||
class="mr-10"
|
|
||||||
type="primary"
|
|
||||||
@click="searchTraceLogs"
|
|
||||||
>
|
|
||||||
{{ t("viewLogs") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
<el-dialog
|
|
||||||
v-model="showTraceLogs"
|
|
||||||
:destroy-on-close="true"
|
|
||||||
fullscreen
|
|
||||||
@closed="showTraceLogs = false"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<el-pagination
|
|
||||||
v-model:currentPage="pageNum"
|
|
||||||
v-model:page-size="pageSize"
|
|
||||||
:small="true"
|
|
||||||
:total="traceStore.traceSpanLogsTotal"
|
|
||||||
@current-change="turnLogsPage"
|
|
||||||
/>
|
|
||||||
<LogTable
|
|
||||||
:tableData="traceStore.traceSpanLogs || []"
|
|
||||||
:type="`service`"
|
|
||||||
:noLink="true"
|
|
||||||
>
|
|
||||||
<div class="log-tips" v-if="!traceStore.traceSpanLogs.length">
|
|
||||||
{{ t("noData") }}
|
|
||||||
</div>
|
|
||||||
</LogTable>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</h5>
|
|
||||||
<div class="mb-5 blue sm">
|
|
||||||
<Selector
|
|
||||||
size="small"
|
|
||||||
:value="
|
|
||||||
traceStore.currentTrace.traceIds &&
|
|
||||||
traceStore.currentTrace.traceIds[0] &&
|
|
||||||
traceStore.currentTrace.traceIds[0].value
|
|
||||||
"
|
|
||||||
:options="traceStore.currentTrace.traceIds"
|
|
||||||
@change="changeTraceId"
|
|
||||||
class="trace-detail-ids"
|
|
||||||
/>
|
|
||||||
<Icon
|
|
||||||
size="sm"
|
|
||||||
class="icon grey link-hover cp ml-5"
|
|
||||||
iconName="review-list"
|
|
||||||
@click="handleClick"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="flex-h item">
|
|
||||||
<div>
|
|
||||||
<div class="tag mr-5">{{ t("start") }}</div>
|
|
||||||
<span class="mr-15 sm">
|
|
||||||
{{ dateFormat(parseInt(traceStore.currentTrace.start)) }}
|
|
||||||
</span>
|
|
||||||
<div class="tag mr-5">{{ t("duration") }}</div>
|
|
||||||
<span class="mr-15 sm"
|
|
||||||
>{{ traceStore.currentTrace.duration }} ms</span
|
|
||||||
>
|
|
||||||
<div class="tag mr-5">{{ t("spans") }}</div>
|
|
||||||
<span class="sm">{{ traceStore.traceSpans.length }}</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<el-button
|
|
||||||
class="grey"
|
|
||||||
size="small"
|
|
||||||
:class="{ ghost: displayMode !== 'List' }"
|
|
||||||
@click="displayMode = 'List'"
|
|
||||||
>
|
|
||||||
<Icon class="mr-5" size="sm" iconName="list-bulleted" />
|
|
||||||
{{ t("list") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
class="grey"
|
|
||||||
size="small"
|
|
||||||
:class="{ ghost: displayMode !== 'Tree' }"
|
|
||||||
@click="displayMode = 'Tree'"
|
|
||||||
>
|
|
||||||
<Icon class="mr-5" size="sm" iconName="issue-child" />
|
|
||||||
{{ t("tree") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
class="grey"
|
|
||||||
size="small"
|
|
||||||
:class="{ ghost: displayMode !== 'Table' }"
|
|
||||||
@click="displayMode = 'Table'"
|
|
||||||
>
|
|
||||||
<Icon class="mr-5" size="sm" iconName="table" />
|
|
||||||
{{ t("table") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
class="grey"
|
|
||||||
size="small"
|
|
||||||
:class="{ ghost: displayMode !== 'Statistics' }"
|
|
||||||
@click="displayMode = 'Statistics'"
|
|
||||||
>
|
|
||||||
<Icon class="mr-5" size="sm" iconName="statistics-bulleted" />
|
|
||||||
{{ t("statistics") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="no-data" v-else>{{ t("noData") }}</div>
|
|
||||||
<div class="trace-chart">
|
|
||||||
<component
|
<component
|
||||||
v-if="traceStore.currentTrace.endpointNames"
|
v-if="traceStore.currentTrace.endpointNames"
|
||||||
:is="displayMode"
|
:is="traceStore.displayMode"
|
||||||
:data="traceStore.traceSpans"
|
:data="traceStore.traceSpans"
|
||||||
:traceId="traceStore.currentTrace.traceIds[0].value"
|
:traceId="traceStore.currentTrace.traceIds[0].value"
|
||||||
:showBtnDetail="false"
|
:showBtnDetail="false"
|
||||||
@ -146,7 +26,8 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { ref, defineComponent } from "vue";
|
import { ref, computed, defineComponent } from "vue";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useTraceStore } from "@/store/modules/trace";
|
import { useTraceStore } from "@/store/modules/trace";
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
@ -155,7 +36,7 @@ import List from "./components/List.vue";
|
|||||||
import graphs from "./components/index";
|
import graphs from "./components/index";
|
||||||
import LogTable from "@/views/dashboard/related/components/LogTable/Index.vue";
|
import LogTable from "@/views/dashboard/related/components/LogTable/Index.vue";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
// import TraceDetailsTools from '@/views/dashboard'
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "TraceDetail",
|
name: "TraceDetail",
|
||||||
components: {
|
components: {
|
||||||
@ -163,18 +44,27 @@ export default defineComponent({
|
|||||||
List,
|
List,
|
||||||
LogTable,
|
LogTable,
|
||||||
},
|
},
|
||||||
setup() {
|
setup(props, ctx) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const traceStore = useTraceStore();
|
const traceStore = useTraceStore();
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
const traceId = ref<string>("");
|
const traceId = ref<string>("");
|
||||||
const displayMode = ref<string>("List");
|
const queries = useRoute().query;
|
||||||
|
const isFullView = computed(() => {
|
||||||
|
return queries?.fullview === "true" && queries?.portal === "true";
|
||||||
|
});
|
||||||
|
const displayMode = computed(() => {
|
||||||
|
return traceStore.displayMode;
|
||||||
|
});
|
||||||
const pageNum = ref<number>(1);
|
const pageNum = ref<number>(1);
|
||||||
const pageSize = 10;
|
const pageSize = 10;
|
||||||
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
||||||
dayjs(date).format(pattern);
|
dayjs(date).format(pattern);
|
||||||
const showTraceLogs = ref<boolean>(false);
|
const showTraceLogs = ref<boolean>(false);
|
||||||
|
|
||||||
|
function showTraceList() {
|
||||||
|
ctx.emit("show:list");
|
||||||
|
}
|
||||||
function handleClick(ids: string[] | any) {
|
function handleClick(ids: string[] | any) {
|
||||||
let copyValue = null;
|
let copyValue = null;
|
||||||
if (ids.length === 1) {
|
if (ids.length === 1) {
|
||||||
@ -215,6 +105,8 @@ export default defineComponent({
|
|||||||
searchTraceLogs();
|
searchTraceLogs();
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
isFullView,
|
||||||
|
showTraceList,
|
||||||
traceStore,
|
traceStore,
|
||||||
displayMode,
|
displayMode,
|
||||||
dateFormat,
|
dateFormat,
|
||||||
@ -233,17 +125,21 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.trace-detail {
|
.trace-detail {
|
||||||
|
// min-height: 300px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trace-chart {
|
.trace-chart {
|
||||||
height: calc(100% - 100px);
|
height: 100%;
|
||||||
|
// height: calc(100% - 100px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.trace-chart.full-view {
|
||||||
|
height: calc(100% - 1px) !important;
|
||||||
|
}
|
||||||
.trace-detail-wrapper {
|
.trace-detail-wrapper {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
|
@ -13,83 +13,122 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="flex-h row">
|
|
||||||
<div class="mr-5" v-if="dashboardStore.entity === EntityType[1].value">
|
|
||||||
<span class="grey mr-5">{{ t("service") }}:</span>
|
|
||||||
<Selector
|
|
||||||
size="small"
|
|
||||||
:value="state.service.value"
|
|
||||||
:options="traceStore.services"
|
|
||||||
placeholder="Select a service"
|
|
||||||
@change="changeField('service', $event)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mr-5" v-if="dashboardStore.entity !== EntityType[3].value">
|
|
||||||
<span class="grey mr-5">{{ t("instance") }}:</span>
|
|
||||||
<Selector
|
|
||||||
size="small"
|
|
||||||
:value="state.instance.value"
|
|
||||||
:options="traceStore.instances"
|
|
||||||
placeholder="Select a instance"
|
|
||||||
@change="changeField('instance', $event)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mr-5" v-if="dashboardStore.entity !== EntityType[2].value">
|
|
||||||
<span class="grey mr-5">{{ t("endpoint") }}:</span>
|
|
||||||
<Selector
|
|
||||||
size="small"
|
|
||||||
:value="state.endpoint.value"
|
|
||||||
:options="traceStore.endpoints"
|
|
||||||
placeholder="Select a endpoint"
|
|
||||||
:isRemote="true"
|
|
||||||
@change="changeField('endpoint', $event)"
|
|
||||||
@query="searchEndpoints"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mr-5">
|
|
||||||
<span class="grey mr-5">{{ t("status") }}:</span>
|
|
||||||
<Selector
|
|
||||||
size="small"
|
|
||||||
:value="state.status.value"
|
|
||||||
:options="Status"
|
|
||||||
placeholder="Select a status"
|
|
||||||
@change="changeField('status', $event)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="mr-5">
|
|
||||||
<span class="grey mr-5">{{ t("traceID") }}:</span>
|
|
||||||
<el-input size="small" v-model="traceId" class="traceId" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-h">
|
<div class="flex-h">
|
||||||
<!-- <div class="mr-5">
|
<div class="flex-h filter-container">
|
||||||
<span class="grey mr-5">{{ t("timeRange") }}:</span>
|
<div v-for="(filter, index) in arrayOfFilters" :key="index">
|
||||||
<TimePicker
|
<el-tooltip
|
||||||
:value="dateTime"
|
v-if="!activeFilter.length || activeFilter === filter.name"
|
||||||
position="bottom"
|
class="box-item"
|
||||||
format="YYYY-MM-DD HH:mm"
|
effect="dark"
|
||||||
@input="changeTimeRange"
|
:content="filter.description"
|
||||||
/>
|
placement="bottom-start"
|
||||||
</div> -->
|
>
|
||||||
<div class="mr-5">
|
<el-button
|
||||||
<span class="sm b grey mr-5">{{ t("duration") }}:</span>
|
type="success"
|
||||||
<el-input size="small" class="inputs mr-5" v-model="minTraceDuration" />
|
:class="[listOfActiveFilters.includes(filter.name) ? 'active-filter' : '']"
|
||||||
<span class="grey mr-5">-</span>
|
class="filter-btn mx-3"
|
||||||
<el-input size="small" class="inputs" v-model="maxTraceDuration" />
|
@click="setFilter(filter.name)"
|
||||||
|
>
|
||||||
|
<Icon size="sm" :iconName="filter.iconName" />
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="wrap-filters">
|
||||||
|
<div class="filter" v-if="activeFilter === 'service'">
|
||||||
|
<span class="grey mr-5">{{ t("service") }}:</span>
|
||||||
|
<Selector
|
||||||
|
size="small"
|
||||||
|
:value="state.service.value"
|
||||||
|
:options="traceStore.services"
|
||||||
|
placeholder="Select a service"
|
||||||
|
@change="changeField('service', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="filter"
|
||||||
|
v-if="
|
||||||
|
activeFilter === 'instance' && dashboardStore.entity !== EntityType[3].value
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span class="grey mr-5">{{ t("instance") }}:</span>
|
||||||
|
<Selector
|
||||||
|
size="small"
|
||||||
|
:value="state.instance.value"
|
||||||
|
:options="traceStore.instances"
|
||||||
|
placeholder="Select a instance"
|
||||||
|
@change="changeField('instance', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="filter"
|
||||||
|
v-if="
|
||||||
|
dashboardStore.entity !== EntityType[2].value && activeFilter === 'endpoints'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span class="grey mr-5">{{ t("endpoint") }}:</span>
|
||||||
|
<Selector
|
||||||
|
size="small"
|
||||||
|
:value="state.endpoint.value"
|
||||||
|
:options="traceStore.endpoints"
|
||||||
|
placeholder="Select a endpoint"
|
||||||
|
:isRemote="true"
|
||||||
|
@change="changeField('endpoint', $event)"
|
||||||
|
@query="searchEndpoints"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="activeFilter === 'status'" class="filter">
|
||||||
|
<span class="grey mr-5">{{ t("status") }}:</span>
|
||||||
|
<Selector
|
||||||
|
size="small"
|
||||||
|
:value="state.status.value"
|
||||||
|
:options="Status"
|
||||||
|
placeholder="Select a status"
|
||||||
|
@change="changeField('status', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="activeFilter === 'traceId'" class="filter">
|
||||||
|
<span class="grey mr-5">{{ t("traceID") }}:</span>
|
||||||
|
<el-input size="small" v-model="traceId" class="traceId" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="activeFilter === 'duration'" class="filter">
|
||||||
|
<span class="sm b grey mr-5">{{ t("duration") }}:</span>
|
||||||
|
<el-input size="small" class="inputs mr-5" v-model="minTraceDuration" />
|
||||||
|
<span class="grey mr-5">-</span>
|
||||||
|
<el-input size="small" class="inputs" v-model="maxTraceDuration" />
|
||||||
|
</div>
|
||||||
|
<keep-alive>
|
||||||
|
<ConditionTags
|
||||||
|
v-if="activeFilter === 'tags'"
|
||||||
|
ref="traceTagsComponent"
|
||||||
|
:type="'TRACE'"
|
||||||
|
@update="updateTags"
|
||||||
|
/>
|
||||||
|
</keep-alive>
|
||||||
|
<el-button
|
||||||
|
v-if="activeFilter"
|
||||||
|
class="search-btn filter-btn"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="searchTraces"
|
||||||
|
>
|
||||||
|
<Icon iconSize="sm" iconName="search" />
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="activeFilter"
|
||||||
|
class="search-btn filter-btn"
|
||||||
|
size="small"
|
||||||
|
type="danger"
|
||||||
|
@click="cancelSearch"
|
||||||
|
>
|
||||||
|
<Icon iconSize="sm" iconName="cancel" />
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<ConditionTags :type="'TRACE'" @update="updateTags" />
|
|
||||||
<el-button
|
|
||||||
class="search-btn"
|
|
||||||
size="small"
|
|
||||||
type="primary"
|
|
||||||
@click="searchTraces"
|
|
||||||
>
|
|
||||||
{{ t("search") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, watch } from "vue";
|
import { ref, reactive, watch, computed } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import { Status } from "../../data";
|
import { Status } from "../../data";
|
||||||
@ -101,11 +140,60 @@ import ConditionTags from "@/views/components/ConditionTags.vue";
|
|||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { EntityType } from "../../data";
|
import { EntityType } from "../../data";
|
||||||
|
|
||||||
|
interface filtersObject {
|
||||||
|
name: string;
|
||||||
|
iconName: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const traceStore = useTraceStore();
|
const traceStore = useTraceStore();
|
||||||
|
const listOfActiveFilters = ref<string[]>([]);
|
||||||
|
const arrayOfFilters = ref<filtersObject[]>([
|
||||||
|
{
|
||||||
|
name: "service",
|
||||||
|
iconName: "cloud_queue",
|
||||||
|
description: "Service",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "instance",
|
||||||
|
iconName: "storage",
|
||||||
|
description: "Instance",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "status",
|
||||||
|
iconName: "device_hub",
|
||||||
|
description: "Status",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "duration",
|
||||||
|
iconName: "av_timer",
|
||||||
|
description: "Duration",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "traceId",
|
||||||
|
iconName: "timeline",
|
||||||
|
description: "Trace ID",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tags",
|
||||||
|
iconName: "epic",
|
||||||
|
description: "Tags",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "endpoints",
|
||||||
|
iconName: "device_hub",
|
||||||
|
description: "Endpoints",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const activeFilter = ref<string>("");
|
||||||
|
function setFilter(filter: string) {
|
||||||
|
activeFilter.value = filter;
|
||||||
|
}
|
||||||
|
|
||||||
const traceId = ref<string>("");
|
const traceId = ref<string>("");
|
||||||
const minTraceDuration = ref<string>("");
|
const minTraceDuration = ref<string>("");
|
||||||
const maxTraceDuration = ref<string>("");
|
const maxTraceDuration = ref<string>("");
|
||||||
@ -118,6 +206,8 @@ const state = reactive<any>({
|
|||||||
service: { value: "", label: "" },
|
service: { value: "", label: "" },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const traceTagsComponent = ref<InstanceType<typeof ConditionTags> | null>(null);
|
||||||
|
|
||||||
// const dateTime = computed(() => [
|
// const dateTime = computed(() => [
|
||||||
// appStore.durationRow.start,
|
// appStore.durationRow.start,
|
||||||
// appStore.durationRow.end,
|
// appStore.durationRow.end,
|
||||||
@ -167,7 +257,92 @@ async function getInstances(id?: string) {
|
|||||||
}
|
}
|
||||||
state.instance = traceStore.instances[0];
|
state.instance = traceStore.instances[0];
|
||||||
}
|
}
|
||||||
|
function addToActiveFilterList() {
|
||||||
|
listOfActiveFilters.value.push(activeFilter.value);
|
||||||
|
}
|
||||||
|
function removeFromActiveFilters() {
|
||||||
|
listOfActiveFilters.value = listOfActiveFilters.value.filter(
|
||||||
|
(filter) => filter !== activeFilter.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function cancelSearch() {
|
||||||
|
switch (activeFilter.value) {
|
||||||
|
case "status":
|
||||||
|
state.status = { label: "All", value: "ALL" };
|
||||||
|
break;
|
||||||
|
case "instance":
|
||||||
|
state.instance = { value: "0", label: "All" };
|
||||||
|
break;
|
||||||
|
case "endpoints":
|
||||||
|
state.endpoint = { value: "0", label: "All" };
|
||||||
|
break;
|
||||||
|
case "service":
|
||||||
|
state.service = { value: "", label: "" };
|
||||||
|
break;
|
||||||
|
case "duration":
|
||||||
|
minTraceDuration.value = "";
|
||||||
|
maxTraceDuration.value = "";
|
||||||
|
break;
|
||||||
|
case "tags":
|
||||||
|
tagsList.value = [];
|
||||||
|
tagsMap.value = [];
|
||||||
|
updateTags({ tagsMap: [], tagsList: [] });
|
||||||
|
traceTagsComponent.value?.emptyTags();
|
||||||
|
break;
|
||||||
|
case "traceId":
|
||||||
|
traceId.value = "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
removeFromActiveFilters();
|
||||||
|
activeFilter.value = "";
|
||||||
|
traceStore.activeFilter = "";
|
||||||
|
searchTraces();
|
||||||
|
}
|
||||||
|
function handleActiveFilterState() {
|
||||||
|
switch (activeFilter.value) {
|
||||||
|
case "traceId":
|
||||||
|
if (!traceId.value.length) return;
|
||||||
|
traceStore.setActiveFilter(activeFilter.value);
|
||||||
|
addToActiveFilterList();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "tags":
|
||||||
|
if (!tagsList.value.length) return;
|
||||||
|
traceStore.setActiveFilter(activeFilter.value);
|
||||||
|
addToActiveFilterList();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "duration":
|
||||||
|
if (!minTraceDuration.value.length || !maxTraceDuration.value.length) return;
|
||||||
|
traceStore.setActiveFilter(activeFilter.value);
|
||||||
|
addToActiveFilterList();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "service":
|
||||||
|
traceStore.setActiveFilter(activeFilter.value);
|
||||||
|
addToActiveFilterList();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "instance":
|
||||||
|
traceStore.setActiveFilter(activeFilter.value);
|
||||||
|
addToActiveFilterList();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "status":
|
||||||
|
traceStore.setActiveFilter(activeFilter.value);
|
||||||
|
addToActiveFilterList();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "endpoints":
|
||||||
|
traceStore.setActiveFilter(activeFilter.value);
|
||||||
|
addToActiveFilterList();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
function searchTraces() {
|
function searchTraces() {
|
||||||
|
handleActiveFilterState();
|
||||||
|
activeFilter.value = "";
|
||||||
let endpoint = "",
|
let endpoint = "",
|
||||||
instance = "";
|
instance = "";
|
||||||
if (dashboardStore.entity === EntityType[2].value) {
|
if (dashboardStore.entity === EntityType[2].value) {
|
||||||
@ -185,8 +360,8 @@ function searchTraces() {
|
|||||||
serviceInstanceId: instance || state.instance.id || undefined,
|
serviceInstanceId: instance || state.instance.id || undefined,
|
||||||
traceState: state.status.value || "ALL",
|
traceState: state.status.value || "ALL",
|
||||||
queryDuration: appStore.durationTime,
|
queryDuration: appStore.durationTime,
|
||||||
minTraceDuration: appStore.minTraceDuration || undefined,
|
minTraceDuration: minTraceDuration.value || undefined,
|
||||||
maxTraceDuration: appStore.maxTraceDuration || undefined,
|
maxTraceDuration: maxTraceDuration.value || undefined,
|
||||||
queryOrder: "BY_DURATION",
|
queryOrder: "BY_DURATION",
|
||||||
tags: tagsMap.value.length ? tagsMap.value : undefined,
|
tags: tagsMap.value.length ? tagsMap.value : undefined,
|
||||||
paging: { pageNum: 1, pageSize: 15, needTotal: true },
|
paging: { pageNum: 1, pageSize: 15, needTotal: true },
|
||||||
@ -260,4 +435,28 @@ watch(
|
|||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.filter-container {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.wrap-filters {
|
||||||
|
padding: 0 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
.filter {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filter-btn {
|
||||||
|
height: 18px;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
.active-filter.filter-btn {
|
||||||
|
background: rgba(4, 147, 114, 1) !important;
|
||||||
|
span {
|
||||||
|
color: #275410 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -110,6 +110,7 @@ function changeSort(opt: Option[] | any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function selectTrace(i: Trace) {
|
async function selectTrace(i: Trace) {
|
||||||
|
traceStore.setCurrentView("traceDetails");
|
||||||
traceStore.setCurrentTrace(i);
|
traceStore.setCurrentTrace(i);
|
||||||
selectedKey.value = i.key;
|
selectedKey.value = i.key;
|
||||||
if (i.traceIds.length) {
|
if (i.traceIds.length) {
|
||||||
@ -136,6 +137,7 @@ async function queryTraces() {
|
|||||||
border-bottom: 1px solid #c1c5ca41;
|
border-bottom: 1px solid #c1c5ca41;
|
||||||
border-right: 1px solid #c1c5ca41;
|
border-right: 1px solid #c1c5ca41;
|
||||||
height: 35px;
|
height: 35px;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selectors {
|
.selectors {
|
||||||
@ -163,11 +165,11 @@ async function queryTraces() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.trace-t {
|
.trace-t {
|
||||||
width: 420px;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.list {
|
||||||
width: 400px;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trace-tr {
|
.trace-tr {
|
||||||
|
@ -26,7 +26,7 @@ module.exports = {
|
|||||||
proxy: {
|
proxy: {
|
||||||
"/graphql": {
|
"/graphql": {
|
||||||
target: `${
|
target: `${
|
||||||
process.env.SW_PROXY_TARGET || "http://demo.skywalking.apache.org"
|
process.env.SW_PROXY_TARGET || "https://demo.sourceplus.plus:12800"
|
||||||
}`,
|
}`,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user