feat: view pod relation dashboards with params

This commit is contained in:
Qiuxia Fan 2022-02-16 14:38:30 +08:00
parent 147f4f644d
commit 4ba120cad3
10 changed files with 261 additions and 38 deletions

View File

@ -87,6 +87,16 @@ export const routesDashboard: Array<RouteRecordRaw> = [
notShow: true, notShow: true,
}, },
}, },
{
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name",
component: () => import("@/views/dashboard/Edit.vue"),
name: "ViewPodRelation",
meta: {
title: "dashboardEdit",
exact: true,
notShow: true,
},
},
], ],
}, },
]; ];

View File

@ -143,3 +143,45 @@ export const ConfigData4: any = {
}, },
children: [], children: [],
}; };
export const ConfigData5: any = {
x: 0,
y: 0,
w: 8,
h: 12,
i: "0",
metrics: ["endpoint_relation_cpm"],
metricTypes: ["readMetricsValues"],
type: "Widget",
widget: {
title: "endpoint_relation_cpm",
tips: "Tooltip",
},
graph: {
type: "Line",
},
standard: {
unit: "min",
},
children: [],
};
export const ConfigData6: any = {
x: 0,
y: 0,
w: 8,
h: 12,
i: "0",
metrics: ["service_instance_relation_server_cpm"],
metricTypes: ["readMetricsValues"],
type: "Widget",
widget: {
title: "service_instance_relation_server_cpm",
tips: "Tooltip",
},
graph: {
type: "Line",
},
standard: {
unit: "min",
},
children: [],
};

View File

