feat: support collapsing and expanding for the event widget (#503)

This commit is contained in:
Fine0830
2025-10-10 15:35:48 +08:00
committed by GitHub
parent 51817f32de
commit 4bf57ec7c5
13 changed files with 133 additions and 40 deletions

View File

@@ -413,5 +413,6 @@ const msg = {
spanName: "Span name",
parentId: "Parent ID",
shareTrace: "Share This Trace",
eventDefaultCollapse: "Default Collapse",
};
export default msg;

View File

@@ -413,5 +413,6 @@ const msg = {
spanName: "Nombre de Lapso",
parentId: "ID Padre",
shareTrace: "Compartir Traza",
eventDefaultCollapse: "Default Collapse",
};
export default msg;

View File

@@ -411,5 +411,6 @@ const msg = {
spanName: "跨度名称",
parentId: "父ID",
shareTrace: "分享Trace",
eventDefaultCollapse: "默认折叠",
};
export default msg;

View File

@@ -253,9 +253,13 @@ export const dashboardStore = defineStore({
setTopology(show: boolean) {
this.showTopology = show;
},
setConfigs(param: LayoutConfig) {
const actived = this.activedGridItem.split("-");
setLayouts(param: LayoutConfig[]) {
this.layout = param;
},
setConfigs(param: LayoutConfig, gridIndex?: string) {
const actived = gridIndex || this.activedGridItem.split("-");
const index = this.layout.findIndex((d: LayoutConfig) => actived[0] === d.i);
if (actived.length === 3) {
const tabIndex = Number(actived[1]);
const itemIndex = (this.layout[index].children || [])[tabIndex].children.findIndex(
@@ -270,11 +274,13 @@ export const dashboardStore = defineStore({
this.setCurrentTabItems((this.layout[index].children || [])[tabIndex].children);
return;
}
this.layout[index] = {
...this.layout[index],
const layout = JSON.parse(JSON.stringify(this.layout));
layout[index] = {
...layout[index],
...param,
};
this.selectedGrid = this.layout[index];
this.setLayouts(layout);
this.selectedGrid = layout[index];
},
setWidget(param: LayoutConfig) {
for (let i = 0; i < this.layout.length; i++) {

View File

@@ -36,8 +36,8 @@ export const eventStore = defineStore({
state: (): eventState => ({
loading: false,
events: [],
instances: [{ value: "", label: "All" }],
endpoints: [{ value: "", label: "All" }],
instances: [{ value: "0", label: "All" }],
endpoints: [{ value: "0", label: "All" }],
condition: null,
}),
actions: {
@@ -58,7 +58,7 @@ export const eventStore = defineStore({
if (response.errors) {
return response;
}
this.instances = [{ value: "", label: "All" }, ...response.data.pods];
this.instances = [{ value: "0", label: "All" }, ...response.data.pods];
return response;
},
async getEndpoints(keyword?: string) {
@@ -75,7 +75,7 @@ export const eventStore = defineStore({
if (response.errors) {
return response;
}
this.endpoints = [{ value: "", label: "All" }, ...response.data.pods];
this.endpoints = [{ value: "0", label: "All" }, ...response.data.pods];
return response;
},
async getEvents() {

View File

@@ -48,6 +48,7 @@ export interface LayoutConfig {
id?: string;
associate?: { widgetId: string }[];
eventAssociate?: boolean;
eventDefaultCollapse?: boolean;
filters?: Filters;
relatedTrace?: RelatedTrace;
subExpressions?: string[];

View File

@@ -15,6 +15,10 @@ limitations under the License. -->
<div class="config-label flex-h mr-20">{{ t("enableAssociate") }}</div>
<el-switch v-model="eventAssociate" active-text="Yes" inactive-text="No" @change="updateConfig" />
</div>
<div class="config-item flex-h">
<div class="config-label flex-h mr-20">{{ t("eventDefaultCollapse") }}</div>
<el-switch v-model="eventDefaultCollapse" active-text="Yes" inactive-text="No" @change="updateConfig" />
</div>
<ConfigurationFooter />
</template>
<script lang="ts" setup>
@@ -28,10 +32,19 @@ limitations under the License. -->
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const eventAssociate = ref(dashboardStore.selectedGrid?.eventAssociate || false);
const eventDefaultCollapse = ref(
dashboardStore.selectedGrid?.eventDefaultCollapse === undefined
? true
: dashboardStore.selectedGrid?.eventDefaultCollapse,
);
function updateConfig() {
const { selectedGrid } = dashboardStore;
dashboardStore.selectWidget({ ...selectedGrid, eventAssociate: eventAssociate.value } as LayoutConfig);
dashboardStore.selectWidget({
...selectedGrid,
eventAssociate: eventAssociate.value,
eventDefaultCollapse: eventDefaultCollapse.value,
} as LayoutConfig);
}
</script>

View File

@@ -14,10 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<div class="event-wrapper flex-v">
<div class="operations">
<span class="cp" @click="handleCollapse">
<Icon iconName="sort" size="middle" />
</span>
<el-popover placement="bottom" trigger="click" :width="100" v-if="dashboardStore.editMode">
<template #reference>
<span class="delete cp">
<Icon iconName="ellipsis_v" size="middle" class="operation" />
<span class="cp">
<Icon iconName="ellipsis_v" size="middle" />
</span>
</template>
<div class="tools" @click="editConfig">
@@ -27,15 +31,20 @@ limitations under the License. -->
<span>{{ t("delete") }}</span>
</div>
</el-popover>
<div class="header">
<Header :needQuery="needQuery" />
</div>
<div class="event">
<div class="event-inspector" v-if="collapsedState"> Event Timeline Inspector </div>
<Transition name="collapse" v-else>
<div class="timeline">
<Header :needQuery="needQuery" />
<div class="event mt-10">
<Content :data="data" />
</div>
</div>
</Transition>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, onMounted, nextTick } from "vue";
import type { PropType } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
@@ -54,6 +63,17 @@ limitations under the License. -->
});
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const collapsedState = ref(true);
const originalState = ref({ h: props.data.h });
onMounted(() => {
collapsedState.value = props.data.eventDefaultCollapse === undefined ? true : props.data.eventDefaultCollapse;
if (collapsedState.value) {
dashboardStore.setConfigs({ ...props.data, ...{ h: 3 } }, props.data.i);
} else {
dashboardStore.setConfigs({ ...props.data, ...originalState.value }, props.data.i);
}
});
function removeWidget() {
dashboardStore.removeControls(props.data);
@@ -62,6 +82,24 @@ limitations under the License. -->
dashboardStore.setConfigPanel(true);
dashboardStore.selectWidget(props.data);
}
function handleCollapse() {
dashboardStore.activeGridItem(props.data.i);
collapsedState.value = !collapsedState.value;
if (collapsedState.value) {
dashboardStore.setConfigs({ ...props.data, ...{ h: 3 } });
} else {
dashboardStore.setConfigs({ ...props.data, ...originalState.value });
}
}
watch(
() => props.data.h,
(newHeight) => {
if (!collapsedState.value) {
originalState.value = { h: newHeight };
}
},
);
</script>
<style lang="scss" scoped>
.event-wrapper {
@@ -72,14 +110,14 @@ limitations under the License. -->
overflow: auto;
}
.delete {
.operations {
position: absolute;
top: 5px;
right: 3px;
z-index: 9999;
}
.header {
.timeline {
padding: 10px;
font-size: $font-size-smaller;
border-bottom: 1px solid $border-color;
@@ -103,4 +141,31 @@ limitations under the License. -->
width: 100%;
height: calc(100% - 80px);
}
.collapse-enter-active,
.collapse-leave-active {
transition: all 0.8s ease;
overflow: hidden;
}
.collapse-enter-from,
.collapse-leave-to {
opacity: 0;
max-height: 0;
transform: translateY(-10px);
}
.collapse-enter-to,
.collapse-leave-from {
opacity: 1;
max-height: 1000px;
transform: translateY(0);
}
.event-inspector {
text-align: center;
line-height: 45px;
font-size: $font-size-normal;
font-weight: bold;
}
</style>

View File

@@ -95,6 +95,8 @@ limitations under the License. -->
:is-draggable="dashboardStore.editMode"
:is-resizable="dashboardStore.editMode"
@layout-updated="layoutUpdatedEvent"
:vertical-compact="true"
:auto-size="true"
>
<grid-item
v-for="item in dashboardStore.currentTabItems"

View File

@@ -122,10 +122,10 @@ limitations under the License. -->
};
const metrics: { [key: string]: { source: { [key: string]: unknown }; typesOfMQE: string[] } } =
(await useDashboardQueryProcessor([config])) || {};
const params = metrics[data.value.i];
const params = metrics[data.value.i] || {};
loading.value = false;
state.source = params.source || {};
typesOfMQE.value = params.typesOfMQE;
typesOfMQE.value = params.typesOfMQE || [];
}
function removeWidget() {

View File

@@ -23,6 +23,8 @@ limitations under the License. -->
v-loading.fullscreen.lock="loading"
element-loading-text="Loading..."
element-loading-background="rgba(122, 122, 122, 0.8)"
:vertical-compact="true"
:auto-size="true"
>
<grid-item
v-for="item in dashboardStore.layout"

View File

@@ -51,6 +51,7 @@ limitations under the License. -->
width: 0,
height: 0,
};
visTimeline();
useThrottleFn(resize, 500)();
});

View File

@@ -86,8 +86,8 @@ limitations under the License. -->
const pageSize = 20;
const pageNum = ref<number>(1);
const state = reactive<any>({
instance: { value: "", label: "All", id: "" },
endpoint: { value: "", label: "All", id: "" },
instance: { value: "0", label: "All" },
endpoint: { value: "0", label: "All" },
eventType: { value: "", label: "All" },
});
const total = computed(() =>
@@ -99,8 +99,8 @@ limitations under the License. -->
async function init() {
fetchSelectors();
await queryEvents();
state.instance = { value: "", label: "All" };
state.endpoint = { value: "", label: "All" };
state.instance = { value: "0", label: "All" };
state.endpoint = { value: "0", label: "All" };
}
function fetchSelectors() {
@@ -138,13 +138,13 @@ limitations under the License. -->
state.instance = eventStore.instances[0];
}
async function queryEvents() {
let endpoint = state.endpoint.value,
instance = state.instance.value;
let endpoint = state.endpoint.value === "0" ? undefined : state.endpoint.value,
instance = state.instance.value === "0" ? undefined : state.instance.value;
if (dashboardStore.entity === EntityType[2].value) {
endpoint = selectorStore.currentPod && selectorStore.currentPod.id;
endpoint = selectorStore.currentPod?.id;
}
if (dashboardStore.entity === EntityType[3].value) {
instance = selectorStore.currentPod && selectorStore.currentPod.id;
instance = selectorStore.currentPod?.id;
}
if (!selectorStore.currentService) {
return;