feat: Move topology to widgets (#29)

This commit is contained in:
Fine0830 2022-03-20 19:45:31 +08:00 committed by GitHub
parent 597e98e291
commit 42d8e909f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 279 additions and 348 deletions

View File

@ -49,7 +49,7 @@ const props = defineProps({
default: () => [],
},
value: {
type: [Array, String] as PropType<string[] | string>,
type: [Array, String, Number] as PropType<any>,
default: () => [],
},
size: { type: null, default: "default" },

View File

@ -112,6 +112,7 @@ const msg = {
showGroup: "Show Group",
noRoot: "Please set a root dashboard for",
noWidget: "Please add widgets.",
rename: "Rename",
hourTip: "Select Hour",
minuteTip: "Select Minute",
secondTip: "Select Second",

View File

@ -112,6 +112,7 @@ const msg = {
noRoot: "请设置根仪表板,为",
showGroup: "显示分组",
noWidget: "请添加组件",
rename: "重命名",
hourTip: "选择小时",
minuteTip: "选择分钟",
secondTip: "选择秒数",

View File

@ -27,6 +27,7 @@ import { Duration } from "@/types/app";
import { AxiosResponse } from "axios";
import { ElMessage } from "element-plus";
import { useI18n } from "vue-i18n";
import { EntityType } from "@/views/dashboard/data";
interface DashboardState {
showConfig: boolean;
layout: LayoutConfig[];
@ -92,15 +93,15 @@ export const dashboardStore = defineStore({
];
}
if (type === "Topology") {
newItem.w = 4;
newItem.h = 6;
newItem.h = 36;
newItem.graph = {
fontColor: "white",
backgroundColor: "green",
iconTheme: true,
content: "Topology",
fontSize: 18,
showDepth: true,
depth:
this.entity === EntityType[1].value
? 1
: this.entity === EntityType[0].value
? 2
: 3,
};
}
if (type === "Trace" || type === "Profile" || type === "Log") {
@ -144,19 +145,13 @@ export const dashboardStore = defineStore({
metrics: [""],
};
if (type === "Topology") {
newItem.w = 4;
newItem.h = 6;
newItem.h = 32;
newItem.graph = {
fontColor: "white",
backgroundColor: "green",
iconTheme: true,
content: "Topology",
fontSize: 18,
showDepth: true,
};
}
if (type === "Trace" || type === "Profile" || type === "Log") {
newItem.h = 24;
newItem.h = 32;
}
if (this.layout[idx].children) {
const items = children.map((d: LayoutConfig) => {

View File

@ -129,6 +129,6 @@ export interface TopologyConfig {
iconTheme?: boolean;
content?: string;
fontSize?: number;
depth?: string;
depth?: number;
showDepth?: boolean;
}

View File

@ -28,16 +28,7 @@ limitations under the License. -->
@closed="dashboardStore.setConfigPanel(false)"
>
<TopologyConfig v-if="dashboardStore.selectedGrid.type === 'Topology'" />
<Widget v-else />
</el-dialog>
<el-dialog
v-model="dashboardStore.showTopology"
:destroy-on-close="true"
fullscreen
@closed="dashboardStore.setTopology(false)"
custom-class="dark-dialog"
>
<Topology />
<WidgetConfig v-else />
</el-dialog>
</div>
</template>
@ -47,9 +38,8 @@ import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router";
import GridLayout from "./panel/Layout.vue";
import Tool from "./panel/Tool.vue";
import Widget from "./configuration/Widget.vue";
import TopologyConfig from "./configuration/Topology.vue";
import Topology from "./related/topology/Index.vue";
import WidgetConfig from "./configuration/Widget.vue";
import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app";

View File

@ -60,7 +60,7 @@ limitations under the License. -->
{{ t("view") }}
</el-button>
<el-button size="small" @click="handleEdit(scope.row)">
{{ t("edit") }}
{{ t("rename") }}
</el-button>
<el-popconfirm
title="Are you sure to delete this?"
@ -122,7 +122,6 @@ import router from "@/router";
import { DashboardItem } from "@/types/dashboard";
import { saveFile, readFile } from "@/utils/file";
import { EntityType } from "./data";
import { findLastKey } from "lodash";
/*global Nullable*/
const { t } = useI18n();
@ -134,17 +133,7 @@ const loading = ref<boolean>(false);
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
const multipleSelection = ref<DashboardItem[]>([]);
const dashboardFile = ref<Nullable<HTMLDivElement>>(null);
// # - os-linux
// # - k8s
// # - general(agent-installed)
// # - faas
// # - mesh
// # - mesh-cp
// # - mesh-dp
// # - database
// # - cache
// # - browser
// # - skywalking
appStore.setPageTitle("Dashboard List");
const handleSelectionChange = (val: DashboardItem[]) => {
multipleSelection.value = val;

View File

@ -4,17 +4,32 @@ this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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>
<WidgetOptions />
<StyleOptions />
<div class="item">
<span class="label">{{ t("showDepth") }}</span>
<el-switch
v-model="showDepth"
active-text="Yes"
inactive-text="No"
@change="changeConfig({ showDepth })"
/>
</div>
<div class="item" v-show="showDepth">
<span class="label">{{ t("defaultDepth") }}</span>
<Selector
class="input"
size="small"
:value="depth"
:options="DepthList"
@change="changeDepth($event)"
/>
</div>
<div class="footer">
<el-button size="small">
{{ t("cancel") }}
@ -25,18 +40,34 @@ limitations under the License. -->
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { useI18n } from "vue-i18n";
import WidgetOptions from "./components/WidgetOptions.vue";
import StyleOptions from "./topology/StyleOptions.vue";
import { useDashboardStore } from "@/store/modules/dashboard";
import { DepthList } from "../data";
import { Option } from "@/types/app";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const { selectedGrid } = dashboardStore;
const showDepth = ref<boolean>(selectedGrid.graph.showDepth);
const depth = ref<number>(selectedGrid.graph.depth || 2);
function applyConfig() {
dashboardStore.setConfigs(dashboardStore.selectedGrid);
dashboardStore.setConfigPanel(false);
}
function changeConfig(param: { [key: string]: unknown }) {
const { selectedGrid } = dashboardStore;
const graph = {
...selectedGrid.graph,
...param,
};
dashboardStore.selectWidget({ ...selectedGrid, graph });
}
function changeDepth(opt: Option[] | any) {
const val = opt[0].value;
changeConfig({ depth: val });
}
</script>
<style lang="scss" scoped>
.footer {
@ -49,4 +80,15 @@ function applyConfig() {
width: 100%;
background-color: #fff;
}
.label {
font-size: 13px;
font-weight: 500;
display: block;
margin-bottom: 5px;
}
.item {
margin: 10px 0;
}
</style>

View File

@ -82,7 +82,7 @@ import { useAppStoreWithOut } from "@/store/modules/app";
import { Option } from "@/types/app";
import graphs from "../graphs";
import configs from "./widget/graph-styles";
import WidgetOptions from "./components/WidgetOptions.vue";
import WidgetOptions from "./widget/WidgetOptions.vue";
import StandardOptions from "./widget/StandardOptions.vue";
import MetricOptions from "./widget/MetricOptions.vue";

View File

@ -1,151 +0,0 @@
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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="item">
<span class="label">{{ t("backgroundColors") }}</span>
<Selector
:value="backgroundColor"
:options="colors"
size="small"
placeholder="Select a color"
class="input"
@change="changeConfig({ backgroundColor: $event[0].value })"
/>
</div>
<div class="item">
<span class="label">{{ t("fontSize") }}</span>
<el-slider
class="slider"
v-model="fontSize"
show-input
input-size="small"
:min="12"
:max="30"
:step="1"
@change="changeConfig({ fontSize })"
/>
</div>
<div class="item">
<span class="label">{{ t("fontColors") }}</span>
<Selector
:value="fontColor"
:options="colors"
size="small"
placeholder="Select a color"
class="input"
@change="changeConfig({ fontColor: $event[0].value })"
/>
</div>
<div class="item">
<span class="label">{{ t("iconTheme") }}</span>
<el-switch
v-model="iconTheme"
active-text="Light"
inactive-text="Dark"
@change="changeConfig({ iconTheme })"
/>
</div>
<div class="item">
<span class="label">{{ t("content") }}</span>
<el-input
class="input"
v-model="content"
size="small"
@change="changeConfig({ content })"
/>
</div>
<div class="item">
<span class="label">{{ t("showDepth") }}</span>
<el-switch
v-model="showDepth"
active-text="Yes"
inactive-text="No"
@change="changeConfig({ showDepth })"
/>
</div>
<div class="item" v-show="showDepth">
<span class="label">{{ t("defaultDepth") }}</span>
<Selector
class="input"
size="small"
:value="depth"
:options="DepthList"
@change="changeDepth($event)"
/>
</div>
</template>
<script lang="ts" setup>
import { useI18n } from "vue-i18n";
import { ref } from "vue";
import { useDashboardStore } from "@/store/modules/dashboard";
import { DepthList } from "../../data";
import { Option } from "@/types/app";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const { selectedGrid } = dashboardStore;
const iconTheme = ref(selectedGrid.graph.iconTheme || true);
const backgroundColor = ref(selectedGrid.graph.backgroundColor || "green");
const fontColor = ref(selectedGrid.graph.fontColor || "white");
const content = ref<string>(selectedGrid.graph.content);
const fontSize = ref<number>(selectedGrid.graph.fontSize);
const depth = ref<string>(selectedGrid.graph.depth || "2");
const showDepth = ref<boolean>(selectedGrid.graph.showDepth);
const colors = [
{
label: "Green",
value: "green",
},
{ label: "Blue", value: "blue" },
{ label: "Red", value: "red" },
{ label: "Grey", value: "grey" },
{ label: "White", value: "white" },
{ label: "Black", value: "black" },
{ label: "Orange", value: "orange" },
];
function changeConfig(param: { [key: string]: unknown }) {
const { selectedGrid } = dashboardStore;
const graph = {
...selectedGrid.graph,
...param,
};
dashboardStore.selectWidget({ ...selectedGrid, graph });
}
function changeDepth(opt: Option[]) {
const val = opt[0].value;
changeConfig({ depth: val });
}
</script>
<style lang="scss" scoped>
.slider {
width: 500px;
margin-top: -3px;
}
.label {
font-size: 13px;
font-weight: 500;
display: block;
margin-bottom: 5px;
}
.input {
width: 500px;
}
.item {
margin-bottom: 10px;
}
</style>

View File

@ -97,6 +97,7 @@ limitations under the License. -->
:key="item.i"
@click="clickTabGrid($event, item)"
:class="{ active: activeTabWidget === item.i }"
drag-ignore-from="svg.d3-trace-tree, .dragger, .micro-topo-chart"
>
<component
:is="item.type"

View File

@ -13,20 +13,8 @@ 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="topology">
<div class="header flex-h">
<div>{{ data.widget?.title || "" }}</div>
<div>
<el-tooltip :content="data.widget?.tips">
<span>
<Icon
iconName="info_outline"
size="sm"
class="operation"
v-show="data.widget?.tips"
/>
</span>
</el-tooltip>
<div class="topology flex-v">
<div class="operation">
<el-popover
placement="bottom"
trigger="click"
@ -35,7 +23,7 @@ limitations under the License. -->
>
<template #reference>
<span>
<Icon iconName="ellipsis_v" size="middle" class="operation" />
<Icon iconName="ellipsis_v" size="middle" />
</span>
</template>
<div class="tools" @click="editConfig">
@ -46,25 +34,7 @@ limitations under the License. -->
</div>
</el-popover>
</div>
</div>
<div
class="body"
@click="ViewTopology"
:style="{ backgroundColor: Colors[data.graph.backgroundColor] }"
>
<Icon
:iconName="data.graph.iconTheme ? 'topology-light' : 'topology-dark'"
size="middle"
/>
<div
:style="{
color: Colors[data.graph.fontColor],
fontSize: data.graph.fontSize + 'px',
}"
>
{{ data.graph.content }}
</div>
</div>
<Topology :config="props.data" />
</div>
</template>
<script lang="ts" setup>
@ -72,7 +42,8 @@ import type { PropType } from "vue";
import { useRoute } from "vue-router";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import { Colors } from "../data";
import Topology from "../related/topology/Index.vue";
/*global defineProps */
const props = defineProps({
data: {
@ -85,32 +56,27 @@ const { t } = useI18n();
const routeParams = useRoute().params;
const dashboardStore = useDashboardStore();
function removeTopo() {
dashboardStore.removeControls(props.data);
}
function editConfig() {
dashboardStore.setConfigPanel(true);
dashboardStore.selectWidget(props.data);
}
function ViewTopology() {
dashboardStore.setTopology(true);
}
function removeTopo() {
dashboardStore.removeControls(props.data);
}
</script>
<style lang="scss" scoped>
.topology {
font-size: 12px;
height: 100%;
}
.header {
height: 30px;
padding: 5px;
background-color: #333840;
width: 100%;
border-bottom: 1px solid #eee;
justify-content: space-between;
height: 100%;
font-size: 12px;
position: relative;
}
.operation {
position: absolute;
top: 5px;
right: 3px;
cursor: pointer;
}
@ -127,19 +93,6 @@ function removeTopo() {
}
}
.body {
text-align: center;
width: 100%;
height: calc(100% - 30px);
cursor: pointer;
box-sizing: border-box;
color: #333;
display: -webkit-box;
-webkit-box-orient: horizontal;
-webkit-box-pack: center;
-webkit-box-align: center;
}
.no-data {
font-size: 14px;
color: #888;

View File

@ -108,11 +108,7 @@ export default defineComponent({
const dashboardStore = useDashboardStore();
const selectorStore = useSelectorStore();
if (
dashboardStore.entity === EntityType[1].value ||
props.needQuery ||
!dashboardStore.currentDashboard.id
) {
if (props.needQuery || !dashboardStore.currentDashboard.id) {
queryMetrics();
}
@ -165,11 +161,7 @@ export default defineComponent({
}
);
watch(
() => [
selectorStore.currentService,
selectorStore.currentDestService,
appStore.durationTime,
],
() => [selectorStore.currentService, selectorStore.currentDestService],
() => {
if (
dashboardStore.entity === EntityType[0].value ||
@ -188,6 +180,14 @@ export default defineComponent({
queryMetrics();
}
);
watch(
() => appStore.durationTime,
() => {
if (dashboardStore.entity === EntityType[1].value) {
queryMetrics();
}
}
);
return {
state,

View File

@ -186,7 +186,6 @@ export const ServiceTools = [
export const InstanceTools = [
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
{ name: "all_inbox", content: "Add Tab", id: "addTab" },
{ name: "device_hub", content: "Add Topology", id: "addTopology" },
{ name: "merge", content: "Add Trace", id: "addTrace" },
{ name: "assignment", content: "Add Log", id: "addLog" },
{ name: "save", content: "Apply", id: "apply" },
@ -229,19 +228,10 @@ export enum LegendOpt {
VALUE = "value",
CONDITION = "condition",
}
export const DepthList = ["1", "2", "3", "4", "5"].map((item: string) => ({
export const DepthList = [1, 2, 3, 4, 5].map((item: number) => ({
value: item,
label: item,
}));
export const Colors: any = {
green: "#67C23A",
blue: "#409EFF",
red: "#F56C6C",
grey: "#909399",
white: "#fff",
black: "#000",
orange: "#E6A23C",
};
export const Status = [
{ label: "All", value: "ALL" },
{ label: "Success", value: "SUCCESS" },

View File

@ -35,7 +35,11 @@ limitations under the License. -->
<template #default="scope">
<router-link
class="link"
:to="`/dashboard/${dashboardStore.layerId}/${EntityType[2].value}/${selectorStore.currentService.id}/${scope.row.id}/${config.dashboardName}`"
:to="`/dashboard/${dashboardStore.layerId}/${
EntityType[2].value
}/${selectorStore.currentService.id}/${
scope.row.id
}/${config.dashboardName.split(' ').join('-')}`"
:style="{ fontSize: `${config.fontSize}px` }"
>
{{ scope.row.label }}

View File

@ -35,7 +35,11 @@ limitations under the License. -->
<template #default="scope">
<router-link
class="link"
:to="`/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${selectorStore.currentService.id}/${scope.row.id}/${config.dashboardName}`"
:to="`/dashboard/${dashboardStore.layerId}/${
EntityType[3].value
}/${selectorStore.currentService.id}/${
scope.row.id
}/${config.dashboardName.split(' ').join('-')}`"
:style="{ fontSize: `${config.fontSize}px` }"
>
{{ scope.row.label }}

View File

@ -31,7 +31,7 @@ limitations under the License. -->
:key="item.i"
@click="clickGrid(item)"
:class="{ active: dashboardStore.activedGridItem === item.i }"
drag-ignore-from="svg.d3-trace-tree, .dragger"
drag-ignore-from="svg.d3-trace-tree, .dragger, .micro-topo-chart"
>
<component :is="item.type" :data="item" />
</grid-item>

View File

@ -299,6 +299,14 @@ watch(
init();
}
);
watch(
() => appStore.durationTime,
() => {
if (dashboardStore.entity === EntityType[1].value) {
init();
}
}
);
</script>
<style lang="scss" scoped>
.inputs {

View File

@ -56,9 +56,14 @@ import { useProfileStore } from "@/store/modules/profile";
import { useSelectorStore } from "@/store/modules/selectors";
import { ElMessage } from "element-plus";
import NewTask from "./components/NewTask.vue";
import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app";
import { EntityType } from "../../data";
const profileStore = useProfileStore();
const appStore = useAppStoreWithOut();
const selectorStore = useSelectorStore();
const dashboardStore = useDashboardStore();
const { t } = useI18n();
// const service = ref<any>({});
const endpointName = ref<string>("");
@ -104,6 +109,14 @@ watch(
searchTasks();
}
);
watch(
() => appStore.durationTime,
() => {
if (dashboardStore.entity === EntityType[1].value) {
searchTasks();
}
}
);
</script>
<style lang="scss" scoped>
.header {

View File

@ -13,18 +13,26 @@ 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>
<PodTopology v-if="isSankey" />
<Graph v-else />
<PodTopology :config="config" v-if="isSankey" />
<Graph :config="config" v-else />
</template>
<script lang="ts" setup>
import type { PropType } from "vue";
import { ref } from "vue";
import Graph from "./components/Graph.vue";
import PodTopology from "./components/PodTopology.vue";
import { EntityType } from "../../data";
import { useDashboardStore } from "@/store/modules/dashboard";
/*global defineProps */
defineProps({
config: {
type: Object as PropType<any>,
default: () => ({ graph: {} }),
},
});
const dashboardStore = useDashboardStore();
const isSankey = ref<boolean>(
[EntityType[2].value, EntityType[4].value].includes(dashboardStore.entity)
[EntityType[2].value, EntityType[3].value].includes(dashboardStore.entity)
);
</script>

View File

@ -17,13 +17,14 @@ limitations under the License. -->
ref="chart"
class="micro-topo-chart"
v-loading="loading"
element-loading-background="rgba(0, 0, 0, 0)"
:style="`height: ${height}px`"
>
<div class="setting" v-show="showSetting">
<Settings @update="updateSettings" @updateNodes="freshNodes" />
</div>
<div class="tool">
<span v-show="dashboardStore.selectedGrid.showDepth">
<span v-show="config.graph.showDepth">
<span class="label">{{ t("currentDepth") }}</span>
<Selector
class="inputs"
@ -63,7 +64,8 @@ limitations under the License. -->
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onBeforeUnmount, reactive } from "vue";
import type { PropType } from "vue";
import { ref, onMounted, onBeforeUnmount, reactive, watch } from "vue";
import { useI18n } from "vue-i18n";
import * as d3 from "d3";
import d3tip from "d3-tip";
@ -82,14 +84,22 @@ import { ElMessage } from "element-plus";
import Settings from "./Settings.vue";
import { Option } from "@/types/app";
import { Service } from "@/types/selector";
import { useAppStoreWithOut } from "@/store/modules/app";
/*global Nullable */
/*global Nullable, defineProps */
const props = defineProps({
config: {
type: Object as PropType<any>,
default: () => ({ graph: {} }),
},
});
const { t } = useI18n();
const selectorStore = useSelectorStore();
const topologyStore = useTopologyStore();
const dashboardStore = useDashboardStore();
const height = ref<number>(document.body.clientHeight - 90);
const width = ref<number>(document.body.clientWidth - 40);
const appStore = useAppStoreWithOut();
const height = ref<number>(100);
const width = ref<number>(100);
const loading = ref<boolean>(false);
const simulation = ref<any>(null);
const svg = ref<Nullable<any>>(null);
@ -110,7 +120,7 @@ const items = ref<
{ id: "inspect", title: "Inspect", func: handleInspect },
{ id: "alarm", title: "Alarm", func: handleGoAlarm },
]);
const depth = ref<string>(dashboardStore.selectedGrid.depth || "2");
const depth = ref<number>(props.config.graph.depth || 2);
onMounted(async () => {
loading.value = true;
@ -119,19 +129,23 @@ onMounted(async () => {
if (resp && resp.errors) {
ElMessage.error(resp.errors);
}
const dom = document.querySelector(".topology")?.getBoundingClientRect() || {
height: 40,
width: 0,
};
height.value = dom.height - 40;
width.value = dom.width;
window.addEventListener("resize", resize);
svg.value = d3
.select(chart.value)
.append("svg")
.attr("class", "topo-svg")
.attr("height", height.value)
.attr("width", width.value);
svg.value = d3.select(chart.value).append("svg").attr("class", "topo-svg");
await init();
update();
});
async function init() {
tip.value = (d3tip as any)().attr("class", "d3-tip").offset([-8, 0]);
graph.value = svg.value.append("g").attr("class", "topo-svg-graph");
graph.value = svg.value
.append("g")
.attr("class", "topo-svg-graph")
.attr("transform", `translate(0, -100)`);
graph.value.call(tip.value);
simulation.value = simulationInit(
d3,
@ -410,8 +424,8 @@ function setConfig() {
showSetting.value = !showSetting.value;
}
function resize() {
height.value = document.body.clientHeight - 90;
width.value = document.body.clientWidth - 40;
height.value = document.body.clientHeight;
width.value = document.body.clientWidth;
svg.value.attr("height", height.value).attr("width", width.value);
}
function updateSettings(config: any) {
@ -453,7 +467,7 @@ async function freshNodes() {
update();
}
async function changeDepth(opt: Option[]) {
async function changeDepth(opt: Option[] | any) {
depth.value = opt[0].value;
await getTopology();
freshNodes();
@ -461,17 +475,40 @@ async function changeDepth(opt: Option[]) {
onBeforeUnmount(() => {
window.removeEventListener("resize", resize);
});
watch(
() => [selectorStore.currentService, selectorStore.currentDestService],
() => {
freshNodes();
}
);
watch(
() => appStore.durationTime,
() => {
if (dashboardStore.entity === EntityType[1].value) {
init();
}
}
);
</script>
<style lang="scss">
.topo-svg {
width: 100%;
height: calc(100% - 5px);
cursor: move;
}
.micro-topo-chart {
position: relative;
height: calc(100% - 30px);
overflow: auto;
margin-top: 30px;
.setting {
position: absolute;
top: 70px;
right: 0;
top: 80px;
right: 10px;
width: 400px;
height: 700px;
height: 600px;
background-color: #2b3037;
overflow: auto;
padding: 0 15px;
@ -510,8 +547,8 @@ onBeforeUnmount(() => {
.tool {
position: absolute;
top: 22px;
right: 0;
top: 35px;
right: 10px;
}
.switch-icon {
@ -524,11 +561,6 @@ onBeforeUnmount(() => {
border-radius: 3px;
}
.topo-svg {
display: block;
width: 100%;
}
.topo-line {
stroke-linecap: round;
stroke-width: 3px;

View File

@ -16,8 +16,7 @@ limitations under the License. -->
<div class="tool">
<span
v-show="
dashboardStore.entity === EntityType[2].value &&
dashboardStore.selectedGrid.showDepth
dashboardStore.entity === EntityType[2].value && config.graph.showDepth
"
>
<span class="label">{{ t("currentDepth") }}</span>
@ -47,6 +46,7 @@ limitations under the License. -->
class="sankey"
:style="`height:${height}px;width:${width}px;`"
v-loading="loading"
element-loading-background="rgba(0, 0, 0, 0)"
@click="handleClick"
>
<Sankey @click="selectNodeLink" />
@ -72,36 +72,47 @@ limitations under the License. -->
</div>
</template>
<script lang="ts" setup>
import { watch } from "vue";
import type { PropType } from "vue";
import { useI18n } from "vue-i18n";
import { ref, onMounted, reactive } from "vue";
import { Option } from "@/types/app";
import { useTopologyStore } from "@/store/modules/topology";
import { useDashboardStore } from "@/store/modules/dashboard";
import { useSelectorStore } from "@/store/modules/selectors";
import { useAppStoreWithOut } from "@/store/modules/app";
import { EntityType, DepthList } from "../../../data";
import { ElMessage } from "element-plus";
import Sankey from "./Sankey.vue";
import Settings from "./Settings.vue";
import router from "@/router";
/*global defineProps */
const props = defineProps({
config: {
type: Object as PropType<any>,
default: () => ({ graph: {} }),
},
});
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const selectorStore = useSelectorStore();
const topologyStore = useTopologyStore();
const appStore = useAppStoreWithOut();
const loading = ref<boolean>(false);
const height = ref<number>(document.body.clientHeight - 150);
const width = ref<number>(document.body.clientWidth - 40);
const height = ref<number>(100);
const width = ref<number>(100);
const showSettings = ref<boolean>(false);
const settings = ref<any>({});
const operationsPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
const depth = ref<string>(dashboardStore.selectedGrid.depth || "3");
const depth = ref<number>(props.config.graph.depth || 3);
const items = [
{ id: "inspect", title: "Inspect", func: inspect },
{ id: "dashboard", title: "View Dashboard", func: goDashboard },
{ id: "alarm", title: "View Alarm", func: goAlarm },
];
onMounted(async () => {
onMounted(() => {
loadTopology(selectorStore.currentPod && selectorStore.currentPod.id);
});
@ -112,6 +123,12 @@ async function loadTopology(id: string) {
if (resp && resp.errors) {
ElMessage.error(resp.errors);
}
const dom = document.querySelector(".topology")?.getBoundingClientRect() || {
height: 70,
width: 5,
};
height.value = dom.height - 70;
width.value = dom.width - 5;
}
function inspect() {
@ -176,7 +193,7 @@ function selectNodeLink(d: any) {
operationsPos.y = d.event.event.clientY;
}
async function changeDepth(opt: Option[]) {
async function changeDepth(opt: Option[] | any) {
depth.value = opt[0].value;
loadTopology(selectorStore.currentPod.id);
}
@ -190,7 +207,7 @@ async function getTopology(id: string) {
Number(depth.value)
);
break;
case EntityType[4].value:
case EntityType[3].value:
resp = await topologyStore.getInstanceTopology();
break;
}
@ -202,20 +219,36 @@ function handleClick(event: any) {
topologyStore.setLink(null);
}
}
watch(
() => [selectorStore.currentPod],
() => {
loadTopology(selectorStore.currentPod.id);
topologyStore.setNode(null);
topologyStore.setLink(null);
}
);
watch(
() => appStore.durationTime,
() => {
loadTopology(selectorStore.currentPod.id);
topologyStore.setNode(null);
topologyStore.setLink(null);
}
);
</script>
<style lang="scss" scoped>
.sankey {
margin-top: 10px;
background-color: #333840;
background-color: #333840 !important;
color: #ddd;
}
.settings {
position: absolute;
top: 40px;
right: 0;
top: 60px;
right: 10px;
width: 400px;
height: 700px;
height: 500px;
background-color: #2b3037;
overflow: auto;
padding: 0 15px;
@ -228,7 +261,8 @@ function handleClick(event: any) {
.tool {
text-align: right;
margin-top: 10px;
margin-top: 40px;
margin-right: 10px;
position: relative;
}

View File

@ -28,14 +28,14 @@ export default function topoLegend(
.attr("width", 30)
.attr("height", 30)
.attr("x", clientWidth - (item === "CUBEERROR" ? 340 : 440))
.attr("y", clientHeight - 50)
.attr("y", clientHeight + 50)
.attr("xlink:href", () =>
item === "CUBEERROR" ? icons.CUBEERROR : icons.CUBE
);
graph
.append("text")
.attr("x", clientWidth - (item === "CUBEERROR" ? 310 : 410))
.attr("y", clientHeight - 30)
.attr("y", clientHeight + 70)
.text(() => {
const l = config || [];
const str = l

View File

@ -210,7 +210,16 @@ function updateTags(data: { tagsMap: Array<Option>; tagsList: string[] }) {
tagsMap.value = data.tagsMap;
}
watch(
() => selectorStore.currentService,
() => [selectorStore.currentPod],
() => {
if (dashboardStore.entity === EntityType[0].value) {
return;
}
init();
}
);
watch(
() => [selectorStore.currentService],
() => {
if (dashboardStore.entity !== EntityType[0].value) {
return;
@ -218,6 +227,14 @@ watch(
init();
}
);
watch(
() => appStore.durationTime,
() => {
if (dashboardStore.entity === EntityType[1].value) {
init();
}
}
);
</script>
<style lang="scss" scoped>
.inputs {