refactor: optimize data types for widgets and dashboards (#490)

This commit is contained in:
Fine0830
2025-08-14 18:25:40 +08:00
committed by GitHub
parent e885b61353
commit 54a700bf19
141 changed files with 972 additions and 743 deletions

View File

@@ -24,6 +24,7 @@ limitations under the License. -->
import { useDashboardStore } from "@/store/modules/dashboard";
import Dashboard from "./dashboard/Edit.vue";
import { useI18n } from "vue-i18n";
import { DashboardItem } from "@/types/dashboard";
const route = useRoute();
const { t } = useI18n();
@@ -38,7 +39,7 @@ limitations under the License. -->
dashboardStore.setMode(false);
await dashboardStore.setDashboards();
const item = dashboardStore.dashboards.find(
(d: { name: string; isRoot: boolean; layer: string; entity: string }) =>
(d: DashboardItem) =>
d.layer === dashboardStore.layerId && [EntityType[0].value, EntityType[1].value].includes(d.entity) && d.isRoot,
);
if (!item) {

View File

@@ -87,7 +87,7 @@ limitations under the License. -->
alarmStore.alarms.length === pageSize ? pageSize * pageNum.value + 1 : pageSize * pageNum.value,
);
const maxRange = computed(() =>
getMaxRange(appStore.coldStageMode ? appStore.recordsTTL.coldNormal : appStore.recordsTTL.normal),
getMaxRange(appStore.coldStageMode ? appStore.recordsTTL?.coldNormal || 0 : appStore.recordsTTL?.normal || 0),
);
refreshAlarms({ pageNum: 1 });

View File

@@ -28,7 +28,7 @@ limitations under the License. -->
:destroy-on-close="true"
@closed="dashboardStore.setConfigPanel(false)"
>
<component :is="dashboardStore.selectedGrid.type" />
<component :is="dashboardStore.selectedGrid?.type" />
</el-dialog>
<el-dialog
v-model="dashboardStore.showLinkConfig"
@@ -77,9 +77,9 @@ limitations under the License. -->
dashboardStore.setLayout(setWidgetsID(layout.children || []));
if (p.entity) {
dashboardStore.setCurrentDashboard({
layer: p.layerId,
entity: p.entity,
name: p.name,
layer: p.layerId as string,
entity: p.entity as string,
name: p.name as string,
id: c.id,
isRoot: layout.isRoot,
});
@@ -112,7 +112,7 @@ limitations under the License. -->
}
onUnmounted(() => {
dashboardStore.setCurrentDashboard({});
dashboardStore.setCurrentDashboard(null);
});
return {

View File

@@ -578,14 +578,17 @@ limitations under the License. -->
name: value,
});
dashboards.value = dashboardStore.dashboards.map((item: DashboardItem) => {
if (dashboardStore.currentDashboard.id === item.id) {
item = dashboardStore.currentDashboard;
if (dashboardStore.currentDashboard?.id === item.id) {
item = dashboardStore.currentDashboard as DashboardItem;
}
return item;
});
dashboardStore.resetDashboards(dashboards.value);
sessionStorage.setItem("dashboards", JSON.stringify(dashboards.value));
sessionStorage.removeItem(key);
if (!dashboardStore.currentDashboard) {
return;
}
const str = [
dashboardStore.currentDashboard.layer,
dashboardStore.currentDashboard.entity,

View File

@@ -81,8 +81,8 @@ limitations under the License. -->
init();
async function init() {
dashboardStore.setLayer(route.params.layer);
dashboardStore.setEntity(route.params.entity);
dashboardStore.setLayer(route.params.layer as string);
dashboardStore.setEntity(route.params.entity as string);
const { auto, autoPeriod } = config.value;
if (auto) {
await setDuration();
@@ -102,30 +102,30 @@ limitations under the License. -->
async function setSelector() {
const { serviceId, podId, processId, destServiceId, destPodId, destProcessId, entity } = route.params;
if (serviceId) {
await selectorStore.getService(serviceId);
await selectorStore.getService(serviceId as string);
}
if (
[EntityType[4].value, EntityType[5].value, EntityType[6].value, EntityType[7].value].includes(
entity as string,
)
) {
await selectorStore.getService(destServiceId, true);
await selectorStore.getService(destServiceId as string, true);
}
if ([EntityType[3].value, EntityType[5].value, EntityType[7].value].includes(entity as string)) {
await selectorStore.getInstance(podId);
await selectorStore.getInstance(podId as string);
}
if ([EntityType[2].value, EntityType[6].value].includes(entity as string)) {
await selectorStore.getEndpoint(podId);
await selectorStore.getEndpoint(podId as string);
}
if (EntityType[6].value === entity) {
await selectorStore.getEndpoint(destPodId, true);
await selectorStore.getEndpoint(destPodId as string, true);
}
if ([EntityType[5].value, EntityType[7].value].includes(entity as string)) {
await selectorStore.getInstance(destPodId, true);
await selectorStore.getInstance(destPodId as string, true);
}
if (EntityType[7].value === entity) {
selectorStore.getProcess(processId);
selectorStore.getProcess(destProcessId, true);
selectorStore.getProcess(processId as string);
selectorStore.getProcess(destProcessId as string, true);
}
}
async function queryMetrics() {

View File

@@ -25,15 +25,15 @@ limitations under the License. -->
<div v-else>
<label>{{ t("auto") }}</label>
<el-switch class="mr-5" v-model="auto" style="height: 25px" />
<Selector v-model="freshOpt" :options="RefreshOptions" size="small" />
<Selector style="width: 200px" v-model="freshOpt" :options="RefreshOptions" />
<div class="mt-5">
<label>{{ t("period") }}</label>
<el-input class="auto-period" size="small" type="number" v-model="period" min="1" />
<el-input class="auto-period" type="number" v-model="period" min="1" />
<span class="ml-5">{{ t("second") }}</span>
<i class="ml-10">{{ t("timeReload") }}</i>
</div>
</div>
<el-button size="small" type="primary" class="mt-20" @click="getLink">{{ t("generateLink") }}</el-button>
<el-button type="primary" class="mt-20" @click="getLink">{{ t("generateLink") }}</el-button>
<div v-show="widgetLink" class="mt-10">
<span @click="viewPage" class="link">
{{ host + widgetLink }}

View File

@@ -49,12 +49,12 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import { EntityType } from "../data";
import type { DashboardItem } from "@/types/dashboard";
import type { DashboardItem, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const instanceDashboardName = ref<boolean>(dashboardStore.selectedGrid.instanceDashboardName);
const processDashboardName = ref<number>(dashboardStore.selectedGrid.processDashboardName);
const instanceDashboardName = ref<string>(dashboardStore.selectedGrid?.instanceDashboardName || "");
const processDashboardName = ref<string>(dashboardStore.selectedGrid?.processDashboardName || "");
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
const instanceDashboards: Array<DashboardItem & { label: string; value: string }> = [];
const processDashboards: Array<DashboardItem & { label: string; value: string }> = [];
@@ -76,14 +76,14 @@ limitations under the License. -->
}
function applyConfig() {
dashboardStore.setConfigs(dashboardStore.selectedGrid);
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
dashboardStore.setConfigPanel(false);
}
function changeDashboard(param: { [key: string]: unknown }) {
dashboardStore.selectWidget({
...dashboardStore.selectedGrid,
...param,
});
} as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -28,23 +28,22 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { ref } from "vue";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const originConfig = dashboardStore.selectedGrid;
const eventAssociate = ref(dashboardStore.selectedGrid.eventAssociate || false);
const eventAssociate = ref(dashboardStore.selectedGrid?.eventAssociate || false);
function updateConfig() {
dashboardStore.selectedGrid = {
...dashboardStore.selectedGrid,
eventAssociate,
};
dashboardStore.selectWidget(dashboardStore.selectedGrid);
const { selectedGrid } = dashboardStore;
dashboardStore.selectWidget({ ...selectedGrid, eventAssociate: eventAssociate.value } as LayoutConfig);
}
function applyConfig() {
dashboardStore.setConfigPanel(false);
dashboardStore.setConfigs(dashboardStore.selectedGrid);
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
}
function cancelConfig() {

View File

@@ -33,13 +33,14 @@ limitations under the License. -->
import { useDashboardStore } from "@/store/modules/dashboard";
import { ElMessage } from "element-plus";
import { WidgetType, ListEntity } from "@/views/dashboard/data";
import type { LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const originConfig = dashboardStore.selectedGrid;
const expressions = reactive<{ [key: string]: string }>({});
const widgetTabs = computed(() =>
(dashboardStore.selectedGrid.children || []).filter((child: any) =>
(dashboardStore.selectedGrid?.children || []).filter((child: any) =>
child.children.find(
(item: any) =>
item.type === WidgetType.Widget &&
@@ -48,7 +49,7 @@ limitations under the License. -->
),
);
for (const child of originConfig.children || []) {
for (const child of originConfig?.children || []) {
expressions[child.name] = child.expression || "";
}
function changeExpression(name: string) {
@@ -56,7 +57,7 @@ limitations under the License. -->
ElMessage.error("Only support the is_present function");
return;
}
const children = JSON.parse(JSON.stringify(dashboardStore.selectedGrid.children || []));
const children = JSON.parse(JSON.stringify(dashboardStore.selectedGrid?.children || []));
for (const item of children) {
if (item.name === name) {
@@ -64,11 +65,11 @@ limitations under the License. -->
}
}
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, children });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, children } as LayoutConfig);
}
function applyConfig() {
dashboardStore.setConfigPanel(false);
dashboardStore.setConfigs(dashboardStore.selectedGrid);
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
}
function cancelConfig() {

View File

@@ -78,10 +78,12 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { ref } from "vue";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { LayoutConfig, TextConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const originConfig = dashboardStore.selectedGrid;
const graph = originConfig.graph || {};
const graph = (originConfig?.graph as TextConfig) || {};
const url = ref(graph.url || "");
const backgroundColor = ref(graph.backgroundColor || "green");
const fontColor = ref(graph.fontColor || "white");
@@ -112,14 +114,14 @@ limitations under the License. -->
function changeConfig(param: { [key: string]: unknown }) {
const { selectedGrid } = dashboardStore;
const graph = {
...selectedGrid.graph,
...selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...selectedGrid, graph });
dashboardStore.selectWidget({ ...selectedGrid, graph } as LayoutConfig);
}
function applyConfig() {
dashboardStore.setConfigPanel(false);
dashboardStore.setConfigs(dashboardStore.selectedGrid);
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
}
function cancelConfig() {

View File

@@ -30,11 +30,12 @@ limitations under the License. -->
import { ref } from "vue";
import { useDashboardStore } from "@/store/modules/dashboard";
import { validateAndSanitizeUrl } from "@/utils/validateAndSanitizeUrl";
import type { LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const originConfig = dashboardStore.selectedGrid;
const widget = originConfig.widget || {};
const widget = originConfig?.widget || {};
const url = ref(widget.url || "");
const urlError = ref("");
@@ -55,10 +56,10 @@ limitations under the License. -->
const { selectedGrid } = dashboardStore;
const widget = {
...dashboardStore.selectedGrid.widget,
...dashboardStore.selectedGrid?.widget,
[key]: param[key], // Use the sanitized URL directly, no need for decodeURIComponent
};
dashboardStore.selectWidget({ ...selectedGrid, widget });
dashboardStore.selectWidget({ ...selectedGrid, widget } as LayoutConfig);
}
function applyConfig() {
@@ -66,7 +67,7 @@ limitations under the License. -->
return; // Don't apply if there's a validation error
}
dashboardStore.setConfigPanel(false);
dashboardStore.setConfigs(dashboardStore.selectedGrid);
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
}
function cancelConfig() {

View File

@@ -74,11 +74,12 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { ref } from "vue";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { TimeRangeConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const originConfig = dashboardStore.selectedGrid;
const graph = originConfig.graph || {};
const graph = (originConfig?.graph as TimeRangeConfig) || {};
const backgroundColor = ref(graph.backgroundColor || "green");
const fontColor = ref(graph.fontColor || "white");
const fontSize = ref<number>(graph.fontSize || 12);
@@ -107,14 +108,14 @@ limitations under the License. -->
function changeConfig(param: { [key: string]: unknown }) {
const { selectedGrid } = dashboardStore;
const graph = {
...selectedGrid.graph,
...selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...selectedGrid, graph });
dashboardStore.selectWidget({ ...selectedGrid, graph } as LayoutConfig);
}
function applyConfig() {
dashboardStore.setConfigPanel(false);
dashboardStore.setConfigs(dashboardStore.selectedGrid);
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
}
function cancelConfig() {

View File

@@ -34,24 +34,25 @@ limitations under the License. -->
import { useDashboardStore } from "@/store/modules/dashboard";
import { DepthList } from "../data";
import type { Option } from "@/types/app";
import type { TopologyConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph || {};
const showDepth = ref<boolean>(graph.showDepth);
const depth = ref<number>(graph.depth || 2);
const graph = (dashboardStore.selectedGrid?.graph as TopologyConfig) || {};
const showDepth = ref<boolean>(graph?.showDepth || false);
const depth = ref<number>(graph?.depth || 2);
function applyConfig() {
dashboardStore.setConfigs(dashboardStore.selectedGrid);
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
dashboardStore.setConfigPanel(false);
}
function changeConfig(param: { [key: string]: unknown }) {
const { selectedGrid } = dashboardStore;
const graph = {
...selectedGrid.graph,
...selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...selectedGrid, graph });
dashboardStore.selectWidget({ ...selectedGrid, graph } as LayoutConfig);
}
function changeDepth(opt: Option[] | any) {
const val = opt[0].value;

View File

@@ -32,16 +32,16 @@ limitations under the License. -->
:data="states.source"
:config="{
...graph,
decorations: dashboardStore.selectedGrid.graph?.decorations,
legend: dashboardStore.selectedGrid.graph?.legend,
i: dashboardStore.selectedGrid.i,
metricConfig: dashboardStore.selectedGrid.metricConfig,
relatedTrace: dashboardStore.selectedGrid.relatedTrace,
expressions: dashboardStore.selectedGrid.expressions || [],
typesOfMQE: dashboardStore.selectedGrid.typesOfMQE || [],
subExpressions: dashboardStore.selectedGrid.subExpressions || [],
subTypesOfMQE: dashboardStore.selectedGrid.subTypesOfMQE || [],
valueRelatedDashboard: dashboardStore.selectedGrid.valueRelatedDashboard,
valueMappings: dashboardStore.selectedGrid?.graph?.valueMappings,
legend: dashboardStore.selectedGrid?.graph?.legend,
i: dashboardStore.selectedGrid?.i,
metricConfig: dashboardStore.selectedGrid?.metricConfig,
relatedTrace: dashboardStore.selectedGrid?.relatedTrace,
expressions: dashboardStore.selectedGrid?.expressions || [],
typesOfMQE: dashboardStore.selectedGrid?.typesOfMQE || [],
subExpressions: dashboardStore.selectedGrid?.subExpressions || [],
subTypesOfMQE: dashboardStore.selectedGrid?.subTypesOfMQE || [],
valueRelatedDashboard: dashboardStore.selectedGrid?.valueRelatedDashboard,
}"
:needQuery="true"
@expressionTips="getErrors"
@@ -88,6 +88,7 @@ limitations under the License. -->
import type { Option } from "@/types/app";
import graphs from "../graphs";
import CustomOptions from "./widget/index";
import type { LayoutConfig } from "@/types/dashboard";
export default defineComponent({
name: "WidgetEdit",
@@ -106,23 +107,21 @@ limitations under the License. -->
const states = reactive<{
activeNames: string;
source: unknown;
index: string;
index: string | undefined;
visType: Option[];
}>({
activeNames: "1",
source: {},
index: dashboardStore.selectedGrid.i,
index: dashboardStore.selectedGrid?.i,
visType: [],
});
const originConfig = dashboardStore.selectedGrid;
const widget = computed(() => dashboardStore.selectedGrid.widget || {});
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
const widget = computed(() => dashboardStore.selectedGrid?.widget || {});
const graph = computed(() => dashboardStore.selectedGrid?.graph || {});
const title = computed(() => encodeURIComponent(widget.value.title || ""));
const tips = computed(() => encodeURIComponent(widget.value.tips || ""));
const hasAssociate = computed(() =>
["Bar", "Line", "Area", "TopList"].includes(
dashboardStore.selectedGrid.graph && dashboardStore.selectedGrid.graph.type,
),
["Bar", "Line", "Area", "TopList"].includes(dashboardStore.selectedGrid?.graph?.type || ""),
);
function getSource(source: unknown) {
@@ -140,7 +139,7 @@ limitations under the License. -->
function applyConfig() {
dashboardStore.setConfigPanel(false);
dashboardStore.setConfigs(dashboardStore.selectedGrid);
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
}
function cancelConfig() {

View File

@@ -33,24 +33,25 @@ limitations under the License. -->
import { useDashboardStore } from "@/store/modules/dashboard";
import getDashboard from "@/hooks/useDashboardsSession";
import type { Option } from "@/types/app";
import type { DashboardItem, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const associate = dashboardStore.selectedGrid.associate || [];
const associate = dashboardStore.selectedGrid?.associate || [];
const widgetIds = ref<string[]>(associate.map((d: { widgetId: string }) => d.widgetId));
const widgets: any = computed(() => {
const widgetList = getDashboard(dashboardStore.currentDashboard).widgets;
const widgetList = getDashboard(dashboardStore.currentDashboard as DashboardItem).widgets;
const items = [];
for (const d of widgetList) {
const isLinear = ["Bar", "Line", "Area"].includes((d.graph && d.graph.type) || "");
if (isLinear && d.id && dashboardStore.selectedGrid.id !== d.id) {
if (isLinear && d.id && dashboardStore.selectedGrid?.id !== d.id) {
items.push({ value: d.id, label: (d.widget && d.widget.name) || d.id });
}
}
return items;
});
function updateWidgetConfig(options: Option[]) {
const arr: any = getDashboard(dashboardStore.currentDashboard).widgets;
const arr: any = getDashboard(dashboardStore.currentDashboard as DashboardItem).widgets;
const opt = options.map((d: Option) => {
return { widgetId: d.value };
});
@@ -60,7 +61,7 @@ limitations under the License. -->
...dashboardStore.selectedGrid,
associate: opt,
};
dashboardStore.selectWidget({ ...widget });
dashboardStore.selectWidget({ ...widget } as LayoutConfig);
// remove unuse association widget option
for (const id of widgetIds.value) {
@@ -76,7 +77,7 @@ limitations under the License. -->
// add association options in target widgets
for (let i = 0; i < opt.length; i++) {
const item = JSON.parse(JSON.stringify(opt));
item[i] = { widgetId: dashboardStore.selectedGrid.id };
item[i] = { widgetId: dashboardStore.selectedGrid?.id };
const w = arr.find((d: { id: string }) => d.id === opt[i].widgetId);
const config = {
...w,

View File

@@ -62,6 +62,7 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import { RefIdTypes } from "../../data";
import type { LayoutConfig, RelatedTrace } from "@/types/dashboard";
const QueryOrders = [
{ label: "None", value: "BY_START_TIME" },
@@ -74,21 +75,20 @@ limitations under the License. -->
];
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const { graph, relatedTrace } = dashboardStore.selectedGrid;
const traceOpt = relatedTrace || {};
const status = ref<string>(traceOpt.status || Status[0].value);
const queryOrder = ref<string>(traceOpt.queryOrder || QueryOrders[0].value);
const latency = ref<boolean>(traceOpt.latency || false);
const enableRelate = ref<boolean>(traceOpt.enableRelate || false);
const type = ref<string>((graph && graph.type) || "");
const refIdType = ref<string>(traceOpt.refIdType || "");
const traceOpt = dashboardStore.selectedGrid?.relatedTrace as RelatedTrace;
const status = ref<string>(traceOpt?.status || Status[0].value);
const queryOrder = ref<string>(traceOpt?.queryOrder || QueryOrders[0].value);
const latency = ref<boolean>(traceOpt?.latency || false);
const enableRelate = ref<boolean>(traceOpt?.enableRelate || false);
const type = ref<string>(dashboardStore.selectedGrid?.graph?.type || "");
const refIdType = ref<string>(traceOpt?.refIdType || "");
function updateConfig(param: { [key: string]: unknown }) {
const relatedTrace = {
...dashboardStore.selectedGrid.relatedTrace,
...dashboardStore.selectedGrid?.relatedTrace,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, relatedTrace });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, relatedTrace } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -50,11 +50,11 @@ limitations under the License. -->
import { ElMessage } from "element-plus";
import { useDashboardStore } from "@/store/modules/dashboard";
import getDashboard from "@/hooks/useDashboardsSession";
import type { LayoutConfig } from "@/types/dashboard";
import type { LayoutConfig, DashboardItem } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const widget = dashboardStore.selectedGrid.widget || {};
const widget = dashboardStore.selectedGrid?.widget || {};
const title = ref<string>(widget.title || "");
const tips = ref<string>(widget.tips || "");
const name = ref<string>(widget.name || "");
@@ -66,10 +66,10 @@ limitations under the License. -->
}
const { selectedGrid } = dashboardStore;
const widget = {
...dashboardStore.selectedGrid.widget,
...dashboardStore.selectedGrid?.widget,
[key]: decodeURIComponent(param[key]),
};
dashboardStore.selectWidget({ ...selectedGrid, widget });
dashboardStore.selectWidget({ ...selectedGrid, widget } as LayoutConfig);
}
function updateWidgetName(param: { [key: string]: string }) {
const key = Object.keys(param)[0];
@@ -79,7 +79,7 @@ limitations under the License. -->
ElMessage.error(t("nameTip"));
return;
}
const { widgets } = getDashboard(dashboardStore.currentDashboard);
const { widgets } = getDashboard(dashboardStore.currentDashboard as DashboardItem);
const item = widgets.find((d: LayoutConfig) => d.widget && d.widget.name === n);
if (item) {
ElMessage.error(t("duplicateName"));

View File

@@ -33,19 +33,20 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import Legend from "./components/Legend.vue";
import type { AreaConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph || {};
const graph = (dashboardStore.selectedGrid?.graph as AreaConfig) || {};
const opacity = ref(graph.opacity);
function updateConfig(param: { [key: string]: unknown }) {
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -29,18 +29,19 @@ limitations under the License. -->
import { useDashboardStore } from "@/store/modules/dashboard";
import { useI18n } from "vue-i18n";
import Legend from "./components/Legend.vue";
import type { BarConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph;
const graph = (dashboardStore.selectedGrid?.graph as BarConfig) || {};
const showBackground = ref(graph.showBackground || false);
function changeConfig(param: { [key: string]: unknown }) {
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -39,19 +39,20 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import ValueMappings from "./components/ValueMappings.vue";
import type { CardConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph || {};
const graph = (dashboardStore.selectedGrid?.graph as CardConfig) || {};
const fontSize = ref(graph.fontSize);
const showUnit = ref<boolean>(graph.showUnit);
const showUnit = ref<boolean>(graph.showUnit || false);
function updateConfig(param: { [key: string]: unknown }) {
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -31,19 +31,20 @@ limitations under the License. -->
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { EndpointListConfig, LayoutConfig } from "@/types/dashboard";
const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph;
const graph = (dashboardStore.selectedGrid?.graph as EndpointListConfig) || {};
const { t } = useI18n();
const fontSize = ref(graph.fontSize);
function updateConfig(param: { [key: string]: unknown }) {
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -31,18 +31,19 @@ limitations under the License. -->
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { CardConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph || {};
const graph = (dashboardStore.selectedGrid?.graph as CardConfig) || {};
const fontSize = ref(graph.fontSize);
function updateConfig(param: { [key: string]: unknown }) {
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -31,18 +31,19 @@ limitations under the License. -->
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { InstanceListConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph;
const graph = (dashboardStore.selectedGrid?.graph as InstanceListConfig) || {};
const fontSize = ref(graph.fontSize);
function updateConfig(param: { [key: string]: unknown }) {
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -51,20 +51,21 @@ limitations under the License. -->
import { useDashboardStore } from "@/store/modules/dashboard";
import Legend from "./components/Legend.vue";
import { isDef } from "@/utils/is";
import type { LineConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
const graph = computed(() => (dashboardStore.selectedGrid?.graph as LineConfig) || {});
const smooth = ref(graph.value.smooth);
const showSymbol = ref(isDef(graph.value.showSymbol) ? graph.value.showSymbol : true);
const step = ref(graph.value.step);
function updateConfig(param: { [key: string]: unknown }) {
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -40,19 +40,20 @@ limitations under the License. -->
import { ref, computed } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { ServiceListConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
const graph = computed(() => (dashboardStore.selectedGrid?.graph as ServiceListConfig) || {});
const fontSize = ref(graph.value.fontSize);
function updateConfig(param: { [key: string]: unknown }) {
const { selectedGrid } = dashboardStore;
const graph = {
...selectedGrid.graph,
...selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...selectedGrid, graph });
dashboardStore.selectWidget({ ...selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -41,19 +41,20 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import ValueMappings from "./components/ValueMappings.vue";
import type { TableConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph || {};
const graph = (dashboardStore.selectedGrid?.graph as TableConfig) || {};
const showTableValues = ref(graph.showTableValues);
const tableHeaderCol2 = ref(graph.tableHeaderCol2);
function updateConfig(param: { [key: string]: unknown }) {
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -29,10 +29,11 @@ limitations under the License. -->
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { TopListConfig, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph || {};
const graph = (dashboardStore.selectedGrid?.graph as TopListConfig) || {};
const color = ref(graph.color || "purple");
const Colors = [
{ label: "Purple", value: "purple" },
@@ -47,10 +48,10 @@ limitations under the License. -->
function updateConfig(param: { [key: string]: unknown }) {
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
...param,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -94,11 +94,11 @@ limitations under the License. -->
import { computed, reactive } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { LegendOptions } from "@/types/dashboard";
import type { LegendOptions, LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
const graph = computed(() => dashboardStore.selectedGrid?.graph || {});
const legend = reactive<LegendOptions>({
show: true,
total: false,
@@ -113,17 +113,17 @@ limitations under the License. -->
});
function updateLegendConfig(param: { [key: string]: unknown }) {
const g = {
...dashboardStore.selectedGrid.graph,
const graph = {
...dashboardStore.selectedGrid?.graph,
legend: {
...dashboardStore.selectedGrid.graph.legend,
...dashboardStore.selectedGrid?.graph?.legend,
...param,
},
};
dashboardStore.selectWidget({
...dashboardStore.selectedGrid,
graph: g,
});
graph,
} as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -39,14 +39,15 @@ limitations under the License. -->
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { useDashboardStore } from "@/store/modules/dashboard";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { LayoutConfig } from "@/types/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const graph = dashboardStore.selectedGrid.graph;
const graph = dashboardStore.selectedGrid?.graph || {};
const valueMappings = ref<{ [key: string]: string }>(graph?.valueMappings || {});
const keys = ref<string[]>(graph.valueMappings ? Object.keys(valueMappings.value) : [""]);
const keys = ref<string[]>(graph?.valueMappings ? Object.keys(valueMappings.value) : [""]);
function changeKeys(event: any, index: number) {
const params = event.target.textContent || "";
@@ -82,10 +83,10 @@ limitations under the License. -->
function updateConfig() {
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
valueMappings: valueMappings.value,
};
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph } as LayoutConfig);
}
</script>
<style lang="scss" scoped>

View File

@@ -126,7 +126,7 @@ limitations under the License. -->
import Icon from "@/components/Icon.vue";
import { useDashboardQueryProcessor } from "@/hooks/useExpressionsProcessor";
import { useI18n } from "vue-i18n";
import type { DashboardItem, MetricConfigOpt } from "@/types/dashboard";
import type { DashboardItem, MetricConfigOpt, LayoutConfig } from "@/types/dashboard";
import Standard from "./Standard.vue";
/*global defineEmits, Indexable */
@@ -142,11 +142,11 @@ limitations under the License. -->
},
});
const dashboardStore = useDashboardStore();
const metrics = computed(() => dashboardStore.selectedGrid.expressions || []);
const subMetrics = computed(() => dashboardStore.selectedGrid.subExpressions || []);
const subMetricTypes = computed(() => dashboardStore.selectedGrid.subTypesOfMQE || []);
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
const typesOfMQE = computed(() => dashboardStore.selectedGrid.typesOfMQE || []);
const metrics = computed(() => dashboardStore.selectedGrid?.expressions || []);
const subMetrics = computed(() => dashboardStore.selectedGrid?.subExpressions || []);
const subMetricTypes = computed(() => dashboardStore.selectedGrid?.subTypesOfMQE || []);
const graph = computed(() => dashboardStore.selectedGrid?.graph || {});
const typesOfMQE = computed(() => dashboardStore.selectedGrid?.typesOfMQE || []);
const states = reactive<{
metrics: string[];
subMetrics: string[];
@@ -166,13 +166,13 @@ limitations under the License. -->
metricTypeList: [],
isList: false,
isTopList: false,
dashboardName: graph.value.dashboardName,
dashboardName: graph.value.dashboardName || "",
dashboardList: [{ label: "", value: "" }],
tips: [],
subTips: [],
subMetrics: subMetrics.value.length ? subMetrics.value : [""],
subMetricTypes: subMetricTypes.value.length ? subMetricTypes.value : [""],
valueRelatedDashboard: dashboardStore.selectedGrid.valueRelatedDashboard,
valueRelatedDashboard: dashboardStore.selectedGrid?.valueRelatedDashboard || "",
});
const currentMetricConfig = ref<MetricConfigOpt>({
unit: "",
@@ -182,7 +182,7 @@ limitations under the License. -->
});
states.isTopList = graph.value.type === ChartTypes[4].value;
states.isList = ListChartTypes.includes(graph.value.type);
states.isList = ListChartTypes.includes(graph.value.type || "");
const defaultLen = ref<number>(states.isList ? 5 : 20);
setDashboards();
@@ -201,7 +201,7 @@ limitations under the License. -->
});
function setDashboards(type?: string) {
const chart = type || (dashboardStore.selectedGrid.graph && dashboardStore.selectedGrid.graph.type);
const chart = type || dashboardStore.selectedGrid?.graph?.type || "";
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
const arr = list.reduce((prev: (DashboardItem & { label: string; value: string })[], d: DashboardItem) => {
if (d.layer === dashboardStore.layerId) {
@@ -237,7 +237,7 @@ limitations under the License. -->
...dashboardStore.selectedGrid,
expressions: [""],
typesOfMQE: [""],
});
} as LayoutConfig);
states.metrics = [""];
states.metricTypes = [""];
defaultLen.value = 5;
@@ -246,7 +246,7 @@ limitations under the License. -->
dashboardStore.selectWidget({
...dashboardStore.selectedGrid,
graph: chart,
});
} as LayoutConfig);
setDashboards(chart.type);
states.dashboardName = "";
defaultLen.value = 10;
@@ -260,7 +260,7 @@ limitations under the License. -->
}
async function queryMetricsWithExpressions() {
const { expressions, metricConfig, i } = dashboardStore.selectedGrid;
const { expressions, metricConfig, i } = dashboardStore.selectedGrid as LayoutConfig;
if (!(expressions && expressions[0])) {
return emit("update", {});
}
@@ -272,7 +272,7 @@ limitations under the License. -->
dashboardStore.selectWidget({
...dashboardStore.selectedGrid,
typesOfMQE: states.metricTypes,
});
} as LayoutConfig);
emit("update", params.source || {});
if (states.isTopList) {
const values: any = Object.values(params.source)[0];
@@ -292,7 +292,7 @@ limitations under the License. -->
dashboardStore.selectWidget({
...dashboardStore.selectedGrid,
valueRelatedDashboard: states.valueRelatedDashboard,
});
} as LayoutConfig);
}
function changeDashboard(opt: { value: string }[]) {
@@ -302,13 +302,13 @@ limitations under the License. -->
states.dashboardName = opt[0].value;
}
const graph = {
...dashboardStore.selectedGrid.graph,
...dashboardStore.selectedGrid?.graph,
dashboardName: states.dashboardName,
};
dashboardStore.selectWidget({
...dashboardStore.selectedGrid,
graph,
});
} as LayoutConfig);
}
function addMetric() {
states.metrics.push("");
@@ -350,7 +350,7 @@ limitations under the License. -->
states.metrics.splice(index, 1);
states.metricTypes.splice(index, 1);
states.tips.splice(index, 1);
const config = dashboardStore.selectedGrid.metricConfig || [];
const config = dashboardStore.selectedGrid?.metricConfig || [];
const metricConfig = config[index] ? config.splice(index, 1) : config;
let p = {};
if (states.isList) {
@@ -369,7 +369,7 @@ limitations under the License. -->
...dashboardStore.selectedGrid,
...p,
metricConfig,
});
} as LayoutConfig);
queryMetrics();
}
@@ -381,7 +381,7 @@ limitations under the License. -->
labelsIndex: "",
sortOrder: "DES",
};
if (!dashboardStore.selectedGrid.metricConfig || !dashboardStore.selectedGrid.metricConfig[index]) {
if (!dashboardStore.selectedGrid?.metricConfig || !dashboardStore.selectedGrid?.metricConfig[index]) {
currentMetricConfig.value = n;
return;
}
@@ -397,7 +397,7 @@ limitations under the License. -->
dashboardStore.selectWidget({
...dashboardStore.selectedGrid,
expressions: states.metrics,
});
} as LayoutConfig);
if (params) {
await queryMetrics();
}
@@ -410,7 +410,7 @@ limitations under the License. -->
...dashboardStore.selectedGrid,
subExpressions: states.subMetrics,
subTypesOfMQE: states.subMetricTypes,
});
} as LayoutConfig);
if (params) {
await queryMetrics();
}

View File

@@ -86,7 +86,7 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { SortOrder, ExpressionResultType, ListChartTypes } from "@/views/dashboard/data";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { MetricConfigOpt } from "@/types/dashboard";
import type { MetricConfigOpt, LayoutConfig } from "@/types/dashboard";
/*global defineEmits, defineProps */
const props = defineProps({
@@ -103,13 +103,15 @@ limitations under the License. -->
...props.currentMetricConfig,
topN: props.currentMetricConfig.topN || 10,
});
const metricTypes = computed(() => dashboardStore.selectedGrid.typesOfMQE || []);
const metricTypes = computed(() => dashboardStore.selectedGrid?.typesOfMQE || []);
const isList = computed(() => {
const graph = dashboardStore.selectedGrid.graph || {};
return ListChartTypes.includes(graph.type);
const graph = dashboardStore.selectedGrid?.graph || {};
return ListChartTypes.includes(graph.type || "");
});
const isTopn = computed(() =>
[ExpressionResultType.RECORD_LIST, ExpressionResultType.SORTED_LIST].includes(metricTypes.value[props.index]),
[ExpressionResultType.RECORD_LIST, ExpressionResultType.SORTED_LIST].includes(
metricTypes.value[props.index] as ExpressionResultType,
),
);
function updateConfig(index: number, param: { [key: string]: string }) {
@@ -120,13 +122,13 @@ limitations under the License. -->
changeConfigs(index, { [key]: decodeURIComponent(param[key]) });
}
function changeConfigs(index: number, param: { [key: string]: string | number }) {
const metricConfig = dashboardStore.selectedGrid.metricConfig || [];
const metricConfig = dashboardStore.selectedGrid?.metricConfig || [];
metricConfig[index] = { ...metricConfig[index], ...param };
dashboardStore.selectWidget({
...dashboardStore.selectedGrid,
metricConfig,
});
} as LayoutConfig);
emit("update");
}
watch(

View File

@@ -34,11 +34,12 @@ limitations under the License. -->
import { useDashboardStore } from "@/store/modules/dashboard";
import Content from "../related/async-profiling/Content.vue";
import Header from "../related/async-profiling/Header.vue";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps*/
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },

View File

@@ -36,11 +36,12 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import Content from "../related/continuous-profiling/Content.vue";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },

View File

@@ -31,15 +31,17 @@ limitations under the License. -->
</div>
</template>
<script lang="ts" setup>
import type { PropType } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import Header from "../related/demand-log/Header.vue";
import Content from "../related/demand-log/Content.vue";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object,
type: Object as PropType<LayoutConfig>,
default: () => ({}),
},
activeIndex: { type: String, default: "" },

View File

@@ -34,11 +34,12 @@ limitations under the License. -->
import { useDashboardStore } from "@/store/modules/dashboard";
import Header from "../related/ebpf/Header.vue";
import Content from "../related/ebpf/Content.vue";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },

View File

@@ -36,15 +36,17 @@ limitations under the License. -->
</div>
</template>
<script lang="ts" setup>
import type { PropType } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import Header from "../related/event/Header.vue";
import Content from "../related/event/Content.vue";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object,
type: Object as PropType<LayoutConfig>,
default: () => ({}),
},
activeIndex: { type: String, default: "" },

View File

@@ -33,11 +33,11 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import Content from "../related/network-profiling/Content.vue";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },

View File

@@ -34,11 +34,12 @@ limitations under the License. -->
import { useDashboardStore } from "@/store/modules/dashboard";
import Header from "../related/profile/Header.vue";
import Content from "../related/profile/Content.vue";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },

View File

@@ -161,12 +161,12 @@ limitations under the License. -->
const l = dashboardStore.layout.findIndex((d: LayoutConfig) => d.i === props.data.i);
dashboardStore.setActiveTabIndex(activeTabIndex.value);
if (dashboardStore.layout[l].children.length) {
if (dashboardStore.layout[l]?.children?.length) {
const tab = dashboardStore.layout[l].children[activeTabIndex.value];
dashboardStore.setCurrentTabItems(
tab.enable === false ? [] : dashboardStore.layout[l].children[activeTabIndex.value].children,
);
dashboardStore.setActiveTabIndex(activeTabIndex.value, props.data.i);
dashboardStore.setActiveTabIndex(activeTabIndex.value, Number(props.data.i));
}
queryExpressions();
@@ -177,7 +177,7 @@ limitations under the License. -->
dashboardStore.selectWidget(props.data);
dashboardStore.setActiveTabIndex(idx);
const l = dashboardStore.layout.findIndex((d: LayoutConfig) => d.i === props.data.i);
dashboardStore.setCurrentTabItems(dashboardStore.layout[l].children[activeTabIndex.value].children);
dashboardStore.setCurrentTabItems(dashboardStore.layout[l]?.children?.[activeTabIndex.value]?.children || []);
needQuery.value = true;
if (route.params.activeTabIndex) {
let p = location.href.split("/tab/")[0];
@@ -192,10 +192,10 @@ limitations under the License. -->
function deleteTabItem(e: Event, idx: number) {
e.stopPropagation();
dashboardStore.removeTabItem(props.data, idx);
const kids = dashboardStore.layout[l].children[0];
const kids = dashboardStore.layout[l]?.children?.[0];
const arr = (kids && kids.children) || [];
dashboardStore.setCurrentTabItems(arr);
dashboardStore.activeGridItem(0);
dashboardStore.activeGridItem("0");
activeTabIndex.value = 0;
needQuery.value = true;
}
@@ -226,7 +226,7 @@ limitations under the License. -->
}
function layoutUpdatedEvent() {
const l = dashboardStore.layout.findIndex((d: LayoutConfig) => d.i === props.data.i);
dashboardStore.setCurrentTabItems(dashboardStore.layout[l].children[activeTabIndex.value].children);
dashboardStore.setCurrentTabItems(dashboardStore.layout[l]?.children?.[activeTabIndex.value]?.children || []);
}
function getStringWidth(s: string) {
const dom = document.createElement("span");
@@ -282,7 +282,7 @@ limitations under the License. -->
const index = (props.data.children || []).findIndex((tab: any) => tab.enable !== false) || 0;
const items = ((props.data.children || [])[index] || {}).children;
dashboardStore.setCurrentTabItems(items || []);
dashboardStore.activeGridItem(0);
dashboardStore.activeGridItem("0");
activeTabIndex.value = index;
dashboardStore.setActiveTabIndex(activeTabIndex.value);
needQuery.value = true;
@@ -324,7 +324,7 @@ limitations under the License. -->
dashboardStore.activeGridItem(props.data.i);
dashboardStore.selectWidget(props.data);
const l = dashboardStore.layout.findIndex((d: LayoutConfig) => d.i === props.data.i);
dashboardStore.setCurrentTabItems(dashboardStore.layout[l].children[activeTabIndex.value].children);
dashboardStore.setCurrentTabItems(dashboardStore.layout[l]?.children?.[activeTabIndex.value]?.children || []);
needQuery.value = true;
if (route.params.activeTabIndex) {
let p = location.href.split("/tab/")[0];

View File

@@ -33,11 +33,12 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import Content from "../related/task-timeline/Content.vue";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },

View File

@@ -58,18 +58,19 @@ limitations under the License. -->
import { TextColors } from "@/views/dashboard/data";
import { useAppStoreWithOut } from "@/store/modules/app";
import { Themes } from "@/constants/data";
import type { LayoutConfig, TextConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },
});
const { t } = useI18n();
const appStore = useAppStoreWithOut();
const graph = computed(() => props.data.graph || {});
const graph = computed(() => (props.data.graph as TextConfig) || {});
const dashboardStore = useDashboardStore();
const backgroundColor = computed(

View File

@@ -50,11 +50,12 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import { validateAndSanitizeUrl } from "@/utils/validateAndSanitizeUrl";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },

View File

@@ -63,17 +63,18 @@ limitations under the License. -->
import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app";
import { TextColors } from "@/views/dashboard/data";
import type { LayoutConfig, TimeRangeConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },
});
const { t } = useI18n();
const graph = computed(() => props.data.graph || {});
const graph = computed(() => (props.data.graph as TimeRangeConfig) || {});
const dashboardStore = useDashboardStore();
const appStore = useAppStoreWithOut();
const content = computed(() => {

View File

@@ -37,11 +37,12 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import Topology from "../related/topology/Index.vue";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },

View File

@@ -53,11 +53,12 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import { mutationObserver } from "@/utils/mutation";
import type { LayoutConfig } from "@/types/dashboard";
/* global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },

View File

@@ -80,7 +80,7 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useDashboardQueryProcessor } from "@/hooks/useExpressionsProcessor";
import { ListChartTypes } from "../data";
import type { EventParams } from "@/types/dashboard";
import type { EventParams, DashboardItem } from "@/types/dashboard";
import getDashboard from "@/hooks/useDashboardsSession";
const props = {
@@ -141,7 +141,7 @@ limitations under the License. -->
}
}
function clickHandle(params: EventParams | any) {
const { widgets } = getDashboard(dashboardStore.currentDashboard);
const { widgets } = getDashboard(dashboardStore.currentDashboard as DashboardItem);
const associate = (props.data.associate && props.data.associate) || [];
for (const item of associate) {
@@ -170,7 +170,7 @@ limitations under the License. -->
return;
}
const chart = dashboardStore.selectedGrid.graph || {};
if (ListChartTypes.includes(chart.type)) {
if (ListChartTypes.includes(chart.type || "")) {
return;
}
queryMetrics();

View File

@@ -192,7 +192,7 @@ limitations under the License. -->
return;
}
router.push(
`/dashboard/${dashboard.layer}/${dashboard.entity}/${selectorStore.currentService.id}/${scope.row.id}/${dashboard.name}`,
`/dashboard/${dashboard.layer}/${dashboard.entity}/${selectorStore.currentService?.id}/${scope.row.id}/${dashboard.name}`,
);
}
async function searchList() {

View File

@@ -208,7 +208,7 @@ limitations under the License. -->
return;
}
router.push(
`/dashboard/${dashboard.layer}/${dashboard.entity}/${selectorStore.currentService.id}/${
`/dashboard/${dashboard.layer}/${dashboard.entity}/${selectorStore.currentService?.id}/${
scope.row.id
}/${dashboard.name.split(" ").join("-")}`,
);

View File

@@ -85,6 +85,10 @@ limitations under the License. -->
import type { MetricConfigOpt } from "@/types/dashboard";
import ColumnGraph from "./components/ColumnGraph.vue";
interface ServiceWithGroup extends Service {
merge: boolean;
group: string;
}
/*global defineProps */
const props = defineProps({
data: {
@@ -115,12 +119,12 @@ limitations under the License. -->
const chartLoading = ref<boolean>(false);
const currentPage = ref<number>(1);
const pageSize = 10;
const services = ref<Service[]>([]);
const services = ref<ServiceWithGroup[]>([]);
const colMetrics = ref<string[]>([]);
const colSubMetrics = ref<string[]>([]);
const searchText = ref<string>("");
const groups = ref<any>({});
const sortServices = ref<(Service & { merge: boolean })[]>([]);
const sortServices = ref<ServiceWithGroup[]>([]);
const metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
const typesOfMQE = ref<string[]>(props.config.typesOfMQE || []);
@@ -144,12 +148,12 @@ limitations under the License. -->
return 1;
}
return 0;
});
const s = sortServices.value.filter((d: Service, index: number) => index < pageSize);
}) as ServiceWithGroup[];
const s = sortServices.value.filter((d: ServiceWithGroup, index: number) => index < pageSize);
setServices(s);
}
function setServices(arr: (Service & { merge: boolean })[]) {
function setServices(arr: ServiceWithGroup[]) {
groups.value = {};
const map: { [key: string]: any[] } = arr.reduce((result: { [key: string]: any[] }, item: any) => {
item.group = item.group || "";
@@ -191,11 +195,11 @@ limitations under the License. -->
router.push(path);
}
async function queryServiceMetrics(arr: Service[]) {
async function queryServiceMetrics(arr: ServiceWithGroup[]) {
if (!arr.length) {
return;
}
const currentServices = arr.map((d: Service) => {
const currentServices = arr.map((d: ServiceWithGroup) => {
return {
id: d.id,
value: d.value,
@@ -203,13 +207,13 @@ limitations under the License. -->
layers: d.layers,
group: d.group,
normal: d.normal,
merge: d.merge,
merge: d.merge || false,
shortName: d.shortName,
};
});
queryServiceExpressions(currentServices);
}
async function queryServiceExpressions(currentServices: Service[]) {
async function queryServiceExpressions(currentServices: ServiceWithGroup[]) {
const expressions = props.config.expressions || [];
const subExpressions = props.config.subExpressions || [];
@@ -254,7 +258,7 @@ limitations under the License. -->
if (searchText.value) {
services = sortServices.value.filter((d: { label: string }) => d.label.includes(searchText.value));
}
const arr = services.filter((d: Service, index: number) => {
const arr = services.filter((d: ServiceWithGroup, index: number) => {
if (index >= (currentPage.value - 1) * pageSize && index < pageSize * currentPage.value) {
return d;
}

View File

@@ -70,13 +70,12 @@ limitations under the License. -->
import { TextColors, MetricCatalog } from "@/views/dashboard/data";
import Trace from "@/views/dashboard/related/trace/Index.vue";
import { WidgetType, QueryOrders, Status, RefIdTypes, ExpressionResultType } from "@/views/dashboard/data";
import type { Filters, RelatedTrace, TopListData, TopListItem } from "@/types/dashboard";
/*global defineProps, Recordable*/
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<{
[key: string]: { name: string; value: number; refId: string; owner: object }[];
}>,
type: Object as PropType<TopListData>,
default: () => ({}),
},
config: {
@@ -84,7 +83,7 @@ limitations under the License. -->
color: string;
expressions: string[];
typesOfMQE: string[];
relatedTrace: any;
relatedTrace: RelatedTrace;
valueRelatedDashboard: string;
}>,
default: () => ({ color: "purple" }),
@@ -94,28 +93,29 @@ limitations under the License. -->
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const showTrace = ref<boolean>(false);
const traceOptions = ref<{ type: string; filters?: unknown }>({
const traceOptions = ref<{ type: string; filters?: Filters } | any>({
...props.data,
type: WidgetType.Trace,
});
const refIdType = computed(
() => (props.config.relatedTrace && props.config.relatedTrace.refIdType) || RefIdTypes[0].value,
);
const key = computed(() => Object.keys(props.data)[0] || "");
const key = computed<string>(() => Object.keys(props.data)[0] || "");
const available = computed(
() => Array.isArray(props.data[key.value]) && props.data[key.value][0] && props.data[key.value][0].value,
);
const maxValue = computed(() => {
if (!(props.data[key.value] && props.data[key.value].length)) {
if (!props.data[key.value].length) {
return 0;
}
const temp: number[] = props.data[key.value].map((i: any) => i.value);
const temp: number[] = props.data?.[key.value].map((i: any) => i.value);
return Math.max.apply(null, temp);
});
function handleClick(i: string) {
copy(i);
}
function viewTrace(item: { name: string; refId: string; value: unknown; owner: object }) {
const filters = {
function viewTrace(item: TopListItem) {
const filters: Filters = {
...item,
queryOrder: QueryOrders[1].value,
status: Status[2].value,
@@ -130,7 +130,7 @@ limitations under the License. -->
};
showTrace.value = true;
}
function viewDashboard(item: Recordable) {
function viewDashboard(item: TopListItem) {
const { owner } = item;
let path;
if (owner.scope === MetricCatalog.SERVICE) {

View File

@@ -85,12 +85,13 @@ limitations under the License. -->
}
}
if (item.type === WidgetType.Tab) {
const index = isNaN(item.activedTabIndex) ? 0 : item.activedTabIndex;
widgets.push(
...item.children[index].children.filter(
const index = isNaN(item.activedTabIndex as number) ? 0 : (item.activedTabIndex as number);
if (item.children && item.children[index]) {
const list = item.children[index]?.children.filter(
(d: LayoutConfig) => d.type === WidgetType.Widget && !ListChartTypes.includes(d.graph?.type || ""),
),
);
);
widgets.push(...list);
}
}
}
const configList = widgets.map((d: LayoutConfig) => ({

View File

@@ -168,6 +168,7 @@ limitations under the License. -->
import type { Option } from "@/types/app";
import InstanceMap from "@/views/dashboard/related/topology/pod/InstanceMap.vue";
import HierarchyMap from "@/views/dashboard/related/topology/service/HierarchyMap.vue";
import { Process, Instance, Endpoint } from "@/types/selector";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
@@ -175,7 +176,7 @@ limitations under the License. -->
const topologyStore = useTopologyStore();
const appStore = useAppStoreWithOut();
const route = useRoute();
const params = route?.params || {};
const params: any = route?.params || {};
const toolIcons = ref<{ name: string; content: string; id: WidgetType }[]>(AllTools);
const loading = ref<boolean>(false);
const showHierarchy = ref<boolean>(false);
@@ -252,7 +253,8 @@ limitations under the License. -->
ElMessage.error(json.errors);
return;
}
let currentService, currentDestService;
let currentService = null,
currentDestService = null;
if (states.currentService) {
for (const d of selectorStore.services) {
if (d.value === states.currentService) {
@@ -274,22 +276,22 @@ limitations under the License. -->
}
selectorStore.setCurrentService(currentService);
selectorStore.setCurrentDestService(currentDestService);
states.currentService = selectorStore.currentService && selectorStore.currentService.value;
states.currentDestService = selectorStore.currentDestService && selectorStore.currentDestService.value;
states.currentService = selectorStore.currentService?.value || "";
states.currentDestService = selectorStore.currentDestService?.value || "";
}
async function setSourceSelector() {
await selectorStore.getService(String(params.serviceId));
states.currentService = selectorStore.currentService.value;
states.currentService = selectorStore.currentService?.value || "";
const e = String(params.entity).split("Relation")[0];
await fetchPods(e, selectorStore.currentService.id, true);
await fetchPods(e, selectorStore.currentService?.id, true);
}
async function setDestSelector() {
await selectorStore.getService(String(params.destServiceId), true);
states.currentDestService = selectorStore.currentDestService.value;
await fetchPods(String(params.entity), selectorStore.currentDestService.id, true);
states.currentDestService = selectorStore.currentDestService?.value || "";
await fetchPods(String(params.entity), selectorStore.currentDestService?.id || "", true);
}
async function getServices() {
@@ -341,14 +343,14 @@ limitations under the License. -->
EntityType[8].value,
].includes(dashboardStore.entity)
) {
await fetchPods(e, selectorStore.currentService.id, true);
await fetchPods(e, selectorStore.currentService?.id || "", true);
}
if (!selectorStore.currentDestService) {
return;
}
states.currentDestService = selectorStore.currentDestService.value;
if ([EntityType[5].value, EntityType[6].value, EntityType[7].value].includes(dashboardStore.entity)) {
await fetchPods(dashboardStore.entity, selectorStore.currentDestService.id, true);
await fetchPods(dashboardStore.entity, selectorStore.currentDestService?.id || "", true);
}
}
@@ -360,7 +362,7 @@ limitations under the License. -->
states.currentPod = "";
states.currentProcess = "";
const e = dashboardStore.entity.split("Relation")[0];
fetchPods(e, selectorStore.currentService.id, true);
fetchPods(e, selectorStore.currentService?.id, true);
} else {
selectorStore.setCurrentService(null);
}
@@ -373,7 +375,7 @@ limitations under the License. -->
selectorStore.setCurrentDestPod(null);
states.currentDestPod = "";
states.currentDestProcess = "";
fetchPods(dashboardStore.entity, selectorStore.currentDestService.id, true);
fetchPods(dashboardStore.entity, selectorStore.currentDestService?.id || "", true);
} else {
selectorStore.setCurrentDestService(null);
}
@@ -395,12 +397,12 @@ limitations under the License. -->
}
}
function changeDestProcess(pod: Option[]) {
selectorStore.setCurrentDestProcess(pod[0] || null);
function changeDestProcess(pod: Process[]) {
selectorStore.setCurrentDestProcess(pod[0]);
states.currentDestProcess = pod[0].label || "";
}
function changeProcess(pod: Option[]) {
function changeProcess(pod: Process[]) {
selectorStore.setCurrentProcess(pod[0] || null);
states.currentProcess = pod[0].label || "";
}
@@ -447,7 +449,10 @@ limitations under the License. -->
dashboardStore.addControl(id);
}
async function fetchPods(type: string, serviceId: string, setPod: boolean, param?: { keyword?: string }) {
async function fetchPods(type: string, serviceId: string | undefined, setPod: boolean, param?: { keyword?: string }) {
if (!serviceId) {
return;
}
let resp;
switch (type) {
case EntityType[2].value:
@@ -517,11 +522,11 @@ limitations under the License. -->
async function fetchProcess(setPod: boolean) {
const resp = await selectorStore.getProcesses({
instanceId: selectorStore.currentPod.id,
instanceId: selectorStore.currentPod?.id || "",
});
if (setPod) {
const process = selectorStore.currentProcess?.id || params.processId || selectorStore.processes[0].id;
const currentProcess = selectorStore.processes.find((d: { id: string }) => d.id === process);
const currentProcess = selectorStore.processes.find((d: Process) => d.id === process);
if (currentProcess) {
selectorStore.setCurrentProcess(currentProcess);
states.currentProcess = currentProcess.label;
@@ -534,7 +539,7 @@ limitations under the License. -->
}
async function fetchDestProcess(setPod: boolean) {
const resp = await selectorStore.getProcesses({
instanceId: selectorStore.currentDestPod.id,
instanceId: selectorStore.currentDestPod?.id,
isRelation: true,
});
if (setPod) {
@@ -572,7 +577,7 @@ limitations under the License. -->
return;
}
const destPod = selectorStore.currentDestPod?.id || params.destPodId || selectorStore.destPods[0].id;
const currentDestPod = selectorStore.destPods.find((d: { id: string }) => d.id === destPod);
const currentDestPod = selectorStore.destPods.find((d: Instance | Endpoint) => d.id === destPod);
if (!currentDestPod) {
states.currentDestPod = "";
selectorStore.setCurrentDestPod(null);
@@ -604,7 +609,7 @@ limitations under the License. -->
return;
}
const pod = selectorStore.currentPod?.id || params.podId || selectorStore.pods[0].id;
const currentPod = selectorStore.pods.find((d: { id: string }) => d.id === pod);
const currentPod = selectorStore.pods.find((d: Endpoint | Instance) => d.id === pod);
if (!currentPod) {
selectorStore.setCurrentPod(null);
states.currentPod = "";
@@ -651,13 +656,13 @@ limitations under the License. -->
const param = {
keyword: query,
};
fetchPods(EntityType[2].value, selectorStore.currentService.id, false, param);
fetchPods(EntityType[2].value, selectorStore.currentService?.id, false, param);
}
function searchDestPods(query: string) {
const param = {
keyword: query,
};
fetchPods(EntityType[6].value, selectorStore.currentDestService.id, false, param);
fetchPods(EntityType[6].value, selectorStore.currentDestService?.id, false, param);
}
function viewTopology() {
showHierarchy.value = true;

View File

@@ -35,12 +35,12 @@ limitations under the License. -->
import EBPFStack from "@/views/dashboard/related/ebpf/components/EBPFStack.vue";
import { ComponentType } from "./components/data";
const asyncProfilingStore = useAsyncProfilingStore();
const asyncProfilingStore: ReturnType<typeof useAsyncProfilingStore> = useAsyncProfilingStore();
const selectorStore = useSelectorStore();
onMounted(async () => {
const resp = await asyncProfilingStore.getServiceInstances({ serviceId: selectorStore.currentService.id });
if (resp && resp.errors) {
const resp = await asyncProfilingStore.getServiceInstances({ serviceId: selectorStore.currentService?.id || "" });
if (resp?.errors) {
ElMessage.error(resp.errors);
}
});

View File

@@ -50,7 +50,7 @@ limitations under the License. -->
const serviceInstanceIds = ref<string[]>([]);
const selectedEventType = ref<string>("");
const eventTypes = computed(() =>
(asyncProfilingStore.selectedTask.events ?? [])
(asyncProfilingStore.selectedTask?.events || [])
.map((d: string) => {
if (d === ProfilingEvents[1]) {
return [
@@ -65,7 +65,7 @@ limitations under the License. -->
);
const instances = computed(() =>
asyncProfilingStore.instances.filter((d: Instance) =>
(asyncProfilingStore.selectedTask.successInstanceIds ?? []).includes(d.id),
(asyncProfilingStore.selectedTask?.successInstanceIds || []).includes(d.id || ""),
),
);
@@ -80,12 +80,12 @@ limitations under the License. -->
}
async function analyzeProfiling() {
const instanceIds = asyncProfilingStore.instances
const instanceIds = (asyncProfilingStore.instances || [])
.filter((d: Instance) => (serviceInstanceIds.value ?? []).includes(d.value))
.map((d: Instance) => d.id);
.map((d: Instance) => d.id || "") as string[];
const res = await asyncProfilingStore.getAsyncProfilingAnalyze({
instanceIds,
taskId: asyncProfilingStore.selectedTask.id,
taskId: asyncProfilingStore.selectedTask?.id || "",
eventType: (EventsMap as any)[selectedEventType.value],
});
if (res.data && res.data.errors) {
@@ -95,7 +95,7 @@ limitations under the License. -->
}
watch(
() => asyncProfilingStore.selectedTask.successInstanceIds,
() => asyncProfilingStore.selectedTask?.successInstanceIds,
() => {
serviceInstanceIds.value = [];
selectedEventType.value = "";

View File

@@ -114,6 +114,7 @@ limitations under the License. -->
import { useSelectorStore } from "@/store/modules/selectors";
import { ElMessage } from "element-plus";
import { DurationOptions, ProfilingEvents } from "./data";
import type { AsyncProfileTaskCreationRequest } from "@/types/async-profiling";
/* global defineEmits */
const emits = defineEmits(["close"]);
@@ -165,12 +166,12 @@ limitations under the License. -->
}
const params = {
serviceId: selectorStore.currentService.id,
serviceId: selectorStore.currentService?.id,
serviceInstanceIds: serviceInstanceIds.value,
duration: finalDuration,
events: asyncEvents.value,
execArgs: execArgs.value,
};
} as AsyncProfileTaskCreationRequest;
loading.value = true;
const res = await asyncProfilingStore.createTask(params);
loading.value = false;

View File

@@ -26,7 +26,7 @@ limitations under the License. -->
@click="changeTask(i)"
:key="index"
:class="{
selected: asyncProfilingStore.selectedTask.id === i.id,
selected: asyncProfilingStore.selectedTask?.id === i.id,
}"
>
<td class="profile-td">
@@ -50,7 +50,7 @@ limitations under the License. -->
</div>
</div>
<el-dialog v-model="showDetail" :destroy-on-close="true" fullscreen @closed="showDetail = false">
<div class="profile-detail flex-v" v-if="asyncProfilingStore.selectedTask.id">
<div class="profile-detail flex-v" v-if="asyncProfilingStore.selectedTask?.id">
<div>
<h5 class="mb-10">{{ t("task") }}.</h5>
<div class="mb-10 clear item">
@@ -67,20 +67,15 @@ limitations under the License. -->
</div>
<div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("duration") }}:</span>
<span class="g-sm-8 wba">{{ asyncProfilingStore.selectedTask.duration / 60 }}min</span>
<span class="g-sm-8 wba">{{ asyncProfilingStore.selectedTask?.duration / 60 }}min</span>
</div>
<div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("events") }}:</span>
<span class="g-sm-8 wba"> {{ asyncProfilingStore.selectedTask.events.join(", ") }} </span>
<span class="g-sm-8 wba"> {{ (asyncProfilingStore.selectedTask?.events || []).join(", ") }} </span>
</div>
</div>
<div>
<h5
class="mb-5 mt-10"
v-show="asyncProfilingStore.selectedTask.logs && asyncProfilingStore.selectedTask.logs.length"
>
{{ t("logs") }}.
</h5>
<h5 class="mb-5 mt-10" v-show="asyncProfilingStore.selectedTask?.logs?.length"> {{ t("logs") }}. </h5>
<div v-for="(i, index) in Object.keys(instanceLogs)" :key="index">
<div class="sm">
<span class="mr-10 grey">{{ t("instance") }}:</span>
@@ -128,7 +123,8 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import { useSelectorStore } from "@/store/modules/selectors";
import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
import type { TaskLog, TaskListItem } from "@/types/profile";
import type { TaskLog } from "@/types/profile";
import type { AsyncProfilingTask } from "@/types/async-profiling";
import { ElMessage } from "element-plus";
import { dateFormat } from "@/utils/dateFormat";
import type { Instance, Service } from "@/types/selector";
@@ -156,13 +152,13 @@ limitations under the License. -->
}
}
async function changeTask(item: TaskListItem) {
if (item.id !== asyncProfilingStore.selectedTask.id) {
async function changeTask(item: AsyncProfilingTask) {
if (item.id !== asyncProfilingStore.selectedTask?.id) {
asyncProfilingStore.setAnalyzeTrees([]);
asyncProfilingStore.setSelectedTask(item);
}
service.value = (selectorStore.services.filter((s: Service) => s.id === item.serviceId)[0] ?? {}).label;
const res = await asyncProfilingStore.getTaskLogs({ taskId: item.id });
const res = await asyncProfilingStore.getTaskLogs({ taskID: item.id });
if (res.errors) {
ElMessage.error(res.errors);

View File

@@ -19,38 +19,38 @@ limitations under the License. -->
<div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("taskId") }}:</span>
<span class="g-sm-8 wba">
{{ details.taskId }}
{{ details?.taskId || "" }}
</span>
</div>
<div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("service") }}:</span>
<span class="g-sm-8 wba">
{{ details.serviceName }}
{{ details?.serviceName || "" }}
</span>
</div>
<div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("labels") }}:</span>
<span class="g-sm-8 wba">
{{ details.processLabels.join(";") }}
{{ details?.processLabels?.join(";") }}
</span>
</div>
<div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("monitorTime") }}:</span>
<span class="g-sm-8 wba">
{{ dateFormat(details.taskStartTime) }}
{{ dateFormat(details?.taskStartTime || NaN) }}
</span>
</div>
<div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("monitorDuration") }}:</span>
<span class="g-sm-8 wba"> {{ details.fixedTriggerDuration / 60 }} min </span>
<span class="g-sm-8 wba"> {{ (details?.fixedTriggerDuration || 0) / 60 }} min </span>
</div>
<div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("triggerType") }}:</span>
<span class="g-sm-8 wba">{{ details.triggerType }}</span>
<span class="g-sm-8 wba">{{ details?.triggerType }}</span>
</div>
<div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("targetType") }}:</span>
<span class="g-sm-8 wba">{{ details.targetType }}</span>
<span class="g-sm-8 wba">{{ details?.targetType }}</span>
</div>
</div>
</div>
@@ -61,10 +61,10 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import type { EBPFTaskList } from "@/types/ebpf";
/*global defineProps */
/*global defineProps, Nullable */
defineProps({
details: {
type: Object as PropType<EBPFTaskList>,
type: Object as PropType<Nullable<EBPFTaskList>>,
default: () => ({}),
},
});

View File

@@ -84,6 +84,7 @@ limitations under the License. -->
import router from "@/router";
import { HeaderLabels, HeaderChildLabels } from "../data";
import { EntityType } from "../../../data";
import type { Instance } from "@/types/selector";
/*global defineProps */
const props = defineProps({
@@ -97,14 +98,14 @@ limitations under the License. -->
const selectorStore = useSelectorStore();
const continousProfilingStore = useContinousProfilingStore();
const pageSize = 10;
const currentInstances = ref<MonitorInstance[]>([]);
const currentInstances = ref<Instance[]>([]);
function viewProcessDashboard(process: MonitorProcess, instance: MonitorInstance) {
if (!props.config.processDashboardName) {
return;
}
router.push(
`/dashboard/${dashboardStore.layerId}/${EntityType[8].value}/${selectorStore.currentService.id}/${instance.id}/${process.id}/${props.config.processDashboardName}`,
`/dashboard/${dashboardStore.layerId}/${EntityType[8].value}/${selectorStore.currentService?.id}/${instance.id}/${process.id}/${props.config.processDashboardName}`,
);
}
@@ -113,12 +114,12 @@ limitations under the License. -->
return;
}
router.push(
`/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${selectorStore.currentService.id}/${instance.id}/${props.config.instanceDashboardName}`,
`/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${selectorStore.currentService?.id}/${instance.id}/${props.config.instanceDashboardName}`,
);
}
async function changePage(pageIndex: number) {
currentInstances.value = continousProfilingStore.instances.filter((d: unknown, index: number) => {
currentInstances.value = continousProfilingStore.instances.filter((d: Instance, index: number) => {
if (index >= (pageIndex - 1) * pageSize && index < pageIndex * pageSize) {
return d;
}
@@ -129,7 +130,7 @@ limitations under the License. -->
() => continousProfilingStore.instances,
() => {
currentInstances.value = continousProfilingStore.instances.filter(
(_: unknown, index: number) => index < pageSize,
(_: Instance, index: number) => index < pageSize,
);
},
);

View File

@@ -35,7 +35,7 @@ limitations under the License. -->
<td
class="profile-td"
:class="{
selected: continousProfilingStore.selectedStrategy.id === i.id,
selected: continousProfilingStore.selectedStrategy?.id === i.id,
}"
v-if="i.type"
>
@@ -81,7 +81,7 @@ limitations under the License. -->
const { t } = useI18n();
const selectorStore = useSelectorStore();
const continousProfilingStore = useContinousProfilingStore();
const continousProfilingStore: ReturnType<typeof useContinousProfilingStore> = useContinousProfilingStore();
const updateStrategies = ref<boolean>(false);
const inProcess = ref<boolean>(false);

View File

@@ -77,7 +77,7 @@ limitations under the License. -->
}
toRaw(monacoInstance.value).dispose();
monacoInstance.value = null;
demandLogStore.setLogs("");
demandLogStore.setLogs([]);
});
watch(
() => appStore.theme,

View File

@@ -152,7 +152,7 @@ limitations under the License. -->
if (!(state.instance.id || (selectorStore.currentPod && selectorStore.currentPod.id))) {
return;
}
const resp = await demandLogStore.getContainers(state.instance.id || selectorStore.currentPod.id);
const resp = await demandLogStore.getContainers(state.instance.id || selectorStore.currentPod?.id || "");
if (resp.errors) {
disabled.value = true;
ElMessage.error(resp.errors);
@@ -193,7 +193,7 @@ limitations under the License. -->
function searchLogs() {
let instance = "";
if (dashboardStore.entity === EntityType[3].value) {
instance = selectorStore.currentPod.id;
instance = selectorStore.currentPod?.id || "";
}
const serviceInstanceId = instance || (state.instance && state.instance.id) || "";
demandLogStore.setLogCondition({
@@ -247,6 +247,7 @@ limitations under the License. -->
const keywordsOfContentList = keywordsOfContent.value || [];
keywordsOfContentList.splice(index, 1);
demandLogStore.setLogCondition({
...demandLogStore.conditions,
keywordsOfContent: keywordsOfContentList,
});
contentStr.value = "";
@@ -262,12 +263,14 @@ limitations under the License. -->
if (type === "keywordsOfContent") {
keywordsOfContent.value.push(contentStr.value);
demandLogStore.setLogCondition({
...demandLogStore.conditions,
[type]: keywordsOfContent.value,
});
contentStr.value = "";
} else if (type === "excludingKeywordsOfContent") {
excludingKeywordsOfContent.value.push(excludingContentStr.value);
demandLogStore.setLogCondition({
...demandLogStore.conditions,
[type]: excludingKeywordsOfContent.value,
});
excludingContentStr.value = "";
@@ -277,6 +280,7 @@ limitations under the License. -->
function removeExcludeContent(index: number) {
excludingKeywordsOfContent.value.splice(index, 1);
demandLogStore.setLogCondition({
...demandLogStore.conditions,
excludingKeywordsOfContent: excludingKeywordsOfContent.value,
});
excludingContentStr.value = "";
@@ -297,7 +301,7 @@ limitations under the License. -->
() => {
if (dashboardStore.entity === EntityType[0].value) {
fetchSelectors();
demandLogStore.setLogs("");
demandLogStore.setLogs([]);
}
},
);
@@ -306,7 +310,7 @@ limitations under the License. -->
() => {
if (dashboardStore.entity === EntityType[3].value) {
fetchSelectors();
demandLogStore.setLogs("");
demandLogStore.setLogs([]);
}
},
);

View File

@@ -68,7 +68,7 @@ limitations under the License. -->
return;
}
newTask.value = true;
ebpfStore.getCreateTaskData(selectorStore.currentService.id);
ebpfStore.getCreateTaskData(selectorStore.currentService.id || "");
}
watch(

View File

@@ -32,7 +32,7 @@ limitations under the License. -->
</div>
<div class="flex-h">
<Selector
v-if="ebpfStore.selectedTask.targetType === 'OFF_CPU'"
v-if="ebpfStore.selectedTask?.targetType === 'OFF_CPU'"
:value="aggregateType"
:options="AggregateTypes"
size="small"
@@ -102,7 +102,7 @@ limitations under the License. -->
import { dateFormat } from "@/utils/dateFormat";
const { t } = useI18n();
const ebpfStore = useEbpfStore();
const ebpfStore: ReturnType<typeof useEbpfStore> = useEbpfStore();
const pageSize = 5;
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
const selectedProcesses = ref<string[]>([]);
@@ -163,7 +163,7 @@ limitations under the License. -->
}
}
const res = await ebpfStore.getEBPFAnalyze({
scheduleIdList,
scheduleIdList: scheduleIdList as string[],
timeRanges,
aggregateType: aggregateType.value,
});

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<div id="graph-stack" ref="graph">
<span class="tip" v-show="ebpfStore.ebpfTips">{{ ebpfStore.ebpfTips }}</span>
<span class="tip" v-show="(ebpfStore as any).ebpfTips">{{ (ebpfStore as any).ebpfTips }}</span>
</div>
</template>
<script lang="ts" setup>
@@ -25,6 +25,7 @@ limitations under the License. -->
import { useEbpfStore } from "@/store/modules/ebpf";
import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
import type { StackElement } from "@/types/ebpf";
import type { StackElement as AsyncProfilingStackElement } from "@/types/async-profiling";
import { AggregateTypes } from "./data";
import { JFREventType, ComponentType } from "@/views/dashboard/related/async-profiling/components/data";
import "d3-flame-graph/dist/d3-flamegraph.css";
@@ -37,7 +38,8 @@ limitations under the License. -->
default: "",
},
});
const ebpfStore = props.type === ComponentType ? useAsyncProfilingStore() : useEbpfStore();
const ebpfStore: ReturnType<typeof useAsyncProfilingStore | typeof useEbpfStore> =
props.type === ComponentType ? useAsyncProfilingStore() : useEbpfStore();
const stackTree = ref<Nullable<StackElement>>(null);
const selectStack = ref<Nullable<StackElement>>(null);
const graph = ref<Nullable<HTMLDivElement>>(null);
@@ -67,12 +69,15 @@ limitations under the License. -->
};
countRange();
if (props.type === ComponentType) {
const elements = processTree(ebpfStore.analyzeTrees[0].elements);
const elements = processTree(
((ebpfStore as ReturnType<typeof useAsyncProfilingStore>).analyzeTrees[0].elements ||
[]) as AsyncProfilingStackElement[],
);
stackTree.value = elements;
root = { ...root, ...elements };
} else {
for (const tree of ebpfStore.analyzeTrees) {
const ele = processTree(tree.elements);
for (const tree of (ebpfStore as ReturnType<typeof useEbpfStore>).analyzeTrees) {
const ele = processTree(tree.elements as StackElement[]);
root.children && root.children.push(ele);
}
const param = (root.children || []).reduce(
@@ -134,7 +139,7 @@ limitations under the License. -->
if (!ebpfStore.analyzeTrees.length) {
return;
}
const { type } = ebpfStore.analyzeTrees[0];
const { type } = ebpfStore.analyzeTrees[0] as any;
if ([JFREventType.LOCK].includes(type)) {
return `<div class="mb-5">Duration: ${item.dumpCount} ns</div>`;
}
@@ -144,15 +149,15 @@ limitations under the License. -->
return `<div class="mb-5">Memory: ${item.dumpCount} byte</div>`;
}
ebpfStore.aggregateType === AggregateTypes[0].value
(ebpfStore as ReturnType<typeof useEbpfStore>).aggregateType === AggregateTypes[0].value
? `<div class="mb-5">Dump Count: ${item.dumpCount}</div>`
: `<div class="mb-5">Duration: ${item.dumpCount} ns</div>`;
}
function countRange() {
const list = [];
for (const tree of ebpfStore.analyzeTrees) {
for (const ele of tree.elements) {
for (const tree of (ebpfStore as ReturnType<typeof useEbpfStore>).analyzeTrees) {
for (const ele of tree.elements || []) {
list.push(ele.dumpCount);
}
}
@@ -160,7 +165,7 @@ limitations under the License. -->
min.value = Math.min(...list);
}
function processTree(arr: StackElement[]) {
function processTree(arr: StackElement[] | AsyncProfilingStackElement[]) {
const copyArr = JSON.parse(JSON.stringify(arr));
const obj: any = {};
let res = null;

View File

@@ -77,6 +77,7 @@ limitations under the License. -->
import { useAppStoreWithOut } from "@/store/modules/app";
import { ElMessage } from "element-plus";
import { InitTaskField, TargetTypes } from "./data";
import type { EBPFTaskCreationRequest } from "@/types/ebpf";
/* global defineEmits */
const emits = defineEmits(["close"]);
@@ -109,13 +110,16 @@ limitations under the License. -->
}
disabled.value = true;
const date = monitorTime.value === "0" ? new Date() : time.value;
if (!selectorStore.currentService?.id) {
return;
}
const params = {
serviceId: selectorStore.currentService.id,
serviceId: selectorStore.currentService?.id,
processLabels: labels.value,
startTime: date.getTime(),
duration: monitorDuration.value * 60,
targetType: type.value,
};
} as EBPFTaskCreationRequest;
const res = await eBPFStore.createTask(params);
if (res.errors) {
ElMessage.error(res.errors);

View File

@@ -25,7 +25,7 @@ limitations under the License. -->
<td
class="profile-td"
:class="{
selected: ebpfStore.selectedTask.taskId === i.taskId,
selected: ebpfStore.selectedTask?.taskId === i.taskId,
}"
>
<div class="ell">
@@ -37,9 +37,9 @@ limitations under the License. -->
</a>
</div>
<div class="grey ell sm">
<span class="mr-10 sm">{{ dateFormat(i.taskStartTime) }}</span>
<span class="mr-10 sm">{{ dateFormat(i.taskStartTime || NaN) }}</span>
<span class="mr-10 sm">
{{ dateFormat(i.taskStartTime + i.fixedTriggerDuration * 1000) }}
{{ dateFormat(i.taskStartTime + (i.fixedTriggerDuration || 0) * 1000) }}
</span>
</div>
</td>
@@ -61,14 +61,15 @@ limitations under the License. -->
import TaskDetails from "../../components/TaskDetails.vue";
import { dateFormat } from "@/utils/dateFormat";
/* global Nullable */
const { t } = useI18n();
const ebpfStore = useEbpfStore();
const viewDetail = ref<boolean>(false);
async function changeTask(item: EBPFTaskList) {
async function changeTask(item: Nullable<EBPFTaskList>) {
ebpfStore.setSelectedTask(item);
const res = await ebpfStore.getEBPFSchedules({
taskId: item.taskId,
taskId: item?.taskId || "",
});
if (res.errors) {
ElMessage.error(res.errors);

View File

@@ -16,11 +16,11 @@ limitations under the License. -->
<div ref="timeline" class="events"></div>
</template>
<script lang="ts" setup>
import { ref, watch, onMounted } from "vue";
import { ref, watch, onMounted, PropType } from "vue";
import dayjs from "dayjs";
import { useThrottleFn } from "@vueuse/core";
import type { Event } from "@/types/events";
import type { LayoutConfig } from "@/types/dashboard";
import type { LayoutConfig, DashboardItem } from "@/types/dashboard";
import { useEventStore } from "@/store/modules/event";
import { DataSet, Timeline } from "vis-timeline/standalone";
import "vis-timeline/styles/vis-timeline-graph2d.css";
@@ -32,10 +32,10 @@ limitations under the License. -->
import { WidgetType } from "@/views/dashboard/data";
const eventStore = useEventStore();
/*global defineProps, Nullable */
/*global Nullable */
const props = defineProps({
data: {
type: Object,
type: Object as PropType<LayoutConfig>,
default: () => ({}),
},
});
@@ -106,7 +106,7 @@ limitations under the License. -->
return;
}
dashboardStore.selectWidget(props.data);
const dashboard = getDashboard(dashboardStore.currentDashboard).widgets;
const dashboard = getDashboard(dashboardStore.currentDashboard as DashboardItem).widgets;
associateMetrics(properties.items, events, dashboard);
associateTraceLog(properties.items, events, dashboard);
});
@@ -130,11 +130,10 @@ limitations under the License. -->
const i = events[index - 1 || 0];
for (const widget of widgets) {
if (isNaN(index)) {
const item = {
const item: LayoutConfig = {
...widget,
filters: {
sourceId: props.data.id || "",
duration: null,
},
};
dashboardStore.setWidget(item);
@@ -154,8 +153,8 @@ limitations under the License. -->
filters: {
sourceId: props.data.id || "",
duration: {
start: dateFormatStep(getLocalTime(appStore.utc, start), step, true),
end: dateFormatStep(getLocalTime(appStore.utc, end), step, true),
startTime: dateFormatStep(getLocalTime(appStore.utc, start), step, true),
endTime: dateFormatStep(getLocalTime(appStore.utc, end), step, true),
step,
},
},
@@ -187,14 +186,14 @@ limitations under the License. -->
for (const widget of widgets) {
if (isNaN(index)) {
const item = {
const item: LayoutConfig = {
...widget,
filters: {
sourceId: dashboardStore.selectedGrid.id || "",
sourceId: dashboardStore.selectedGrid?.id || "",
isRange: true,
duration: {
startTime: null,
endTime: null,
startTime: "",
endTime: "",
},
},
};
@@ -203,10 +202,10 @@ limitations under the License. -->
const { start, end } = setEndTime(i.start, i.end);
const startTime = dateFormatTime(start, appStore.duration.step);
const endTime = dateFormatTime(end, appStore.duration.step);
const item = {
const item: LayoutConfig = {
...widget,
filters: {
sourceId: dashboardStore.selectedGrid.id || "",
sourceId: dashboardStore.selectedGrid?.id || "",
isRange: true,
duration: {
startTime,

View File

@@ -150,7 +150,6 @@ limitations under the License. -->
return;
}
eventStore.setEventCondition({
// layer: dashboardStore.layerId,
paging: {
pageNum: pageNum.value,
pageSize: pageSize,

View File

@@ -150,17 +150,22 @@ limitations under the License. -->
needQuery: { type: Boolean, default: true },
data: {
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
default: () => ({}),
},
});
const { t } = useI18n();
const appStore = useAppStoreWithOut();
const appStore: ReturnType<typeof useAppStoreWithOut> = useAppStoreWithOut();
const selectorStore = useSelectorStore();
const dashboardStore = useDashboardStore();
const logStore = useLogStore();
const { setDurationRow, getDurationTime, getMaxRange } = useDuration();
const traceId = ref<string>((props.data.filters && props.data.filters.traceId) || "");
const duration = ref<DurationTime>((props.data.filters && props.data.filters.duration) || getDurationTime());
const traceId = ref<string>(props.data.filters?.traceId || "");
const { duration: filtersDuration } = props.data.filters || {};
const duration = ref<DurationTime>(
filtersDuration
? { start: filtersDuration.startTime || "", end: filtersDuration.endTime || "", step: filtersDuration.step || "" }
: getDurationTime(),
);
const keywordsOfContent = ref<string[]>([]);
const excludingKeywordsOfContent = ref<string[]>([]);
const tagsList = ref<string[]>([]);
@@ -175,17 +180,17 @@ limitations under the License. -->
service: { value: "", label: "" },
category: { value: "ALL", label: "All" },
});
const maxRange = computed(() =>
getMaxRange(
appStore.coldStageMode
? isBrowser.value
? appStore.recordsTTL.coldBrowserErrorLog
: appStore.recordsTTL.coldLog
: isBrowser.value
? appStore.recordsTTL.browserErrorLog
: appStore.recordsTTL.log,
),
);
const maxRange = computed(() => {
const ttl = appStore.coldStageMode
? isBrowser.value
? appStore.recordsTTL?.coldBrowserErrorLog
: appStore.recordsTTL?.coldLog
: isBrowser.value
? appStore.recordsTTL?.browserErrorLog
: appStore.recordsTTL?.log;
return getMaxRange(ttl as number);
});
if (props.needQuery) {
init();
}
@@ -259,10 +264,10 @@ limitations under the License. -->
let endpoint = "",
instance = "";
if (dashboardStore.entity === EntityType[2].value) {
endpoint = selectorStore.currentPod.id;
endpoint = selectorStore.currentPod?.id || "";
}
if (dashboardStore.entity === EntityType[3].value) {
instance = selectorStore.currentPod.id;
instance = selectorStore.currentPod?.id || "";
}
if (dashboardStore.layerId === "BROWSER") {
logStore.setLogCondition({
@@ -396,8 +401,15 @@ limitations under the License. -->
if (JSON.stringify(newJson) === JSON.stringify(oldJson)) {
return;
}
traceId.value = props.data.filters.traceId || "";
duration.value = props.data.filters.duration || getDurationTime();
const { traceId: filtersTraceId, duration: filtersDuration } = props.data.filters || {};
traceId.value = filtersTraceId || "";
duration.value = filtersDuration
? {
start: filtersDuration.startTime || "",
end: filtersDuration.endTime || "",
step: filtersDuration.step || "",
}
: getDurationTime();
init();
}
},

View File

@@ -39,19 +39,19 @@ limitations under the License. -->
import { ServiceLogConstants } from "./data";
import getDashboard from "@/hooks/useDashboardsSession";
import { useDashboardStore } from "@/store/modules/dashboard";
import type { LayoutConfig } from "@/types/dashboard";
import type { LayoutConfig, DashboardItem } from "@/types/dashboard";
import { dateFormat } from "@/utils/dateFormat";
import { WidgetType } from "@/views/dashboard/data";
import { useLogStore } from "@/store/modules/log";
const logStore = useLogStore();
/*global defineProps, defineEmits, Recordable */
/*global defineProps, defineEmits */
const props = defineProps({
data: { type: Object as any, default: () => ({}) },
noLink: { type: Boolean, default: true },
});
const dashboardStore = useDashboardStore();
const options: Recordable<LayoutConfig> = inject("options") || {};
const options: LayoutConfig | null = inject("options") || null;
const emit = defineEmits(["select"]);
const columns = ServiceLogConstants;
const level = computed(() => {
@@ -78,11 +78,11 @@ limitations under the License. -->
emit("select", props.data);
}
function linkTrace(id: string) {
const { associationWidget } = getDashboard(dashboardStore.currentDashboard);
const { associationWidget } = getDashboard(dashboardStore.currentDashboard as DashboardItem);
associationWidget(
(options.id as any) || "",
(options?.id || "") as string,
{
sourceId: options.id || "",
sourceId: (options?.id || "") as string,
traceId: id,
id: props.data.serviceId || "",
},

View File

@@ -128,6 +128,7 @@ limitations under the License. -->
import { useAppStoreWithOut } from "@/store/modules/app";
import icons from "@/assets/img/icons";
import { Themes } from "@/constants/data";
import type { EBPFTaskList } from "@/types/ebpf";
/*global Nullable, defineProps */
const props = defineProps({
@@ -361,7 +362,7 @@ limitations under the License. -->
if (dates.value) {
times = dates.value;
} else {
const { taskStartTime, fixedTriggerDuration } = networkProfilingStore.selectedNetworkTask;
const { taskStartTime, fixedTriggerDuration } = (networkProfilingStore.selectedNetworkTask as EBPFTaskList) || {};
const startTime =
fixedTriggerDuration > 1800 ? taskStartTime + fixedTriggerDuration * 1000 - 30 * 60 * 1000 : taskStartTime;
times = {

View File

@@ -15,7 +15,7 @@ limitations under the License. -->
<template>
<div class="label">{{ t("linkDashboard") }}</div>
<Selector
:value="(dashboardStore.selectedGrid && dashboardStore.selectedGrid.linkDashboard) || ''"
:value="dashboardStore.selectedGrid?.linkDashboard || ''"
:options="linkDashboards"
size="small"
placeholder="Please input a dashboard name for calls"
@@ -30,6 +30,7 @@ limitations under the License. -->
import type { DashboardItem } from "@/types/dashboard";
import { useDashboardStore } from "@/store/modules/dashboard";
import { EntityType } from "@/views/dashboard/data";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineEmits */
const emits = defineEmits(["update"]);
const { t } = useI18n();
@@ -55,13 +56,19 @@ limitations under the License. -->
function changeLinkDashboard(opt: { value: string }[]) {
const linkDashboard = opt.length ? opt[0].value : "";
const p = {
const item = {
x: 0,
y: 0,
w: 0,
h: 0,
i: "",
type: "",
...dashboardStore.selectedGrid,
linkDashboard,
};
dashboardStore.selectWidget(p);
dashboardStore.setConfigs(p);
emits("update", p);
dashboardStore.selectWidget(item as LayoutConfig);
dashboardStore.setConfigs(item as LayoutConfig);
emits("update", item);
}
</script>
<style lang="scss" scoped>

View File

@@ -39,7 +39,7 @@ limitations under the License. -->
<td
class="profile-td"
:class="{
selected: networkProfilingStore.selectedNetworkTask.taskId === i.taskId,
selected: networkProfilingStore.selectedNetworkTask?.taskId === i.taskId,
}"
>
<div class="ell">
@@ -103,7 +103,8 @@ limitations under the License. -->
getTopology();
}
async function getTopology() {
const { taskStartTime, fixedTriggerDuration, taskId } = networkProfilingStore.selectedNetworkTask;
const { taskStartTime, fixedTriggerDuration, taskId } =
(networkProfilingStore.selectedNetworkTask as EBPFTaskList) || {};
const serviceInstanceId = (selectorStore.currentPod && selectorStore.currentPod.id) || "";
const startTime =
fixedTriggerDuration > 1800 ? taskStartTime + fixedTriggerDuration * 1000 - 30 * 60 * 1000 : taskStartTime;
@@ -171,7 +172,9 @@ limitations under the License. -->
}
async function keepAliveNetwork() {
const res = await networkProfilingStore.keepNetworkProfiling(networkProfilingStore.selectedNetworkTask.taskId);
const res = await networkProfilingStore.keepNetworkProfiling(
networkProfilingStore.selectedNetworkTask?.taskId || "",
);
if (res.errors) {
intervalKeepAlive.value && clearInterval(intervalKeepAlive.value);
return ElMessage.error(res.errors);

View File

@@ -36,6 +36,7 @@ limitations under the License. -->
import dateFormatStep from "@/utils/dateFormat";
import getLocalTime from "@/utils/localtime";
import { useAppStoreWithOut } from "@/store/modules/app";
import type { EBPFTaskList } from "@/types/ebpf";
/*global Nullable, defineEmits */
const emits = defineEmits(["get"]);
@@ -55,10 +56,11 @@ limitations under the License. -->
if (!timeRange.value) {
return;
}
if (!networkProfilingStore.selectedNetworkTask.taskId) {
if (!networkProfilingStore.selectedNetworkTask?.taskId) {
return;
}
const { taskStartTime, fixedTriggerDuration, targetType, taskId } = networkProfilingStore.selectedNetworkTask;
const { taskStartTime, fixedTriggerDuration, targetType, taskId } =
(networkProfilingStore.selectedNetworkTask as EBPFTaskList) || {};
if (task.value[0] && task.value[0].data.taskId === taskId) {
if (isUpdate.value) {
return;

View File

@@ -89,7 +89,7 @@ limitations under the License. -->
};
countRange();
for (const tree of profileStore.analyzeTrees) {
const ele = processTree(tree.elements);
const ele = processTree(tree.elements as TraceProfilingElement[]);
root.children && root.children.push(ele);
}
const param = (root.children || []).reduce(

View File

@@ -70,7 +70,7 @@ limitations under the License. -->
if (!selectorStore.currentService) {
return;
}
const service = selectorStore.currentService.id;
const service = selectorStore.currentService.id || "";
const res = await profileStore.getEndpoints(service, keyword);
if (res.errors) {

View File

@@ -98,7 +98,7 @@ limitations under the License. -->
if (!selectorStore.currentService) {
return;
}
const service = selectorStore.currentService.id;
const service = selectorStore.currentService.id || "";
const res = await profileStore.getEndpoints(service, keyword);
if (res.errors) {
@@ -129,10 +129,14 @@ limitations under the License. -->
}
async function createTask() {
if (!selectorStore.currentService?.id) {
ElMessage.error("Please select a service");
return;
}
emits("close");
const date = monitorTime.value === "0" ? new Date() : time.value;
const params = {
serviceId: selectorStore.currentService.id,
serviceId: selectorStore.currentService?.id || "",
endpointName: endpointName.value,
startTime: date.getTime(),
duration: Number(monitorDuration.value),

View File

@@ -56,7 +56,7 @@ limitations under the License. -->
const { t } = useI18n();
const profileStore = useProfileStore();
const key = computed(
() => (profileStore.currentSegment.spans?.length && profileStore.currentSegment.spans[0].segmentId) || "",
() => (profileStore.currentSegment?.spans?.length && profileStore.currentSegment?.spans[0]?.segmentId) || "",
);
async function selectSegment(item: Trace) {

View File

@@ -35,14 +35,14 @@ limitations under the License. -->
@change="selectDisplayMode"
class="mr-10 fliter"
/>
<el-button type="primary" size="small" :disabled="!profileStore.currentSpan.profiled" @click="analyzeProfile()">
<el-button type="primary" size="small" :disabled="!profileStore.currentSpan?.profiled" @click="analyzeProfile()">
{{ t("analyze") }}
</el-button>
</div>
<div class="profile-table">
<Table
:data="profileStore.segmentSpans"
:traceId="profileStore.currentSegment.traceId"
:data="(profileStore.segmentSpans as SegmentSpan[])"
:traceId="profileStore.currentSegment?.traceId"
:headerType="WidgetType.Profile"
@select="selectSpan"
/>
@@ -55,7 +55,7 @@ limitations under the License. -->
import Table from "../../trace/components/Table.vue";
import { useProfileStore } from "@/store/modules/profile";
import Selector from "@/components/Selector.vue";
import type { Span } from "@/types/trace";
import type { SegmentSpan, ProfileTimeRange, ProfileAnalyzeParams } from "@/types/profile";
import type { Option } from "@/types/app";
import { ElMessage } from "element-plus";
import { ProfileDataMode, ProfileDisplayMode } from "./data";
@@ -68,9 +68,9 @@ limitations under the License. -->
const dataMode = ref<string>("include");
const displayMode = ref<string>("tree");
const message = ref<string>("");
const timeRange = ref<Array<{ start: number; end: number }>>([]);
const timeRange = ref<ProfileTimeRange[]>([]);
function selectSpan(span: Span) {
function selectSpan(span: SegmentSpan) {
profileStore.setCurrentSpan(span);
}
@@ -85,15 +85,15 @@ limitations under the License. -->
}
async function analyzeProfile() {
if (!profileStore.currentSpan.profiled) {
if (!profileStore.currentSpan?.profiled) {
ElMessage.info("It's a un-profiled span");
return;
}
emits("loading", true);
updateTimeRange();
const params = timeRange.value.map((t: { start: number; end: number }) => {
const params: ProfileAnalyzeParams[] = timeRange.value.map((t: ProfileTimeRange) => {
return {
segmentId: profileStore.currentSpan.segmentId,
segmentId: profileStore.currentSpan?.segmentId || "",
timeRange: t,
};
});
@@ -111,19 +111,19 @@ limitations under the License. -->
if (dataMode.value === "include") {
timeRange.value = [
{
start: profileStore.currentSpan.startTime,
end: profileStore.currentSpan.endTime,
start: profileStore.currentSpan?.startTime || 0,
end: profileStore.currentSpan?.endTime || 0,
},
];
} else {
const { children, startTime, endTime } = profileStore.currentSpan;
let dateRange = [];
const { children, startTime, endTime } = profileStore.currentSpan || {};
let dateRange: ProfileTimeRange[] = [];
if (!children || !children.length) {
if (!children?.length) {
timeRange.value = [
{
start: startTime,
end: endTime,
start: startTime || 0,
end: endTime || 0,
},
];
return;
@@ -131,16 +131,16 @@ limitations under the License. -->
for (const item of children) {
dateRange.push(
{
start: startTime,
end: item.startTime,
start: startTime || 0,
end: item.startTime || 0,
},
{
start: item.endTime,
end: endTime,
start: item.endTime || 0,
end: endTime || 0,
},
);
}
dateRange = dateRange.reduce((prev: any[], cur) => {
dateRange = dateRange.reduce((prev: ProfileTimeRange[], cur: ProfileTimeRange) => {
let isUpdate = false;
for (const item of prev) {
if (cur.start <= item.end && item.start <= cur.start) {

View File

@@ -118,7 +118,7 @@ limitations under the License. -->
const instanceLogs = ref<TaskLog | any>({});
async function changeTask(item: TaskListItem) {
profileStore.setCurrentSegment({});
profileStore.setCurrentSegment(null);
profileStore.setCurrentTask(item);
const res = await profileStore.getSegmentList({ taskID: item.id });
if (res.errors) {

View File

@@ -13,12 +13,12 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<div class="content" v-if="taskTimelineStore.selectedTask.targetType === TargetTypes[2].value">
<div class="content" v-if="taskTimelineStore.selectedTask?.targetType === TargetTypes[2].value">
<process-topology v-if="networkProfilingStore.nodes.length" :config="config" />
</div>
<div
class="content"
v-if="[TargetTypes[1].value, TargetTypes[0].value].includes(taskTimelineStore.selectedTask.targetType)"
v-if="[TargetTypes[1].value, TargetTypes[0].value].includes(taskTimelineStore.selectedTask?.targetType as string)"
>
<div class="schedules">
<EBPFSchedules />
@@ -27,7 +27,7 @@ limitations under the License. -->
<EBPFStack />
</div>
</div>
<div class="text" v-if="!taskTimelineStore.selectedTask.targetType">
<div class="text" v-if="!taskTimelineStore.selectedTask?.targetType">
{{ t("noData") }}
</div>
</template>

View File

@@ -16,7 +16,7 @@ limitations under the License. -->
<div ref="timeline" class="task-timeline"></div>
</template>
<script lang="ts" setup>
import { ref, watch, onMounted, onUnmounted } from "vue";
import { ref, watch, onMounted, onUnmounted, PropType } from "vue";
import dayjs from "dayjs";
import { useThrottleFn } from "@vueuse/core";
import { ElMessage } from "element-plus";
@@ -28,6 +28,7 @@ limitations under the License. -->
import { DataSet, Timeline } from "vis-timeline/standalone";
import "vis-timeline/styles/vis-timeline-graph2d.css";
import { EBPFProfilingTriggerType } from "@/store/data";
import type { LayoutConfig } from "@/types/dashboard";
const taskTimelineStore = useTaskTimelineStore();
const selectorStore = useSelectorStore();
@@ -36,7 +37,7 @@ limitations under the License. -->
/* global defineProps, Nullable */
const props = defineProps({
data: {
type: Object,
type: Object as PropType<LayoutConfig>,
default: () => ({}),
},
});
@@ -57,11 +58,11 @@ limitations under the License. -->
async function init() {
const serviceId = (selectorStore.currentService && selectorStore.currentService.id) || "";
const serviceInstanceId = (selectorStore.currentPod && selectorStore.currentPod.id) || "";
const type = continousProfilingStore.selectedStrategy.type;
const type = continousProfilingStore.selectedStrategy?.type || "";
const res = await taskTimelineStore.getContinousTaskList({
serviceId,
serviceInstanceId,
targets: type ? [type] : null,
targets: type ? [type] : [],
triggerType: EBPFProfilingTriggerType.CONTINUOUS_PROFILING,
});
if (res.errors) {
@@ -121,7 +122,7 @@ limitations under the License. -->
visGraph.value.on("select", async (properties: { items: number[] }) => {
dashboardStore.selectWidget(props.data);
const index = properties.items[0];
const task = taskTimelineStore.taskList[index];
const task = taskTimelineStore.taskList[index] as EBPFTaskList;
await taskTimelineStore.setSelectedTask(task);
await taskTimelineStore.getGraphData();

View File

@@ -75,7 +75,7 @@ limitations under the License. -->
import type { PropType } from "vue";
import { ref, computed, watch } from "vue";
import * as d3 from "d3";
import type { Node, Call } from "@/types/topology";
import type { Node, Call, HierarchyNode } from "@/types/topology";
import { useDashboardStore } from "@/store/modules/dashboard";
import icons from "@/assets/img/icons";
import { changeNode, computeHierarchyLevels, hierarchy } from "./utils/layout";
@@ -92,7 +92,7 @@ limitations under the License. -->
default: "",
},
nodes: {
type: Array as PropType<Node[]>,
type: Array as PropType<(Node | HierarchyNode)[]>,
default: () => [],
},
calls: {
@@ -136,7 +136,7 @@ limitations under the License. -->
function draw() {
const levels = computeHierarchyLevels(props.nodes);
topologyLayout.value = hierarchy(levels, props.calls, radius);
topologyLayout.value = hierarchy(levels as Node[][], props.calls, radius);
graphWidth.value = topologyLayout.value.layout.width;
graphHeight.value = topologyLayout.value.layout.height;
const drag: any = d3.drag().on("drag", (d: { x: number; y: number }) => {

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import * as d3 from "d3";
import type { Node, Call } from "@/types/topology";
import type { Node, Call, HierarchyNode } from "@/types/topology";
export function layout(levels: Node[][], calls: Call[], radius: number) {
// precompute level depth
@@ -279,14 +279,14 @@ export function hierarchy(levels: Node[][], calls: Call[], radius: number) {
return { nodes, layout, calls: computeCallPos(calls, radius) };
}
export function computeHierarchyLevels(nodes: Node[]) {
const levelsNum: number[] = nodes.map((d: Node) => d.l || 0);
export function computeHierarchyLevels(nodes: (Node | HierarchyNode)[]) {
const levelsNum: number[] = nodes.map((d: Node | HierarchyNode) => (d as Node).l || 0);
const list = [...new Set(levelsNum)];
const sortedArr = list.sort((a, b) => b - a);
const nodesList = [];
for (const min of sortedArr) {
const arr = nodes.filter((d) => d.l === min);
const arr = nodes.filter((d) => (d as Node).l === min);
nodesList.push(arr);
}

View File

@@ -52,6 +52,7 @@ limitations under the License. -->
import { EntityType, ConfigFieldTypes } from "@/views/dashboard/data";
import { useDashboardStore } from "@/store/modules/dashboard";
import getDashboard from "@/hooks/useDashboardsSession";
import type { MetricConfigOpt } from "@/types/dashboard";
/*global defineEmits, defineProps */
const props = defineProps({
@@ -68,16 +69,16 @@ limitations under the License. -->
return props.expressions || [];
}
let metrics: string[] = [];
const { linkServerExpressions, linkClientExpressions, nodeExpressions } = dashboardStore.selectedGrid;
const { linkServerExpressions, linkClientExpressions, nodeExpressions } = dashboardStore.selectedGrid || {};
switch (props.type) {
case "linkServerMetricConfig":
metrics = linkServerExpressions;
metrics = linkServerExpressions || [];
break;
case "linkClientMetricConfig":
metrics = linkClientExpressions;
metrics = linkClientExpressions || [];
break;
case "nodeMetricConfig":
metrics = nodeExpressions;
metrics = nodeExpressions || [];
break;
}
return metrics || [];
@@ -106,17 +107,17 @@ limitations under the License. -->
return config || [];
}
let config = [];
let config: MetricConfigOpt[] = [];
switch (props.type) {
case "linkServerMetricConfig":
config = dashboardStore.selectedGrid.linkServerMetricConfig;
config = dashboardStore.selectedGrid?.linkServerMetricConfig || [];
break;
case "linkClientMetricConfig":
config = dashboardStore.selectedGrid.linkClientMetricConfig;
config = dashboardStore.selectedGrid?.linkClientMetricConfig || [];
break;
case "nodeMetricConfig":
config = dashboardStore.selectedGrid.nodeMetricConfig;
config = dashboardStore.selectedGrid?.nodeMetricConfig || [];
break;
}
return config || [];

View File

@@ -161,7 +161,7 @@ limitations under the License. -->
import { ScopeType, EntityType, CallTypes } from "@/views/dashboard/data";
import type { Option } from "@/types/app";
import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor";
import type { DashboardItem, MetricConfigOpt } from "@/types/dashboard";
import type { DashboardItem, MetricConfigOpt, LayoutConfig, NodeDashboard } from "@/types/dashboard";
import type { Node } from "@/types/topology";
import Metrics from "./Metrics.vue";
@@ -171,38 +171,28 @@ limitations under the License. -->
const dashboardStore = useDashboardStore();
const topologyStore = useTopologyStore();
const { selectedGrid } = dashboardStore;
const nodeDashboard =
selectedGrid.nodeDashboard && selectedGrid.nodeDashboard.length ? selectedGrid.nodeDashboard : "";
const isService = [EntityType[0].value, EntityType[1].value].includes(dashboardStore.entity);
const items = reactive<
{
scope: string;
dashboard: string;
}[]
>(isService && nodeDashboard ? nodeDashboard : [{ scope: "", dashboard: "" }]);
const isService: boolean = [EntityType[0].value, EntityType[1].value].includes(dashboardStore.entity);
const items = reactive<NodeDashboard[]>((isService && selectedGrid?.nodeDashboard) || [{ scope: "", dashboard: "" }]);
const states = reactive<{
linkDashboard: string;
nodeDashboard: {
scope: string;
dashboard: string;
}[];
nodeDashboard: NodeDashboard[];
linkDashboards: (DashboardItem & { label: string; value: string })[];
nodeDashboards: (DashboardItem & { label: string; value: string })[];
linkServerExpressions: string[];
linkClientExpressions: string[];
nodeExpressions: string[];
}>({
linkDashboard: selectedGrid.linkDashboard || "",
nodeDashboard: selectedGrid.nodeDashboard || [],
linkDashboard: selectedGrid?.linkDashboard || "",
nodeDashboard: selectedGrid?.nodeDashboard || [],
linkDashboards: [],
nodeDashboards: [],
linkServerExpressions: selectedGrid.linkServerExpressions || [],
linkClientExpressions: selectedGrid.linkClientExpressions || [],
nodeExpressions: selectedGrid.nodeExpressions || [],
linkServerExpressions: selectedGrid?.linkServerExpressions || [],
linkClientExpressions: selectedGrid?.linkClientExpressions || [],
nodeExpressions: selectedGrid?.nodeExpressions || [],
});
const legendMQE = ref<{ expression: string }>(selectedGrid.legendMQE || { expression: "" });
const legendMQE = ref<{ expression: string }>(selectedGrid?.legendMQE || { expression: "" });
const configType = ref<string>("");
const description = reactive<any>(selectedGrid.description || {});
const description = reactive<any>(selectedGrid?.description || {});
getDashboardList();
async function getDashboardList() {
@@ -237,7 +227,7 @@ limitations under the License. -->
}
async function setLegend() {
updateSettings();
const expression = dashboardStore.selectedGrid.legendMQE && dashboardStore.selectedGrid.legendMQE.expression;
const expression: string = dashboardStore.selectedGrid?.legendMQE?.expression || "";
const { getMetrics } = useQueryTopologyExpressionsProcessor(
[expression],
topologyStore.nodes.filter((d: Node) => d.isReal),
@@ -295,7 +285,7 @@ limitations under the License. -->
legendMQE: legendMQE.value,
...metricConfig,
description,
};
} as LayoutConfig;
dashboardStore.selectWidget(param);
dashboardStore.setConfigs(param);
emit("update", param);
@@ -314,7 +304,7 @@ limitations under the License. -->
states.linkClientExpressions = param;
updateSettings();
if (!states.linkClientExpressions.length) {
topologyStore.changeLinkClientMetrics({});
topologyStore.setLinkClientMetrics({});
return;
}
topologyStore.getLinkExpressions(states.linkClientExpressions, CallTypes.Client);

View File

@@ -125,11 +125,11 @@ limitations under the License. -->
const html = exprssions.map((m: string, index: number) => {
const metric =
topologyStore.hierarchyInstanceNodeMetrics[data.layer || ""][m].values.find(
(val: { id: string; value: string }) => val.id === data.id,
) || {};
(val: { id: string; value: unknown }) => val.id === data.id,
) || null;
const opt: MetricConfigOpt = nodeMetricConfig[index] || {};
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric.value || NaN} ${
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric?.value || NaN} ${
opt.unit || ""
}</div>`;
});

View File

@@ -102,7 +102,7 @@ limitations under the License. -->
];
onMounted(() => {
loadTopology(selectorStore.currentPod && selectorStore.currentPod.id);
loadTopology(selectorStore.currentPod?.id);
window.addEventListener("resize", resize);
});
@@ -134,7 +134,7 @@ limitations under the License. -->
}
function inspect() {
const id = topologyStore.node.id;
const id = topologyStore.node?.id;
topologyStore.setNode(null);
topologyStore.setLink(null);
loadTopology(id);
@@ -158,7 +158,7 @@ limitations under the License. -->
ElMessage.error(`The dashboard named ${settings.value.nodeDashboard} doesn't exist`);
return;
}
const path = `/dashboard/${dashboard.layer}/${entity}/${topologyStore.node.serviceId}/${topologyStore.node.id}/${dashboard.name}`;
const path = `/dashboard/${dashboard.layer}/${entity}/${topologyStore.node?.serviceId}/${topologyStore.node?.id}/${dashboard.name}`;
const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank");
topologyStore.setNode(null);
@@ -175,7 +175,7 @@ limitations under the License. -->
}
function backToTopology() {
loadTopology(selectorStore.currentPod.id);
loadTopology(selectorStore.currentPod?.id);
topologyStore.setNode(null);
}
@@ -210,14 +210,14 @@ limitations under the License. -->
async function changeDepth(opt: Option[] | any) {
depth.value = opt[0].value;
loadTopology(selectorStore.currentPod.id);
loadTopology(selectorStore.currentPod?.id);
}
async function getTopology(id?: string) {
let resp;
switch (dashboardStore.entity) {
case EntityType[2].value:
resp = await topologyStore.updateEndpointTopology([id], Number(depth.value));
resp = await topologyStore.updateEndpointTopology([id as string], Number(depth.value));
break;
case EntityType[5].value:
resp = await topologyStore.getInstanceTopology();
@@ -238,7 +238,7 @@ limitations under the License. -->
watch(
() => [selectorStore.currentPod],
() => {
loadTopology(selectorStore.currentPod.id);
loadTopology(selectorStore.currentPod?.id);
topologyStore.setNode(null);
topologyStore.setLink(null);
},
@@ -257,7 +257,7 @@ limitations under the License. -->
watch(
() => appStore.durationTime,
() => {
loadTopology(selectorStore.currentPod.id);
loadTopology(selectorStore.currentPod?.id);
topologyStore.setNode(null);
topologyStore.setLink(null);
},

View File

@@ -91,11 +91,11 @@ limitations under the License. -->
const htmlServer = serverMetrics.map((m, index) => {
const metric =
topologyStore.linkServerMetrics[m]?.values?.find((val: { id: string; value: unknown }) => val.id === data.id) ||
{};
null;
if (metric) {
const opt: MetricConfigOpt = linkServerMetricConfig[index] || {};
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric.value} ${
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric?.value} ${
opt.unit || ""
}</div>`;
}
@@ -104,9 +104,9 @@ limitations under the License. -->
const opt: MetricConfigOpt = linkClientMetricConfig[index] || {};
const metric =
topologyStore.linkClientMetrics[m]?.values?.find((val: { id: string; value: unknown }) => val.id === data.id) ||
{};
null;
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric.value} ${opt.unit || ""}</div>`;
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric?.value} ${opt.unit || ""}</div>`;
});
const html = [
`<div>${data.sourceObj.serviceName} -> ${data.targetObj.serviceName}</div>`,
@@ -123,10 +123,10 @@ limitations under the License. -->
const html = nodeMetrics.map((m, index) => {
const metric =
topologyStore.nodeMetricValue[m]?.values?.find((val: { id: string; value: unknown }) => val.id === data.id) ||
{};
null;
const opt: MetricConfigOpt = nodeMetricConfig[index] || {};
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric.value} ${opt.unit || ""}</div>`;
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric?.value} ${opt.unit || ""}</div>`;
});
return [` <div><span>name: </span>${data.serviceName}</div>`, ...html].join(" ");
}

View File

@@ -133,10 +133,10 @@ limitations under the License. -->
const html = exprssions.map((m: string, index: number) => {
const metric =
topologyStore.hierarchyNodeMetrics[data.layer || ""][m].values.find(
(val: { id: string; value: string }) => val.id === data.id,
) || {};
(val: { id: string; value: unknown }) => val.id === data.id,
) || null;
const opt: MetricConfigOpt = nodeMetricConfig[index] || {};
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric.value || NaN} ${
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric?.value || NaN} ${
opt.unit || ""
}</div>`;
});

View File

@@ -219,10 +219,10 @@ limitations under the License. -->
loading.value = true;
topologyStore.setNode(null);
topologyStore.setLink(null);
const resp = await getTopology();
const resp: any = await getTopology();
loading.value = false;
if (resp && resp.errors) {
if (resp?.errors) {
ElMessage.error(resp.errors);
}
await update();
@@ -309,10 +309,10 @@ limitations under the License. -->
const nodeMetricConfig = settings.value.nodeMetricConfig || [];
const html = nodeMetrics.map((m, index) => {
const metric =
topologyStore.nodeMetricValue[m]?.values?.find((val: { id: string; value: string }) => val.id === data.id) ||
{};
topologyStore.nodeMetricValue[m]?.values?.find((val: { id: string; value: unknown }) => val.id === data.id) ||
null;
const opt: MetricConfigOpt = nodeMetricConfig[index] || {};
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric.value || NaN} ${
return ` <div class="mb-5"><span class="grey">${opt.label || m}: </span>${metric?.value || NaN} ${
opt.unit || "unknown"
}</div>`;
});
@@ -415,11 +415,11 @@ limitations under the License. -->
hierarchyRelated.value = true;
}
async function handleInspect() {
const id = topologyStore.node.id;
const id = topologyStore.node?.id || "";
loading.value = true;
const resp = await topologyStore.getDepthServiceTopology([id], Number(depth.value));
const resp: any = await topologyStore.getDepthServiceTopology([id], Number(depth.value));
loading.value = false;
if (resp && resp.errors) {
if (resp?.errors) {
ElMessage.error(resp.errors);
}
await update();
@@ -431,7 +431,7 @@ limitations under the License. -->
return;
}
const origin = dashboardStore.entity;
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[2].value}/${topologyStore.node.id}/${params.dashboard}`;
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[2].value}/${topologyStore.node?.id}/${params.dashboard}`;
const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank");
@@ -442,7 +442,7 @@ limitations under the License. -->
return;
}
const origin = dashboardStore.entity;
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${topologyStore.node.id}/${params.dashboard}`;
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${topologyStore.node?.id}/${params.dashboard}`;
const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank");
@@ -453,7 +453,7 @@ limitations under the License. -->
return;
}
const origin = dashboardStore.entity;
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${topologyStore.node.id}/${params.dashboard}`;
const path = `/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${topologyStore.node?.id}/${params.dashboard}`;
const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank");
@@ -495,8 +495,8 @@ limitations under the License. -->
}
async function getTopology() {
const ids = selectorStore.services.map((d: Service) => d.id);
const serviceIds = dashboardStore.entity === EntityType[0].value ? [selectorStore.currentService.id] : ids;
const resp = await topologyStore.getDepthServiceTopology(serviceIds, Number(depth.value));
const serviceIds = dashboardStore.entity === EntityType[0].value ? [selectorStore.currentService?.id] : ids;
const resp = await topologyStore.getDepthServiceTopology(serviceIds as string[], Number(depth.value));
return resp;
}
function setConfig() {

View File

@@ -12,9 +12,9 @@ See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<div class="trace-detail" v-loading="loading">
<div class="trace-detail-wrapper clear" v-if="traceStore.currentTrace.endpointNames">
<div class="trace-detail-wrapper clear" v-if="traceStore.currentTrace?.endpointNames">
<h5 class="mb-5 mt-0">
<span class="vm">{{ traceStore.currentTrace.endpointNames[0] }}</span>
<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") }}
@@ -79,10 +79,10 @@ limitations under the License. -->
<div class="no-data" v-else>{{ t("noData") }}</div>
<div class="trace-chart">
<component
v-if="traceStore.currentTrace.endpointNames"
v-if="traceStore.currentTrace?.endpointNames"
:is="displayMode"
:data="traceStore.traceSpans"
:traceId="traceStore.currentTrace.traceIds[0].value"
:traceId="traceStore.currentTrace?.traceIds?.[0]?.value"
:showBtnDetail="false"
:headerType="WidgetType.Trace"
/>
@@ -115,8 +115,7 @@ limitations under the License. -->
props,
setup(props) {
const appStore = useAppStoreWithOut();
/*global Recordable */
const options: Recordable<LayoutConfig> = inject("options") || {};
const options: LayoutConfig | null = inject("options") || null;
const { t } = useI18n();
const traceStore = useTraceStore();
const loading = ref<boolean>(false);
@@ -124,7 +123,7 @@ limitations under the License. -->
const displayMode = ref<string>("List");
function handleClick() {
copy(traceId.value || traceStore.currentTrace.traceIds[0].value);
copy(traceId.value || traceStore.currentTrace?.traceIds?.[0]?.value);
}
async function changeTraceId(opt: Option[]) {
@@ -140,10 +139,10 @@ limitations under the License. -->
async function searchTraceLogs() {
const { associationWidget } = getDashboard();
associationWidget(
(options.id as any) || "",
options?.id || "",
{
sourceId: options?.id || "",
traceId: traceId.value || traceStore.currentTrace.traceIds[0].value,
traceId: traceId.value || traceStore.currentTrace?.traceIds?.[0]?.value,
id: props.serviceId || undefined,
},
WidgetType.Log,

View File

@@ -115,11 +115,16 @@ limitations under the License. -->
const appStore = useAppStoreWithOut();
const selectorStore = useSelectorStore();
const dashboardStore = useDashboardStore();
const traceStore = useTraceStore();
const traceStore: ReturnType<typeof useTraceStore> = useTraceStore();
const { setDurationRow, getDurationTime, getMaxRange } = useDuration();
const filters = reactive<Recordable>(props.data.filters || {});
const traceId = ref<string>(filters.traceId || "");
const duration = ref<DurationTime>(filters.duration || getDurationTime());
const { duration: filtersDuration } = filters;
const duration = ref<DurationTime>(
filtersDuration
? { start: filtersDuration.startTime || "", end: filtersDuration.endTime || "", step: filtersDuration.step || "" }
: getDurationTime(),
);
const minTraceDuration = ref<number>();
const maxTraceDuration = ref<number>();
const tagsList = ref<string[]>([]);
@@ -132,7 +137,7 @@ limitations under the License. -->
});
const durationRow = ref<Duration>(InitializationDurationRow);
const maxRange = computed(() =>
getMaxRange(appStore.coldStageMode ? appStore.recordsTTL.coldTrace : appStore.recordsTTL.trace),
getMaxRange(appStore.coldStageMode ? appStore.recordsTTL?.coldTrace || 0 : appStore.recordsTTL?.trace || 0),
);
if (filters.queryOrder) {
traceStore.setTraceCondition({
@@ -171,7 +176,7 @@ limitations under the License. -->
state.service = { value: "", label: "" };
return;
} else {
state.service = getCurrentNode(traceStore.services) || traceStore.services[0];
state.service = getCurrentNode(traceStore.services as { id: string }[]) || traceStore.services[0];
}
emits("get", state.service.id);
@@ -186,7 +191,7 @@ limitations under the License. -->
ElMessage.error(resp.errors);
return;
}
state.endpoint = getCurrentNode(traceStore.endpoints) || traceStore.endpoints[0];
state.endpoint = getCurrentNode(traceStore.endpoints as { id: string }[]) || traceStore.endpoints[0];
}
async function getInstances(id?: string) {
const resp = await traceStore.getInstances(id);
@@ -194,7 +199,7 @@ limitations under the License. -->
ElMessage.error(resp.errors);
return;
}
state.instance = getCurrentNode(traceStore.instances) || traceStore.instances[0];
state.instance = getCurrentNode(traceStore.instances as { id: string }[]) || traceStore.instances[0];
}
function getCurrentNode(arr: { id: string }[]) {
let item;
@@ -230,10 +235,10 @@ limitations under the License. -->
let endpoint = "",
instance = "";
if (dashboardStore.entity === EntityType[2].value) {
endpoint = selectorStore.currentPod.id;
endpoint = selectorStore.currentPod?.id || "";
}
if (dashboardStore.entity === EntityType[3].value) {
instance = selectorStore.currentPod.id;
instance = selectorStore.currentPod?.id || "";
}
param = {
...param,
@@ -320,8 +325,15 @@ limitations under the License. -->
if (JSON.stringify(newJson) === JSON.stringify(oldJson)) {
return;
}
traceId.value = props.data.filters.traceId || "";
duration.value = props.data.filters.duration || getDurationTime();
const { traceId: filtersTraceId, duration: filtersDuration } = props.data.filters || {};
traceId.value = filtersTraceId || "";
duration.value = filtersDuration
? {
start: filtersDuration.startTime || "",
end: filtersDuration.endTime || "",
step: filtersDuration.step || "",
}
: getDurationTime();
init();
},
);

View File

@@ -19,7 +19,7 @@ limitations under the License. -->
</div>
<div class="conditions flex-h" v-else>
<el-radio-group v-model="conditions" @change="changeCondition" size="small">
<el-radio-button v-for="(item, index) in items" :label="item.label" :key="item.label + index" border>
<el-radio-button v-for="(item, index) in items" :value="item.label" :key="item.label + index" border>
{{ t(item.label) }}
</el-radio-button>
</el-radio-group>
@@ -92,6 +92,7 @@ limitations under the License. -->
import ConditionTags from "@/views/components/ConditionTags.vue";
import { ElMessage } from "element-plus";
import { EntityType, QueryOrders, Status } from "../../data";
import type { LayoutConfig } from "@/types/dashboard";
const FiltersKeys: { [key: string]: string } = {
status: "traceState",
@@ -104,8 +105,8 @@ limitations under the License. -->
const props = defineProps({
needQuery: { type: Boolean, default: true },
data: {
type: Object as PropType<Recordable>,
default: () => ({ graph: {} }),
type: Object as PropType<LayoutConfig>,
default: () => ({}),
},
});
const { t } = useI18n();
@@ -118,7 +119,12 @@ limitations under the License. -->
const tagsList = ref<string[]>([]);
const tagsMap = ref<Option[]>([]);
const traceId = ref<string>(filters.refId || "");
const duration = ref<DurationTime>(filters.duration || appStore.durationTime);
const { duration: filtersDuration } = props.data.filters || {};
const duration = ref<DurationTime>(
filtersDuration
? { start: filtersDuration.startTime || "", end: filtersDuration.endTime || "", step: filtersDuration.step || "" }
: appStore.durationTime,
);
const state = reactive<Recordable>({
instance: "",
endpoint: "",
@@ -150,12 +156,12 @@ limitations under the License. -->
state.instance = filters.owner.serviceInstanceID;
}
} else {
state.service = selectorStore.currentService.id;
state.service = selectorStore.currentService?.id || "";
if (dashboardStore.entity === EntityType[2].value) {
state.endpoint = selectorStore.currentPod.id;
state.endpoint = selectorStore.currentPod?.id || "";
}
if (dashboardStore.entity === EntityType[3].value) {
state.instance = selectorStore.currentPod.id;
state.instance = selectorStore.currentPod?.id || "";
}
}
await queryTraces();
@@ -169,7 +175,7 @@ limitations under the License. -->
await getService();
}
if (dashboardStore.entity === EntityType[0].value) {
state.service = selectorStore.currentService.id;
state.service = selectorStore.currentService?.id || "";
await getInstance();
if (!state.instance) {
await getEndpoint();

View File

@@ -30,10 +30,10 @@ limitations under the License. -->
import TraceList from "./TraceList.vue";
import TraceDetail from "./Detail.vue";
import type { LayoutConfig } from "@/types/dashboard";
/*global defineProps, Recordable */
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<LayoutConfig | Recordable>,
type: Object as PropType<LayoutConfig>,
default: () => ({ graph: {} }),
},
});

View File

@@ -56,7 +56,7 @@ limitations under the License. -->
red: i.isError,
}"
>
<span class="b">{{ i.endpointNames[0] }}</span>
<span class="b">{{ i.endpointNames?.[0] }}</span>
</div>
<div class="grey ell sm">
<span class="tag mr-10 sm"> {{ i.duration }} ms </span>

View File

@@ -61,10 +61,11 @@ limitations under the License. -->
import { mutationObserver } from "@/utils/mutation";
import { TraceGraphType } from "../constant";
import { Themes } from "@/constants/data";
import type { SegmentSpan } from "@/types/profile";
/* global Recordable, Nullable */
const props = defineProps({
data: { type: Array as PropType<Span[]>, default: () => [] },
data: { type: Array as PropType<(Span | SegmentSpan)[]>, default: () => [] },
traceId: { type: String, default: "" },
type: { type: String, default: TraceGraphType.LIST },
headerType: { type: String, default: "" },
@@ -79,8 +80,8 @@ limitations under the License. -->
const refSpans = ref<Array<Ref>>([]);
const tree = ref<Nullable<any>>(null);
const traceGraph = ref<Nullable<HTMLDivElement>>(null);
const parentSpans = ref<Array<Span>>([]);
const refParentSpans = ref<Array<Span>>([]);
const parentSpans = ref<Array<Span | SegmentSpan>>([]);
const refParentSpans = ref<Array<Span | SegmentSpan>>([]);
const debounceFunc = debounce(draw, 500);
const visDate = (date: number, pattern = "YYYY-MM-DD HH:mm:ss:SSS") => dayjs(date).format(pattern);

View File

@@ -157,18 +157,17 @@ limitations under the License. -->
import { dateFormat } from "@/utils/dateFormat";
import { useTraceStore } from "@/store/modules/trace";
import LogTable from "@/views/dashboard/related/log/LogTable/Index.vue";
import type { SpanAttachedEvent } from "@/types/trace";
import type { SpanAttachedEvent, Ref, Span } from "@/types/trace";
import getDashboard from "@/hooks/useDashboardsSession";
import { useDashboardStore } from "@/store/modules/dashboard";
import { WidgetType } from "@/views/dashboard/data";
import type { LayoutConfig } from "@/types/dashboard";
import type { LayoutConfig, DashboardItem } from "@/types/dashboard";
/*global defineProps, Nullable, Recordable */
const props = defineProps({
currentSpan: { type: Object as PropType<Recordable>, default: () => ({}) },
currentSpan: { type: Object as PropType<Span>, default: () => ({}) },
traceId: { type: String, default: "" },
});
const options: Recordable<LayoutConfig> = inject("options") || {};
const options: LayoutConfig | null = inject("options") || null;
const { t } = useI18n();
const traceStore = useTraceStore();
const dashboardStore = useDashboardStore();
@@ -246,12 +245,12 @@ limitations under the License. -->
tree.value.draw();
}
function viewRelateTrace(item: Recordable) {
const { associationWidget } = getDashboard(dashboardStore.currentDashboard);
function viewRelateTrace(item: Ref) {
const { associationWidget } = getDashboard(dashboardStore.currentDashboard as DashboardItem);
associationWidget(
(options.id as any) || "",
(options?.id as string) || "",
{
sourceId: options.id || "",
sourceId: (options?.id as string) || "",
traceId: item.traceId || "",
id: "0",
},

View File

@@ -24,11 +24,12 @@ limitations under the License. -->
<script lang="ts" setup>
import type { PropType } from "vue";
import type { Span } from "@/types/trace";
import type { SegmentSpan } from "@/types/profile";
import Graph from "./D3Graph/Index.vue";
import { TraceGraphType } from "./constant";
defineProps({
data: { type: Array as PropType<Span[]>, default: () => [] },
data: { type: Array as PropType<(Span | SegmentSpan)[]>, default: () => [] },
traceId: { type: String, default: "" },
headerType: { type: String, default: "" },
});

View File

@@ -17,16 +17,16 @@ limitations under the License. -->
<div v-if="type === TraceGraphType.STATISTICS">
<div class="trace-item">
<div :class="['method']">
<el-tooltip :content="data.groupRef.endpointName" placement="top" :show-after="300">
<el-tooltip :content="data.groupRef?.endpointName" placement="top" :show-after="300">
<span>
{{ data.groupRef.endpointName }}
{{ data.groupRef?.endpointName }}
</span>
</el-tooltip>
</div>
<div :class="['type']">
<el-tooltip :content="data.groupRef.type" placement="top" :show-after="300">
<el-tooltip :content="data.groupRef?.type" placement="top" :show-after="300">
<span>
{{ data.groupRef.type }}
{{ data.groupRef?.type }}
</span>
</el-tooltip>
</div>
@@ -40,7 +40,7 @@ limitations under the License. -->
{{ data.sumTime }}
</div>
<div class="avg-time">
{{ parseInt(data.avgTime) }}
{{ parseInt(data.avgTime || "0") }}
</div>
<div class="count">
{{ data.count }}
@@ -52,7 +52,7 @@ limitations under the License. -->
@click="selectSpan"
:class="[
'trace-item',
'level' + (data.level - 1),
'level' + ((data.level || 0) - 1),
{ 'trace-item-error': data.isError },
{ profiled: data.profiled === false },
`trace-item-${data.key}`,
@@ -60,9 +60,9 @@ limitations under the License. -->
:data-text="data.profiled === false ? 'No Thread Dump' : ''"
>
<div
:class="['method', 'level' + (data.level - 1)]"
:class="['method', 'level' + ((data.level || 0) - 1)]"
:style="{
'text-indent': (data.level - 1) * 10 + 'px',
'text-indent': ((data.level || 0) - 1) * 10 + 'px',
width: `${method}px`,
}"
>
@@ -152,10 +152,11 @@ limitations under the License. -->
import { Themes } from "@/constants/data";
import { TraceGraphType } from "../constant";
import { WidgetType } from "@/views/dashboard/data";
import type { Span, Ref } from "@/types/trace";
/*global Recordable*/
const props = {
data: { type: Object as PropType<Recordable>, default: () => ({}) },
data: { type: Object as PropType<Span>, default: () => ({}) },
method: { type: Number, default: 0 },
type: { type: String, default: "" },
headerType: { type: String, default: "" },
@@ -181,7 +182,7 @@ limitations under the License. -->
} else {
const data = props.data;
const exec = data.endTime - data.startTime ? data.endTime - data.startTime : 0;
let result = (exec / data.totalExec) * 100;
let result = (exec / (data.totalExec || 0)) * 100;
result = result > 100 ? 100 : result;
const resultStr = result.toFixed(4) + "%";
return resultStr === "0.0000%" ? "0.9%" : resultStr;
@@ -193,7 +194,7 @@ limitations under the License. -->
return resultStr === "0.0000%" ? "0.9%" : resultStr;
});
const isCrossThread = computed(() => {
const key = props.data.refs.findIndex((d: { type: string }) => d.type === "CROSS_THREAD");
const key = props.data.refs?.findIndex((d: Ref) => d.type === "CROSS_THREAD") ?? -1;
return key > -1 ? true : false;
});
function toggle() {
@@ -228,7 +229,7 @@ limitations under the License. -->
selectedItem(props.data);
viewSpanDetail(dom);
}
function selectedItem(span: Recordable) {
function selectedItem(span: Span) {
traceStore.setSelectedSpan(span);
}
function viewSpanDetail(dom: HTMLSpanElement) {

Some files were not shown because too many files have changed in this diff Show More