feat: Implement Text control and update Topology (#37)

This commit is contained in:
Fine0830 2022-03-25 15:51:06 +08:00 committed by GitHub
parent 4380a874de
commit 99e23c33dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 454 additions and 74 deletions

View File

@ -125,6 +125,7 @@ const msg = {
kubernetesService: "Service", kubernetesService: "Service",
kubernetesCluster: "Cluster", kubernetesCluster: "Cluster",
kubernetes: "Kubernetes", kubernetes: "Kubernetes",
textUrl: "Text Hyperlink",
hourTip: "Select Hour", hourTip: "Select Hour",
minuteTip: "Select Minute", minuteTip: "Select Minute",
secondTip: "Select Second", secondTip: "Select Second",

View File

@ -125,6 +125,7 @@ const msg = {
kubernetesService: "服务", kubernetesService: "服务",
kubernetesCluster: "集群", kubernetesCluster: "集群",
kubernetes: "Kubernetes", kubernetes: "Kubernetes",
textUrl: "文本超链接",
hourTip: "选择小时", hourTip: "选择小时",
minuteTip: "选择分钟", minuteTip: "选择分钟",
secondTip: "选择秒数", secondTip: "选择秒数",

View File

@ -22,10 +22,17 @@ export const NewControl = {
i: "0", i: "0",
type: "Widget", type: "Widget",
widget: { widget: {
title: "Title", title: "",
}, },
graph: {}, graph: {},
standard: {}, standard: {},
metrics: [""], metrics: [""],
metricTypes: [""], metricTypes: [""],
}; };
export const TextConfig = {
fontColor: "white",
backgroundColor: "green",
content: "Text",
fontSize: 14,
textAlign: "left",
};

View File

@ -22,7 +22,7 @@ import query from "@/graphql/fetch";
import { DashboardItem } from "@/types/dashboard"; import { DashboardItem } from "@/types/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { NewControl } from "../data"; import { NewControl, TextConfig } from "../data";
import { Duration } from "@/types/app"; import { Duration } from "@/types/app";
import { AxiosResponse } from "axios"; import { AxiosResponse } from "axios";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
@ -112,6 +112,10 @@ export const dashboardStore = defineStore({
if (type === "Trace" || type === "Profile" || type === "Log") { if (type === "Trace" || type === "Profile" || type === "Log") {
newItem.h = 36; newItem.h = 36;
} }
if (type === "Text") {
newItem.h = 6;
newItem.graph = TextConfig;
}
this.activedGridItem = newItem.i; this.activedGridItem = newItem.i;
this.selectedGrid = newItem; this.selectedGrid = newItem;
this.layout = this.layout.map((d: LayoutConfig) => { this.layout = this.layout.map((d: LayoutConfig) => {
@ -158,6 +162,10 @@ export const dashboardStore = defineStore({
if (type === "Trace" || type === "Profile" || type === "Log") { if (type === "Trace" || type === "Profile" || type === "Log") {
newItem.h = 32; newItem.h = 32;
} }
if (type === "Text") {
newItem.h = 6;
newItem.graph = TextConfig;
}
if (this.layout[idx].children) { if (this.layout[idx].children) {
const items = children.map((d: LayoutConfig) => { const items = children.map((d: LayoutConfig) => {
d.y = d.y + newItem.h; d.y = d.y + newItem.h;
@ -171,10 +179,9 @@ export const dashboardStore = defineStore({
activeGridItem(index: string) { activeGridItem(index: string) {
this.activedGridItem = index; this.activedGridItem = index;
}, },
setActiveTabIndex(index: number) { setActiveTabIndex(index: number, target?: number) {
const idx = this.layout.findIndex( const m = target || this.activedGridItem;
(d: LayoutConfig) => d.i === this.activedGridItem const idx = this.layout.findIndex((d: LayoutConfig) => d.i === m);
);
if (idx < 0) { if (idx < 0) {
return; return;
} }

View File

@ -91,6 +91,14 @@ export interface CardConfig {
textAlign?: "center" | "right" | "left"; textAlign?: "center" | "right" | "left";
} }
export interface TextConfig {
fontSize: number;
backgroundColor: string;
textAlign: string;
fontColor: string;
content: string;
}
export interface TableConfig { export interface TableConfig {
type?: string; type?: string;
showTableValues: boolean; showTableValues: boolean;

View File

@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<Edit v-if="dashboardStore.currentDashboard" /> <Dashboard v-if="dashboardStore.currentDashboard" />
<div v-else class="no-root"> <div v-else class="no-root">
{{ t("noRoot") }} {{ dashboardStore.layerId }} {{ t("noRoot") }} {{ dashboardStore.layerId }}
</div> </div>
@ -24,7 +24,7 @@ import { ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { EntityType } from "./dashboard/data"; import { EntityType } from "./dashboard/data";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import Edit from "./dashboard/Edit.vue"; import Dashboard from "./dashboard/Edit.vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
@ -52,7 +52,6 @@ getDashboard();
async function getDashboard() { async function getDashboard() {
layer.value = routesMap[String(route.name)]; layer.value = routesMap[String(route.name)];
console.log(layer.value);
dashboardStore.setLayer(layer.value); dashboardStore.setLayer(layer.value);
dashboardStore.setEntity(EntityType[1].value); dashboardStore.setEntity(EntityType[1].value);
dashboardStore.setMode(false); dashboardStore.setMode(false);

View File

@ -28,63 +28,71 @@ limitations under the License. -->
:destroy-on-close="true" :destroy-on-close="true"
@closed="dashboardStore.setConfigPanel(false)" @closed="dashboardStore.setConfigPanel(false)"
> >
<TopologyConfig v-if="dashboardStore.selectedGrid.type === 'Topology'" /> <component :is="dashboardStore.selectedGrid.type" />
<WidgetConfig v-else />
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts">
import { ref } from "vue"; import { ref, defineComponent } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import GridLayout from "./panel/Layout.vue"; import GridLayout from "./panel/Layout.vue";
import Tool from "./panel/Tool.vue"; import Tool from "./panel/Tool.vue";
import TopologyConfig from "./configuration/Topology.vue";
import WidgetConfig from "./configuration/Widget.vue";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import Configuration from "./configuration";
const dashboardStore = useDashboardStore(); export default defineComponent({
const appStore = useAppStoreWithOut(); name: "Dashboard",
const { t } = useI18n(); components: { ...Configuration, GridLayout, Tool },
const p = useRoute().params; setup() {
const layoutKey = ref<string>(`${p.layerId}_${p.entity}_${p.name}`); const dashboardStore = useDashboardStore();
const appStore = useAppStoreWithOut();
const { t } = useI18n();
const p = useRoute().params;
const layoutKey = ref<string>(`${p.layerId}_${p.entity}_${p.name}`);
setTemplate();
async function setTemplate() {
await dashboardStore.setDashboards();
setTemplate(); if (!p.entity) {
async function setTemplate() { if (!dashboardStore.currentDashboard) {
await dashboardStore.setDashboards(); return;
}
if (!p.entity) { const { layer, entity, name } = dashboardStore.currentDashboard;
if (!dashboardStore.currentDashboard) { layoutKey.value = `${layer}_${entity}_${name}`;
return; }
const c: { configuration: string; id: string } = JSON.parse(
sessionStorage.getItem(layoutKey.value) || "{}"
);
const layout: any = c.configuration || {};
dashboardStore.setLayout(layout.children || []);
appStore.setPageTitle(layout.name);
if (p.entity) {
dashboardStore.setCurrentDashboard({
layer: p.layerId,
entity: p.entity,
name: p.name,
id: c.id,
isRoot: layout.isRoot,
});
}
}
function handleClick(e: any) {
e.stopPropagation();
if (e.target.className === "ds-main") {
dashboardStore.activeGridItem("");
dashboardStore.selectWidget(null);
}
} }
const { layer, entity, name } = dashboardStore.currentDashboard;
layoutKey.value = `${layer}_${entity}_${name}`;
}
const c: { configuration: string; id: string } = JSON.parse(
sessionStorage.getItem(layoutKey.value) || "{}"
);
const layout: any = c.configuration || {};
dashboardStore.setLayout(layout.children || []);
appStore.setPageTitle(layout.name);
if (p.entity) {
dashboardStore.setCurrentDashboard({
layer: p.layerId,
entity: p.entity,
name: p.name,
id: c.id,
isRoot: layout.isRoot,
});
}
}
function handleClick(e: any) { return {
e.stopPropagation(); t,
if (e.target.className === "ds-main") { handleClick,
dashboardStore.activeGridItem(""); dashboardStore,
dashboardStore.selectWidget(null); };
} },
} });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.ds-main { .ds-main {

View File

@ -0,0 +1,149 @@
<!-- 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("textUrl") }}</span>
<el-input
class="input"
v-model="url"
size="small"
@change="changeConfig({ url })"
/>
</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("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="footer">
<el-button size="small" @click="cancelConfig">
{{ t("cancel") }}
</el-button>
<el-button size="small" type="primary" @click="applyConfig">
{{ t("apply") }}
</el-button>
</div>
</template>
<script lang="ts" setup>
import { useI18n } from "vue-i18n";
import { ref } from "vue";
import { useDashboardStore } from "@/store/modules/dashboard";
const { t } = useI18n();
const dashboardStore = useDashboardStore();
const originConfig = dashboardStore.selectedGrid;
const url = ref(originConfig.graph.url || "");
const backgroundColor = ref(originConfig.graph.backgroundColor || "green");
const fontColor = ref(originConfig.graph.fontColor || "white");
const content = ref<string>(originConfig.graph.content || "");
const fontSize = ref<number>(originConfig.graph.fontSize || 12);
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 applyConfig() {
dashboardStore.setConfigPanel(false);
dashboardStore.setConfigs(dashboardStore.selectedGrid);
}
function cancelConfig() {
dashboardStore.selectWidget(originConfig);
dashboardStore.setConfigPanel(false);
}
</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;
}
.footer {
position: fixed;
bottom: 0;
right: 0;
border-top: 1px solid #eee;
padding: 10px;
text-align: right;
width: 100%;
background-color: #fff;
}
</style>

View File

@ -90,7 +90,6 @@ import configs from "./widget/graph-styles";
import WidgetOptions from "./widget/WidgetOptions.vue"; import WidgetOptions from "./widget/WidgetOptions.vue";
import StandardOptions from "./widget/StandardOptions.vue"; import StandardOptions from "./widget/StandardOptions.vue";
import MetricOptions from "./widget/MetricOptions.vue"; import MetricOptions from "./widget/MetricOptions.vue";
import { ListChartTypes } from "../data";
export default defineComponent({ export default defineComponent({
name: "ConfigEdit", name: "ConfigEdit",

View File

@ -0,0 +1,26 @@
/**
* 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.
*/
import Text from "./Text.vue";
import Widget from "./Widget.vue";
import Topology from "./Topology.vue";
export default {
Text,
Widget,
Topology,
};

View File

@ -121,6 +121,7 @@ import Widget from "./Widget.vue";
import Trace from "./Trace.vue"; import Trace from "./Trace.vue";
import Profile from "./Profile.vue"; import Profile from "./Profile.vue";
import Log from "./Log.vue"; import Log from "./Log.vue";
import Text from "./Text.vue";
const props = { const props = {
data: { data: {
@ -131,7 +132,7 @@ const props = {
}; };
export default defineComponent({ export default defineComponent({
name: "Tab", name: "Tab",
components: { Topology, Widget, Trace, Profile, Log }, components: { Topology, Widget, Trace, Profile, Log, Text },
props, props,
setup(props) { setup(props) {
const { t } = useI18n(); const { t } = useI18n();
@ -149,6 +150,7 @@ export default defineComponent({
dashboardStore.setCurrentTabItems( dashboardStore.setCurrentTabItems(
dashboardStore.layout[l].children[activeTabIndex.value].children dashboardStore.layout[l].children[activeTabIndex.value].children
); );
dashboardStore.setActiveTabIndex(activeTabIndex.value, props.data.i);
} }
function clickTabs(e: Event, idx: number) { function clickTabs(e: Event, idx: number) {

View File

@ -0,0 +1,129 @@
<!-- 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="topology">
<div class="header">
<el-popover
placement="bottom"
trigger="click"
:width="100"
v-if="dashboardStore.editMode"
>
<template #reference>
<span>
<Icon iconName="ellipsis_v" size="middle" class="operation" />
</span>
</template>
<div class="tools" @click="editConfig">
<span>{{ t("edit") }}</span>
</div>
<div class="tools" @click="removeTopo">
<span>{{ t("delete") }}</span>
</div>
</el-popover>
</div>
<div
class="body"
:style="{ backgroundColor: TextColors[data.graph.backgroundColor] }"
>
<div
:style="{
color: TextColors[data.graph.fontColor],
fontSize: data.graph.fontSize + 'px',
}"
>
<a :href="data.graph.url" target="_blank">
{{ data.graph.content }}
</a>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from "vue";
import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard";
import { TextColors } from "@/views/dashboard/data";
/*global defineProps */
const props = defineProps({
data: {
type: Object as PropType<any>,
default: () => ({ graph: {} }),
},
activeIndex: { type: String, default: "" },
});
const { t } = useI18n();
const dashboardStore = useDashboardStore();
function removeTopo() {
dashboardStore.removeControls(props.data);
}
function editConfig() {
dashboardStore.setConfigPanel(true);
dashboardStore.selectWidget(props.data);
}
function viewText() {
const path = props.data.graph.url;
console.log(path);
if (!path) {
return;
}
window.open(path, "_blank");
}
</script>
<style lang="scss" scoped>
.topology {
font-size: 12px;
height: 100%;
position: relative;
}
.operation {
cursor: pointer;
}
.header {
position: absolute;
top: 10px;
right: 10px;
}
.body {
text-align: center;
width: 100%;
height: 100%;
cursor: pointer;
box-sizing: border-box;
color: #333;
display: -webkit-box;
-webkit-box-orient: horizontal;
-webkit-box-pack: center;
-webkit-box-align: center;
}
.tools {
padding: 5px 0;
color: #999;
cursor: pointer;
position: relative;
text-align: center;
&:hover {
color: #409eff;
background-color: #eee;
}
}
</style>

View File

@ -20,5 +20,6 @@ import Widget from "./Widget.vue";
import Trace from "./Trace.vue"; import Trace from "./Trace.vue";
import Profile from "./Profile.vue"; import Profile from "./Profile.vue";
import Log from "./Log.vue"; import Log from "./Log.vue";
import Text from "./Text.vue";
export default { Tab, Widget, Trace, Topology, Profile, Log }; export default { Tab, Widget, Trace, Topology, Profile, Log, Text };

View File

@ -23,10 +23,10 @@ export const ChartTypes = [
{ label: "Bar", value: "Bar" }, { label: "Bar", value: "Bar" },
{ label: "Line", value: "Line" }, { label: "Line", value: "Line" },
{ label: "Area", value: "Area" }, { label: "Area", value: "Area" },
// { label: "Pie", value: "Pie" },
{ label: "Card", value: "Card" }, { label: "Card", value: "Card" },
{ label: "Top List", value: "TopList" }, { label: "Top List", value: "TopList" },
{ label: "Table", value: "Table" }, { label: "Table", value: "Table" },
{ label: "Text", value: "Text" },
{ label: "Heatmap", value: "Heatmap" }, { label: "Heatmap", value: "Heatmap" },
{ label: "Service List", value: "ServiceList" }, { label: "Service List", value: "ServiceList" },
{ label: "Endpoint List", value: "EndpointList" }, { label: "Endpoint List", value: "EndpointList" },
@ -169,6 +169,7 @@ export const SortOrder = [
export const AllTools = [ export const AllTools = [
{ 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: "library_books", content: "Add Text", id: "addText" },
{ name: "device_hub", content: "Add Topology", id: "addTopology" }, { name: "device_hub", content: "Add Topology", id: "addTopology" },
{ name: "merge", content: "Add Trace", id: "addTrace" }, { name: "merge", content: "Add Trace", id: "addTrace" },
{ name: "assignment", content: "Add Log", id: "addLog" }, { name: "assignment", content: "Add Log", id: "addLog" },
@ -177,6 +178,7 @@ export const AllTools = [
export const ServiceTools = [ export const ServiceTools = [
{ 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: "library_books", content: "Add Text", id: "addText" },
{ name: "device_hub", content: "Add Topology", id: "addTopology" }, { name: "device_hub", content: "Add Topology", id: "addTopology" },
{ name: "merge", content: "Add Trace", id: "addTrace" }, { name: "merge", content: "Add Trace", id: "addTrace" },
{ name: "timeline", content: "Add Profile", id: "addProfile" }, { name: "timeline", content: "Add Profile", id: "addProfile" },
@ -186,6 +188,7 @@ export const ServiceTools = [
export const InstanceTools = [ export const InstanceTools = [
{ 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: "library_books", content: "Add Text", id: "addText" },
{ name: "merge", content: "Add Trace", id: "addTrace" }, { name: "merge", content: "Add Trace", id: "addTrace" },
{ name: "assignment", content: "Add Log", id: "addLog" }, { name: "assignment", content: "Add Log", id: "addLog" },
{ name: "save", content: "Apply", id: "apply" }, { name: "save", content: "Apply", id: "apply" },
@ -193,6 +196,7 @@ export const InstanceTools = [
export const EndpointTools = [ export const EndpointTools = [
{ 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: "library_books", content: "Add Text", id: "addText" },
{ name: "device_hub", content: "Add Topology", id: "addTopology" }, { name: "device_hub", content: "Add Topology", id: "addTopology" },
{ name: "merge", content: "Add Trace", id: "addTrace" }, { name: "merge", content: "Add Trace", id: "addTrace" },
{ name: "assignment", content: "Add Log", id: "addLog" }, { name: "assignment", content: "Add Log", id: "addLog" },
@ -201,6 +205,7 @@ export const EndpointTools = [
export const ServiceRelationTools = [ export const ServiceRelationTools = [
{ 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: "library_books", content: "Add Text", id: "addText" },
{ name: "device_hub", content: "Add Topology", id: "addTopology" }, { name: "device_hub", content: "Add Topology", id: "addTopology" },
{ name: "save", content: "Apply", id: "apply" }, { name: "save", content: "Apply", id: "apply" },
]; ];
@ -208,11 +213,13 @@ export const ServiceRelationTools = [
export const EndpointRelationTools = [ export const EndpointRelationTools = [
{ 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: "library_books", content: "Add Text", id: "addText" },
{ name: "save", content: "Apply", id: "apply" }, { name: "save", content: "Apply", id: "apply" },
]; ];
export const InstanceRelationTools = [ export const InstanceRelationTools = [
{ 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: "library_books", content: "Add Text", id: "addText" },
{ name: "device_hub", content: "Add Topology", id: "addTopology" }, { name: "device_hub", content: "Add Topology", id: "addTopology" },
{ name: "save", content: "Apply", id: "apply" }, { name: "save", content: "Apply", id: "apply" },
]; ];
@ -248,3 +255,12 @@ export const QueryOrders = [
{ label: "Start Time", value: "BY_START_TIME" }, { label: "Start Time", value: "BY_START_TIME" },
{ label: "Duration", value: "BY_DURATION" }, { label: "Duration", value: "BY_DURATION" },
]; ];
export const TextColors: { [key: string]: string } = {
green: "#67C23A",
blue: "#409EFF",
red: "#F56C6C",
grey: "#909399",
white: "#fff",
black: "#000",
orange: "#E6A23C",
};

View File

@ -59,6 +59,9 @@ export default defineComponent({
function clickGrid(item: LayoutConfig) { function clickGrid(item: LayoutConfig) {
dashboardStore.activeGridItem(item.i); dashboardStore.activeGridItem(item.i);
dashboardStore.selectWidget(item); dashboardStore.selectWidget(item);
if (item.type === "Tab") {
dashboardStore.setActiveTabIndex(0);
}
} }
onBeforeUnmount(() => { onBeforeUnmount(() => {
dashboardStore.setLayout([]); dashboardStore.setLayout([]);

View File

@ -367,6 +367,9 @@ function setTabControls(id: string) {
case "addTopology": case "addTopology":
dashboardStore.addTabControls("Topology"); dashboardStore.addTabControls("Topology");
break; break;
case "addText":
dashboardStore.addTabControls("Text");
break;
default: default:
ElMessage.info("Don't support this control"); ElMessage.info("Don't support this control");
break; break;
@ -393,6 +396,9 @@ function setControls(id: string) {
case "addTopology": case "addTopology":
dashboardStore.addControl("Topology"); dashboardStore.addControl("Topology");
break; break;
case "addText":
dashboardStore.addControl("Text");
break;
default: default:
dashboardStore.addControl("Widget"); dashboardStore.addControl("Widget");
} }

View File

@ -30,7 +30,6 @@ limitations under the License. -->
class="inputs" class="inputs"
:value="depth" :value="depth"
:options="DepthList" :options="DepthList"
placeholder="Select a option"
@change="changeDepth" @change="changeDepth"
/> />
</span> </span>
@ -377,10 +376,12 @@ async function handleInspect() {
topologyStore.setNode(null); topologyStore.setNode(null);
topologyStore.setLink(null); topologyStore.setLink(null);
loading.value = true; loading.value = true;
const resp = await topologyStore.getServicesTopology([id]); const resp = await topologyStore.getDepthServiceTopology(
[id],
Number(depth.value)
);
loading.value = false; loading.value = false;
if (resp && resp.errors) {
if (resp.errors) {
ElMessage.error(resp.errors); ElMessage.error(resp.errors);
} }
await init(); await init();
@ -555,17 +556,18 @@ watch(
.operations-list { .operations-list {
position: absolute; position: absolute;
padding: 10px;
color: #333; color: #333;
cursor: pointer; cursor: pointer;
background-color: #fff; background-color: #fff;
border-radius: 3px; border-radius: 3px;
padding: 10px 0;
span { span {
display: block; display: block;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
text-align: center; text-align: left;
padding: 0 15px;
} }
span:hover { span:hover {

View File

@ -324,7 +324,7 @@ watch(
.operations-list { .operations-list {
position: absolute; position: absolute;
padding: 10px; padding: 10px 0;
color: #333; color: #333;
cursor: pointer; cursor: pointer;
background-color: #fff; background-color: #fff;
@ -335,7 +335,8 @@ watch(
height: 30px; height: 30px;
width: 140px; width: 140px;
line-height: 30px; line-height: 30px;
text-align: center; text-align: left;
padding: 0 15px;
} }
span:hover { span:hover {

View File

@ -23,6 +23,7 @@ limitations under the License. -->
placeholder="Please input a dashboard name for calls" placeholder="Please input a dashboard name for calls"
@change="changeLinkDashboard" @change="changeLinkDashboard"
class="inputs" class="inputs"
:clearable="true"
/> />
<div class="label">{{ t("linkServerMetrics") }}</div> <div class="label">{{ t("linkServerMetrics") }}</div>
<Selector <Selector
@ -86,7 +87,6 @@ limitations under the License. -->
<span> <span>
<Icon <Icon
class="cp mr-5" class="cp mr-5"
v-show="items.length > 1"
iconName="remove_circle_outline" iconName="remove_circle_outline"
size="middle" size="middle"
@click="deleteItem(index)" @click="deleteItem(index)"
@ -144,7 +144,6 @@ limitations under the License. -->
iconName="remove_circle_outline" iconName="remove_circle_outline"
size="middle" size="middle"
@click="deleteMetric(index)" @click="deleteMetric(index)"
v-show="legend.metric.length > 1"
/> />
<Icon <Icon
class="cp" class="cp"
@ -196,6 +195,10 @@ const { t } = useI18n();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const topologyStore = useTopologyStore(); const topologyStore = useTopologyStore();
const { selectedGrid } = dashboardStore; const { selectedGrid } = dashboardStore;
const nodeDashboard =
selectedGrid.nodeDashboard && selectedGrid.nodeDashboard.length
? selectedGrid.nodeDashboard
: "";
const isService = [EntityType[0].value, EntityType[1].value].includes( const isService = [EntityType[0].value, EntityType[1].value].includes(
dashboardStore.entity dashboardStore.entity
); );
@ -204,7 +207,7 @@ const items = reactive<
scope: string; scope: string;
dashboard: string; dashboard: string;
}[] }[]
>((isService && selectedGrid.nodeDashboard) || [{ scope: "", dashboard: "" }]); >(isService && nodeDashboard ? nodeDashboard : [{ scope: "", dashboard: "" }]);
const states = reactive<{ const states = reactive<{
linkDashboard: string; linkDashboard: string;
nodeDashboard: { nodeDashboard: {
@ -229,9 +232,12 @@ const states = reactive<{
linkDashboards: [], linkDashboards: [],
nodeDashboards: [], nodeDashboards: [],
}); });
const l = selectedGrid.legend && selectedGrid.legend.length;
const legend = reactive<{ const legend = reactive<{
metric: { name: string; condition: string; value: string }[]; metric: { name: string; condition: string; value: string }[];
}>({ metric: selectedGrid.legend || [{ name: "", condition: "", value: "" }] }); }>({
metric: l ? selectedGrid.legend : [{ name: "", condition: "", value: "" }],
});
getMetricList(); getMetricList();
async function getMetricList() { async function getMetricList() {
@ -335,6 +341,9 @@ function addItem() {
items.push({ scope: "", dashboard: "" }); items.push({ scope: "", dashboard: "" });
} }
function deleteItem(index: number) { function deleteItem(index: number) {
if (items.length === 1) {
items.push({ scope: "", dashboard: "" });
}
items.splice(index, 1); items.splice(index, 1);
updateSettings(); updateSettings();
} }
@ -384,6 +393,10 @@ async function changeNodeMetrics(options: Option[] | any) {
topologyStore.queryNodeMetrics(states.nodeMetrics); topologyStore.queryNodeMetrics(states.nodeMetrics);
} }
function deleteMetric(index: number) { function deleteMetric(index: number) {
if (legend.metric.length === 1) {
legend.metric = [{ name: "", condition: "", value: "" }];
return;
}
legend.metric.splice(index, 1); legend.metric.splice(index, 1);
} }
function addMetric() { function addMetric() {

View File

@ -40,14 +40,15 @@ export default class ListGraph {
constructor(el: HTMLDivElement, handleSelectSpan: (i: Trace) => void) { constructor(el: HTMLDivElement, handleSelectSpan: (i: Trace) => void) {
this.handleSelectSpan = handleSelectSpan; this.handleSelectSpan = handleSelectSpan;
this.el = el; this.el = el;
this.width = el.clientWidth - 20; this.width = el.clientWidth - 10;
this.height = el.clientHeight; this.height = el.clientHeight;
this.svg = d3 this.svg = d3
.select(this.el) .select(this.el)
.append("svg") .append("svg")
.attr("class", "trace-list-dowanload") .attr("class", "trace-list-dowanload")
.attr("width", this.width) .attr("width", this.width)
.attr("height", this.height); .attr("height", this.height)
.attr("transform", `translate(-5, 0)`);
this.tip = (d3tip as any)() this.tip = (d3tip as any)()
.attr("class", "d3-tip") .attr("class", "d3-tip")
.offset([-8, 0]) .offset([-8, 0])
@ -220,7 +221,7 @@ export default class ListGraph {
nodeEnter nodeEnter
.transition() .transition()
.duration(400) .duration(400)
.attr("transform", (d: any) => `translate(${d.y},${d.x})`) .attr("transform", (d: any) => `translate(${d.y + 5},${d.x})`)
.style("opacity", 1); .style("opacity", 1);
nodeEnter nodeEnter
.append("circle") .append("circle")
@ -243,7 +244,7 @@ export default class ListGraph {
node node
.transition() .transition()
.duration(400) .duration(400)
.attr("transform", (d: any) => `translate(${d.y},${d.x})`) .attr("transform", (d: any) => `translate(${d.y + 5},${d.x})`)
.style("opacity", 1) .style("opacity", 1)
.select("circle") .select("circle")
.attr("fill", (d: any) => .attr("fill", (d: any) =>
@ -273,8 +274,9 @@ export default class ListGraph {
.attr("fill", "rgba(0,0,0,0)") .attr("fill", "rgba(0,0,0,0)")
.attr("stroke", "rgba(0, 0, 0, 0.1)") .attr("stroke", "rgba(0, 0, 0, 0.1)")
.attr("stroke-width", 2) .attr("stroke-width", 2)
.attr("transform", `translate(5, 0)`)
.attr("d", () => { .attr("d", () => {
const o = { x: source.x0 + 35, y: source.y0 }; const o = { x: source.x0 + 40, y: source.y0 };
return this.diagonal({ source: o, target: o }); return this.diagonal({ source: o, target: o });
}) })
.transition() .transition()