@ -25,6 +25,8 @@ import {
ConfigData2, ConfigData2,
ConfigData3, ConfigData3,
ConfigData4, ConfigData4,
ConfigData5,
ConfigData6,
} from "../data"; } from "../data";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
@ -170,6 +172,12 @@ export const dashboardStore = defineStore({
if (type == "ServiceRelation") { if (type == "ServiceRelation") {
this.layout = [ConfigData4]; this.layout = [ConfigData4];
} }
if (type == "ServiceInstanceRelation") {
this.layout = [ConfigData6];
}
if (type == "EndpointRelation") {
this.layout = [ConfigData5];
}
}, },
setTopology(show: boolean) { setTopology(show: boolean) {
this.showTopology = show; this.showTopology = show;

View File

@ -24,11 +24,13 @@ import { useAppStoreWithOut } from "@/store/modules/app";
interface SelectorState { interface SelectorState {
services: Service[]; services: Service[];
destServices: Service[];
pods: Array<Instance | Endpoint>; pods: Array<Instance | Endpoint>;
currentService: Nullable<Service>; currentService: Nullable<Service>;
currentPod: Nullable<Instance | Endpoint>; currentPod: Nullable<Instance | Endpoint>;
currentDestService: Nullable<Service>; currentDestService: Nullable<Service>;
currentDestPod: Nullable<Instance | Endpoint>; currentDestPod: Nullable<Instance | Endpoint>;
destPods: Array<Instance | Endpoint>;
durationTime: Duration; durationTime: Duration;
} }
@ -36,7 +38,9 @@ export const selectorStore = defineStore({
id: "selector", id: "selector",
state: (): SelectorState => ({ state: (): SelectorState => ({
services: [], services: [],
destServices: [],
pods: [], pods: [],
destPods: [],
currentService: null, currentService: null,
currentPod: null, currentPod: null,
currentDestService: null, currentDestService: null,
@ -54,7 +58,7 @@ export const selectorStore = defineStore({
this.currentPod = pod; this.currentPod = pod;
}, },
setCurrentDestPod(pod: Nullable<Instance | Endpoint>) { setCurrentDestPod(pod: Nullable<Instance | Endpoint>) {
this.currentPod = pod; this.currentDestPod = pod;
}, },
async fetchLayers(): Promise<AxiosResponse> { async fetchLayers(): Promise<AxiosResponse> {
const res: AxiosResponse = await graphql.query("queryLayers").params({}); const res: AxiosResponse = await graphql.query("queryLayers").params({});
@ -68,11 +72,13 @@ export const selectorStore = defineStore({
if (!res.data.errors) { if (!res.data.errors) {
this.services = res.data.data.services || []; this.services = res.data.data.services || [];
this.destServices = res.data.data.services || [];
} }
return res.data; return res.data;
}, },
async getServiceInstances(param?: { async getServiceInstances(param?: {
serviceId: string; serviceId: string;
isRelation: boolean;
}): Promise<Nullable<AxiosResponse>> { }): Promise<Nullable<AxiosResponse>> {
const serviceId = param ? param.serviceId : this.currentService?.id; const serviceId = param ? param.serviceId : this.currentService?.id;
if (!serviceId) { if (!serviceId) {
@ -83,20 +89,22 @@ export const selectorStore = defineStore({
duration: this.durationTime, duration: this.durationTime,
}); });
if (!res.data.errors) { if (!res.data.errors) {
if (param && param.isRelation) {
this.destPods = res.data.data.pods || [];
return res.data;
}
this.pods = res.data.data.pods || []; this.pods = res.data.data.pods || [];
} }
return res.data; return res.data;
}, },
async getEndpoints(params?: { async getEndpoints(params: {
keyword?: string; keyword?: string;
serviceId?: string; serviceId?: string;
isRelation?: boolean;
}): Promise<Nullable<AxiosResponse>> { }): Promise<Nullable<AxiosResponse>> {
if (!params) { if (!params) {
params = {}; params = {};
} }
if (!params.keyword) {
params.keyword = "";
}
const serviceId = params.serviceId || this.currentService?.id; const serviceId = params.serviceId || this.currentService?.id;
if (!serviceId) { if (!serviceId) {
return null; return null;
@ -104,14 +112,18 @@ export const selectorStore = defineStore({
const res: AxiosResponse = await graphql.query("queryEndpoints").params({ const res: AxiosResponse = await graphql.query("queryEndpoints").params({
serviceId, serviceId,
duration: this.durationTime, duration: this.durationTime,
keyword: params.keyword, keyword: params.keyword || "",
}); });
if (!res.data.errors) { if (!res.data.errors) {
if (params.isRelation) {
this.destPods = res.data.data.pods || [];
return res.data;
}
this.pods = res.data.data.pods || []; this.pods = res.data.data.pods || [];
} }
return res.data; return res.data;
}, },
async getService(serviceId: string) { async getService(serviceId: string, isRelation: boolean) {
if (!serviceId) { if (!serviceId) {
return; return;
} }
@ -119,13 +131,18 @@ export const selectorStore = defineStore({
serviceId, serviceId,
}); });
if (!res.data.errors) { if (!res.data.errors) {
if (isRelation) {
this.setCurrentDestService(res.data.data.service);
this.destServices = [res.data.data.service];
return res.data;
}
this.setCurrentService(res.data.data.service); this.setCurrentService(res.data.data.service);
this.services = [res.data.data.service]; this.services = [res.data.data.service];
} }
return res.data; return res.data;
}, },
async getInstance(instanceId: string) { async getInstance(instanceId: string, isRelation?: boolean) {
if (!instanceId) { if (!instanceId) {
return; return;
} }
@ -133,12 +150,18 @@ export const selectorStore = defineStore({
instanceId, instanceId,
}); });
if (!res.data.errors) { if (!res.data.errors) {
if (isRelation) {
this.currentDestPod = res.data.data.instance || null;
this.destPods = [res.data.data.instance];
return;
}
this.currentPod = res.data.data.instance || null; this.currentPod = res.data.data.instance || null;
this.pods = [res.data.data.instance];
} }
return res.data; return res.data;
}, },
async getEndpoint(endpointId: string) { async getEndpoint(endpointId: string, isRelation?: string) {
if (!endpointId) { if (!endpointId) {
return; return;
} }
@ -146,7 +169,13 @@ export const selectorStore = defineStore({
endpointId, endpointId,
}); });
if (!res.data.errors) { if (!res.data.errors) {
if (isRelation) {
this.currentDestPod = res.data.data.endpoint || null;
this.destPods = [res.data.data.endpoint];
return;
}
this.currentPod = res.data.data.endpoint || null; this.currentPod = res.data.data.endpoint || null;
this.pods = [res.data.data.endpoint];
} }
return res.data; return res.data;

View File

@ -147,7 +147,16 @@ export default defineComponent({
} }
); );
watch( watch(
() => selectorStore.currentPod, () => [selectorStore.currentPod],
() => {
if (dashboardStore.entity === EntityType[0].value) {
return;
}
queryMetrics();
}
);
watch(
() => [selectorStore.currentDestPod],
() => { () => {
if (dashboardStore.entity === EntityType[0].value) { if (dashboardStore.entity === EntityType[0].value) {
return; return;

View File

@ -166,9 +166,9 @@ export const ToolIcons = [
{ name: "playlist_add", content: "Add Widget", id: "addWidget" }, { name: "playlist_add", content: "Add Widget", id: "addWidget" },
{ name: "all_inbox", content: "Add Tab", id: "addTab" }, { name: "all_inbox", content: "Add Tab", id: "addTab" },
// { name: "insert_image", content: "Add Image", id: "addImage" }, // { name: "insert_image", content: "Add Image", id: "addImage" },
{ name: "save_alt", content: "Export", id: "export" }, // { name: "save_alt", content: "Export", id: "export" },
{ name: "folder_open", content: "Import", id: "import" }, // { name: "folder_open", content: "Import", id: "import" },
{ name: "settings", content: "Settings", id: "settings" }, // { name: "settings", content: "Settings", id: "settings" },
{ name: "device_hub", content: "Topology", id: "topology" }, { name: "device_hub", content: "Topology", id: "topology" },
{ name: "save", content: "Apply", id: "apply" }, // { name: "save", content: "Apply", id: "apply" },
]; ];

View File

@ -43,11 +43,11 @@ limitations under the License. -->
class="selectorPod" class="selectorPod"
/> />
</div> </div>
<div class="selectors-item" v-if="states.key === 2"> <div class="selectors-item" v-if="states.key === 2 || states.key === 4">
<span class="label">$DestinationService</span> <span class="label">$DestinationService</span>
<Selector <Selector
v-model="states.currentDestService" v-model="states.currentDestService"
:options="selectorStore.services" :options="selectorStore.destServices"
size="small" size="small"
placeholder="Select a service" placeholder="Select a service"
@change="changeDestService" @change="changeDestService"
@ -57,13 +57,12 @@ limitations under the License. -->
<div class="selectors-item" v-if="states.key === 4"> <div class="selectors-item" v-if="states.key === 4">
<span class="label">$DestinationServiceInstance</span> <span class="label">$DestinationServiceInstance</span>
<Selector <Selector
v-model="states.currentPod" v-model="states.currentDestPod"
:options="selectorStore.pods" :options="selectorStore.destPods"
size="small" size="small"
placeholder="Select a data" placeholder="Select a data"
@change="changePods" @change="changePods"
class="selectors" class="selectorPod"
:borderRadius="4"
/> />
</div> </div>
</div> </div>
@ -111,6 +110,7 @@ const states = reactive<{
currentService: string; currentService: string;
currentPod: string; currentPod: string;
currentDestService: string; currentDestService: string;
currentDestPod: string;
}>({ }>({
destService: "", destService: "",
destPod: "", destPod: "",
@ -118,6 +118,7 @@ const states = reactive<{
currentService: "", currentService: "",
currentPod: "", currentPod: "",
currentDestService: "", currentDestService: "",
currentDestPod: "",
}); });
dashboardStore.setLayer(String(params.layerId)); dashboardStore.setLayer(String(params.layerId));
@ -135,12 +136,19 @@ function initSelector() {
async function setSelector() { async function setSelector() {
if ( if (
params.entity === EntityType[2].value || [
params.entity === EntityType[3].value EntityType[2].value,
EntityType[3].value,
EntityType[5].value,
EntityType[6].value,
].includes(String(params.entity))
) { ) {
await selectorStore.getService(String(params.serviceId)); await selectorStore.getService(String(params.serviceId));
states.currentService = selectorStore.currentService.value; states.currentService = selectorStore.currentService.value;
await fetchPods(String(params.entity), false); await selectorStore.getService(String(params.destServiceId), true);
states.currentDestService = selectorStore.currentDestService.value;
const e = String(params.entity).split("Relation")[0];
await fetchPods(e, selectorStore.currentService.id, false);
if (!(selectorStore.pods.length && selectorStore.pods[0])) { if (!(selectorStore.pods.length && selectorStore.pods[0])) {
selectorStore.setCurrentPod(null); selectorStore.setCurrentPod(null);
states.currentPod = ""; states.currentPod = "";
@ -150,11 +158,36 @@ async function setSelector() {
const currentPod = selectorStore.pods.filter( const currentPod = selectorStore.pods.filter(
(d: { id: string }) => d.id === pod (d: { id: string }) => d.id === pod
)[0]; )[0];
selectorStore.setCurrentPod(currentPod); if (currentPod) {
states.currentPod = currentPod.label; selectorStore.setCurrentPod(currentPod);
states.currentPod = currentPod.label;
}
if (
[EntityType[2].value, EntityType[3].value].includes(String(params.entity))
) {
return;
}
await fetchPods(
String(params.entity),
selectorStore.currentDestService.id,
false
);
if (!(selectorStore.destPods.length && selectorStore.destPods[0])) {
selectorStore.setCurrentDestPod(null);
states.currentDestPod = "";
return;
}
const destPod = params.destPodId || selectorStore.destPods[0].id;
const currentDestPod = selectorStore.destPods.filter(
(d: { id: string }) => d.id === destPod
)[0];
if (currentDestPod) {
selectorStore.setCurrentDestPod(currentDestPod);
states.currentDestPod = currentDestPod.label;
}
return; return;
} }
// entity=Service with serviceId // entity=Service/ServiceRelation
const json = await selectorStore.fetchServices(dashboardStore.layerId); const json = await selectorStore.fetchServices(dashboardStore.layerId);
if (json.errors) { if (json.errors) {
ElMessage.error(json.errors); ElMessage.error(json.errors);
@ -195,14 +228,16 @@ async function getServices() {
); );
states.currentService = selectorStore.currentService.value; states.currentService = selectorStore.currentService.value;
states.currentDestService = selectorStore.currentDestService.value; states.currentDestService = selectorStore.currentDestService.value;
fetchPods(dashboardStore.entity, true); const e = dashboardStore.entity.split("Relation")[0];
fetchPods(e, selectorStore.currentService.id, true);
fetchPods(dashboardStore.entity, selectorStore.currentDestService.id, true);
} }
async function changeService(service: Service[]) { async function changeService(service: Service[]) {
if (service[0]) { if (service[0]) {
states.currentService = service[0].value; states.currentService = service[0].value;
selectorStore.setCurrentService(service[0]); selectorStore.setCurrentService(service[0]);
fetchPods(dashboardStore.entity, true); fetchPods(dashboardStore.entity, selectorStore.currentService.id, true);
} else { } else {
selectorStore.setCurrentService(null); selectorStore.setCurrentService(null);
} }
@ -247,11 +282,11 @@ function clickIcons(t: { id: string; content: string; name: string }) {
} }
} }
async function fetchPods(type: string, setPod: boolean) { async function fetchPods(type: string, serviceId: string, setPod: boolean) {
let resp; let resp;
switch (type) { switch (type) {
case "Endpoint": case EntityType[2].value:
resp = await selectorStore.getEndpoints(); resp = await selectorStore.getEndpoints({ serviceId });
if (setPod) { if (setPod) {
selectorStore.setCurrentPod( selectorStore.setCurrentPod(
selectorStore.pods.length ? selectorStore.pods[0] : null selectorStore.pods.length ? selectorStore.pods[0] : null
@ -259,8 +294,8 @@ async function fetchPods(type: string, setPod: boolean) {
states.currentPod = selectorStore.currentPod.label; states.currentPod = selectorStore.currentPod.label;
} }
break; break;
case "ServiceInstance": case EntityType[3].value:
resp = await selectorStore.getServiceInstances(); resp = await selectorStore.getServiceInstances({ serviceId });
if (setPod) { if (setPod) {
selectorStore.setCurrentPod( selectorStore.setCurrentPod(
selectorStore.pods.length ? selectorStore.pods[0] : null selectorStore.pods.length ? selectorStore.pods[0] : null
@ -268,6 +303,27 @@ async function fetchPods(type: string, setPod: boolean) {
states.currentPod = selectorStore.currentPod.label; states.currentPod = selectorStore.currentPod.label;
} }
break; break;
case EntityType[6].value:
resp = await selectorStore.getEndpoints({ serviceId, isRelation: true });
if (setPod) {
selectorStore.setCurrentDestPod(
selectorStore.destPods.length ? selectorStore.destPods[0] : null
);
states.currentDestPod = selectorStore.currentDestPod.label;
}
break;
case EntityType[5].value:
resp = await selectorStore.getServiceInstances({
serviceId,
isRelation: true,
});
if (setPod) {
selectorStore.setCurrentDestPod(
selectorStore.destPods.length ? selectorStore.destPods[0] : null
);
states.currentDestPod = selectorStore.currentDestPod.label;
}
break;
default: default:
resp = {}; resp = {};
} }

View File

@ -200,6 +200,9 @@ function handleLinkClick(event: any, d: Call) {
event.stopPropagation(); event.stopPropagation();
topologyStore.setNode(null); topologyStore.setNode(null);
topologyStore.setLink(d); topologyStore.setLink(d);
if (settings.value.linkDashboard) {
return;
}
const e = const e =
dashboardStore.entity === EntityType[1].value dashboardStore.entity === EntityType[1].value
? EntityType[0].value ? EntityType[0].value

View File

@ -36,12 +36,24 @@ limitations under the License. -->
:style="`height:${height}px;width:${width}px;`" :style="`height:${height}px;width:${width}px;`"
v-loading="loading" v-loading="loading"
> >
<Sankey /> <Sankey @click="selectNodeLink" />
</div>
<div
class="operations-list"
v-if="topologyStore.node"
:style="{
top: operationsPos.y + 'px',
left: operationsPos.x + 'px',
}"
>
<span v-for="(item, index) of items" :key="index" @click="item.func">
{{ item.title }}
</span>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { ref, onMounted } from "vue"; import { ref, onMounted, reactive } from "vue";
import { Option } from "@/types/app"; import { Option } from "@/types/app";
import { useTopologyStore } from "@/store/modules/topology"; import { useTopologyStore } from "@/store/modules/topology";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
@ -50,6 +62,7 @@ import { EntityType } from "../../../data";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import Sankey from "./Sankey.vue"; import Sankey from "./Sankey.vue";
import Settings from "./Settings.vue"; import Settings from "./Settings.vue";
import router from "@/router";
const { t } = useI18n(); const { t } = useI18n();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
@ -60,10 +73,17 @@ const height = ref<number>(document.body.clientHeight - 150);
const width = ref<number>(document.body.clientWidth - 40); const width = ref<number>(document.body.clientWidth - 40);
const showSettings = ref<boolean>(false); const showSettings = ref<boolean>(false);
const depth = ref<string>("2"); const depth = ref<string>("2");
const showTool = ref<boolean>(false);
const depthList = [1, 2, 3, 4, 5].map((item: number) => ({ const depthList = [1, 2, 3, 4, 5].map((item: number) => ({
value: String(item), value: String(item),
label: String(item), label: String(item),
})); }));
const settings = ref<any>({});
const items = ref([
{ id: "inspect", title: "Inspect", func: inspect },
{ id: "alarm", title: "Alarm", func: goAlarm },
]);
const operationsPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
onMounted(async () => { onMounted(async () => {
loading.value = true; loading.value = true;
@ -74,17 +94,61 @@ onMounted(async () => {
} }
}); });
function inspect() {
console.log(settings.value);
}
function goAlarm() {
console.log(settings.value);
}
function goDashboard() {
console.log(settings.value);
}
function setConfig() { function setConfig() {
showSettings.value = !showSettings.value; showSettings.value = !showSettings.value;
} }
function updateConfig(config: any) { function updateConfig(config: any) {
console.log(config); items.value = [
{ id: "inspect", title: "Inspect", func: inspect },
{ id: "alarm", title: "Alarm", func: goAlarm },
];
settings.value = config;
if (config.nodeDashboard) {
items.value.push({
id: "dashboard",
title: "Dashboard",
func: goDashboard,
});
}
}
function selectNodeLink(d: any) {
if (d.dataType === "edge") {
topologyStore.setNode(null);
topologyStore.setLink(d.data);
if (!settings.value.linkDashboard) {
return;
}
console.log(d.data);
const { sourceObj, targetObj } = d.data;
const entity =
dashboardStore.entity === EntityType[2].value
? EntityType[6].value
: EntityType[5].value;
const path = `/dashboard/${dashboardStore.layerId}/${entity}/${sourceObj.serviceId}/${sourceObj.id}/${targetObj.serviceId}/${targetObj.id}/${settings.value.linkDashboard}`;
const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank");
} else {
topologyStore.setNode(d.data);
topologyStore.setLink(null);
showTool.value = true;
}
} }
async function changeDepth(opt: Option[]) { async function changeDepth(opt: Option[]) {
depth.value = opt[0].value; depth.value = opt[0].value;
console.log(depth.value);
loading.value = true; loading.value = true;
const resp = await getTopology(); const resp = await getTopology();
loading.value = false; loading.value = false;

View File

@ -21,6 +21,8 @@ import { computed } from "vue";
import { useTopologyStore } from "@/store/modules/topology"; import { useTopologyStore } from "@/store/modules/topology";
import { Node, Call } from "@/types/topology"; import { Node, Call } from "@/types/topology";
/*global defineEmits */
const emit = defineEmits(["click"]);
const topologyStore = useTopologyStore(); const topologyStore = useTopologyStore();
const option = computed(() => getOption()); const option = computed(() => getOption());
@ -115,7 +117,7 @@ function nodeTooltip(data: Node) {
} }
function clickChart(param: any) { function clickChart(param: any) {
console.log(param); emit("click", param);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>