feat: add switch to control dashboard mode (#31)

This commit is contained in:
Fine0830 2022-03-21 19:34:08 +08:00 committed by GitHub
parent 61f82c54df
commit f1e405fbb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 250 additions and 82 deletions

View File

@ -37,7 +37,7 @@ defineProps({
loading: { type: Boolean, default: false }, loading: { type: Boolean, default: false },
}); });
</script> </script>
<style lang="scss" scope> <style lang="scss" scoped>
.icon { .icon {
width: 16px; width: 16px;
height: 16px; height: 16px;

View File

@ -0,0 +1,32 @@
/**
* 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.
*/
export default function getDashboard(param: {
name: string;
layer: string;
entity: string;
}) {
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
const dashboard = list.find(
(d: { name: string; layer: string; entity: string }) =>
d.name === param.name &&
d.entity === param.entity &&
d.layer === param.layer
);
return dashboard;
}

View File

@ -24,10 +24,11 @@ limitations under the License. -->
<script lang="ts" setup> <script lang="ts" setup>
import { AppMain, SideBar, NavBar } from "./components"; import { AppMain, SideBar, NavBar } from "./components";
</script> </script>
<style lang="scss" scope> <style lang="scss" scoped>
.app-wrapper { .app-wrapper {
height: 100%; height: 100%;
} }
.main-container { .main-container {
flex-grow: 2; flex-grow: 2;
height: 100%; height: 100%;

View File

@ -129,7 +129,7 @@ const filterMenus = (menus: any[]) => {
}; };
</script> </script>
<style lang="scss" scope> <style lang="scss" scoped>
.side-bar { .side-bar {
position: relative; position: relative;
height: 100%; height: 100%;

View File

@ -115,10 +115,12 @@ const msg = {
rename: "Rename", rename: "Rename",
selfObservability: "Self Observability", selfObservability: "Self Observability",
satellite: "Satellite", satellite: "Satellite",
skyWalkingServer: "Sky Walking Server", skyWalkingServer: "SkyWalking Server",
functions: "Functions", functions: "Functions",
browser: "Browser", browser: "Browser",
linux: "Linux", linux: "Linux",
editWarning: "You are entering edit mode",
viewWarning: "You are entering view mode",
hourTip: "Select Hour", hourTip: "Select Hour",
minuteTip: "Select Minute", minuteTip: "Select Minute",
secondTip: "Select Second", secondTip: "Select Second",

View File

@ -119,6 +119,8 @@ const msg = {
functions: "Functions", functions: "Functions",
linux: "Linux", linux: "Linux",
browser: "浏览器", browser: "浏览器",
editWarning: "你正在进入编辑模式",
viewWarning: "你正在进入预览模式",
hourTip: "选择小时", hourTip: "选择小时",
minuteTip: "选择分钟", minuteTip: "选择分钟",
secondTip: "选择秒数", secondTip: "选择秒数",

View File

@ -41,6 +41,7 @@ interface DashboardState {
currentTabItems: LayoutConfig[]; currentTabItems: LayoutConfig[];
dashboards: DashboardItem[]; dashboards: DashboardItem[];
currentDashboard: Nullable<DashboardItem>; currentDashboard: Nullable<DashboardItem>;
editMode: boolean;
} }
export const dashboardStore = defineStore({ export const dashboardStore = defineStore({
@ -58,11 +59,15 @@ export const dashboardStore = defineStore({
currentTabItems: [], currentTabItems: [],
dashboards: [], dashboards: [],
currentDashboard: null, currentDashboard: null,
editMode: false,
}), }),
actions: { actions: {
setLayout(data: LayoutConfig[]) { setLayout(data: LayoutConfig[]) {
this.layout = data; this.layout = data;
}, },
setMode(mode: boolean) {
this.editMode = mode;
},
resetDashboards(list: DashboardItem[]) { resetDashboards(list: DashboardItem[]) {
this.dashboards = list; this.dashboards = list;
sessionStorage.setItem("dashboards", JSON.stringify(list)); sessionStorage.setItem("dashboards", JSON.stringify(list));

View File

@ -23,11 +23,13 @@ import { useRoute } from "vue-router";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { EntityType } from "./dashboard/data"; import { EntityType } from "./dashboard/data";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app";
import Edit from "./dashboard/Edit.vue"; import Edit from "./dashboard/Edit.vue";
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const appStore = useAppStoreWithOut();
const routeNames = [ const routeNames = [
"GeneralServices", "GeneralServices",
"Database", "Database",
@ -44,8 +46,11 @@ const layer = ref<string>("GENERAL");
getDashboard(); getDashboard();
async function getDashboard() { async function getDashboard() {
dashboardStore.setCurrentDashboard(null);
setLayer(String(route.name)); setLayer(String(route.name));
dashboardStore.setLayer(layer.value);
dashboardStore.setEntity(EntityType[0].value);
dashboardStore.setMode(false);
dashboardStore.setCurrentDashboard(null);
await dashboardStore.setDashboards(); await dashboardStore.setDashboards();
const index = dashboardStore.dashboards.findIndex( const index = dashboardStore.dashboards.findIndex(
(d: { name: string; isRoot: boolean; layer: string; entity: string }) => (d: { name: string; isRoot: boolean; layer: string; entity: string }) =>
@ -56,6 +61,7 @@ async function getDashboard() {
} }
const d = dashboardStore.dashboards[index]; const d = dashboardStore.dashboards[index];
dashboardStore.setCurrentDashboard(d); dashboardStore.setCurrentDashboard(d);
appStore.setPageTitle(d.name);
} }
function setLayer(n: string) { function setLayer(n: string) {
switch (n) { switch (n) {
@ -93,9 +99,6 @@ function setLayer(n: string) {
layer.value = "GENERAL"; layer.value = "GENERAL";
break; break;
} }
dashboardStore.setLayer(layer.value);
dashboardStore.setEntity(EntityType[1].value);
// appStore.setPageTitle(layer.value);
} }
watch( watch(
() => route.name, () => route.name,

View File

@ -13,11 +13,11 @@ 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>
<Tool v-if="p.entity" /> <Tool />
<div <div
class="ds-main" class="ds-main"
@click="handleClick" @click="handleClick"
:style="{ height: p.entity ? 'calc(100% - 45px)' : '100%' }" :style="{ height: dashboardStore.editMode ? 'calc(100% - 45px)' : '100%' }"
> >
<grid-layout /> <grid-layout />
<el-dialog <el-dialog

View File

@ -44,7 +44,11 @@ limitations under the License. -->
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column prop="name" label="Name" /> <el-table-column prop="name" label="Name">
<template #default="scope">
<span @click="handleView(scope.row)">{{ scope.row.name }}</span>
</template>
</el-table-column>
<el-table-column prop="layer" label="Layer" width="200" /> <el-table-column prop="layer" label="Layer" width="200" />
<el-table-column prop="entity" label="Entity" width="200" /> <el-table-column prop="entity" label="Entity" width="200" />
<el-table-column prop="isRoot" label="Root" width="100"> <el-table-column prop="isRoot" label="Root" width="100">
@ -56,10 +60,10 @@ limitations under the License. -->
</el-table-column> </el-table-column>
<el-table-column label="Operations"> <el-table-column label="Operations">
<template #default="scope"> <template #default="scope">
<el-button size="small" @click="handleView(scope.row)"> <el-button size="small" @click="handleEdit(scope.row)">
{{ t("edit") }} {{ t("edit") }}
</el-button> </el-button>
<el-button size="small" @click="handleEdit(scope.row)"> <el-button size="small" @click="handleRename(scope.row)">
{{ t("rename") }} {{ t("rename") }}
</el-button> </el-button>
<el-popconfirm <el-popconfirm
@ -196,7 +200,20 @@ function exportTemplates() {
multipleTableRef.value!.clearSelection(); multipleTableRef.value!.clearSelection();
}, 2000); }, 2000);
} }
function handleEdit(row: DashboardItem) {
dashboardStore.setMode(true);
dashboardStore.setEntity(row.entity);
dashboardStore.setLayer(row.layer);
dashboardStore.setCurrentDashboard(row);
router.push(
`/dashboard/${row.layer}/${row.entity}/${row.name.split(" ").join("-")}`
);
}
function handleView(row: DashboardItem) { function handleView(row: DashboardItem) {
dashboardStore.setMode(false);
dashboardStore.setEntity(row.entity);
dashboardStore.setLayer(row.layer);
dashboardStore.setCurrentDashboard(row); dashboardStore.setCurrentDashboard(row);
router.push( router.push(
`/dashboard/${row.layer}/${row.entity}/${row.name.split(" ").join("-")}` `/dashboard/${row.layer}/${row.entity}/${row.name.split(" ").join("-")}`
@ -267,7 +284,7 @@ async function setRoot(row: DashboardItem) {
searchDashboards(); searchDashboards();
loading.value = false; loading.value = false;
} }
function handleEdit(row: DashboardItem) { function handleRename(row: DashboardItem) {
ElMessageBox.prompt("Please input dashboard name", "Edit", { ElMessageBox.prompt("Please input dashboard name", "Edit", {
confirmButtonText: "OK", confirmButtonText: "OK",
cancelButtonText: "Cancel", cancelButtonText: "Cancel",

View File

@ -18,7 +18,7 @@ limitations under the License. -->
placement="bottom" placement="bottom"
trigger="click" trigger="click"
:width="100" :width="100"
v-if="routeParams.entity" v-if="dashboardStore.editMode"
> >
<template #reference> <template #reference>
<span class="delete cp"> <span class="delete cp">
@ -39,7 +39,6 @@ limitations under the License. -->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import Header from "../related/log/Header.vue"; import Header from "../related/log/Header.vue";
import List from "../related/log/List.vue"; import List from "../related/log/List.vue";
@ -53,7 +52,6 @@ const props = defineProps({
activeIndex: { type: String, default: "" }, activeIndex: { type: String, default: "" },
}); });
const { t } = useI18n(); const { t } = useI18n();
const routeParams = useRoute().params;
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
function removeWidget() { function removeWidget() {

View File

@ -18,7 +18,7 @@ limitations under the License. -->
placement="bottom" placement="bottom"
trigger="click" trigger="click"
:width="100" :width="100"
v-if="routeParams.entity" v-if="dashboardStore.editMode"
> >
<template #reference> <template #reference>
<span class="delete cp"> <span class="delete cp">
@ -39,7 +39,6 @@ import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import Header from "../related/profile/Header.vue"; import Header from "../related/profile/Header.vue";
import Content from "../related/profile/Content.vue"; import Content from "../related/profile/Content.vue";
import { useRoute } from "vue-router";
/*global defineProps */ /*global defineProps */
const props = defineProps({ const props = defineProps({
@ -50,8 +49,8 @@ const props = defineProps({
activeIndex: { type: String, default: "" }, activeIndex: { type: String, default: "" },
}); });
const { t } = useI18n(); const { t } = useI18n();
const routeParams = useRoute().params;
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
function removeWidget() { function removeWidget() {
dashboardStore.removeControls(props.data); dashboardStore.removeControls(props.data);
} }

View File

@ -34,10 +34,10 @@ limitations under the License. -->
size="sm" size="sm"
iconName="cancel" iconName="cancel"
@click="deleteTabItem($event, idx)" @click="deleteTabItem($event, idx)"
v-if="routeParams.entity" v-if="dashboardStore.editMode"
/> />
</span> </span>
<span class="tab-icons" v-if="routeParams.entity"> <span class="tab-icons" v-if="dashboardStore.editMode">
<el-tooltip content="Add tab items" placement="bottom"> <el-tooltip content="Add tab items" placement="bottom">
<i @click="addTabItem"> <i @click="addTabItem">
<Icon size="middle" iconName="add" /> <Icon size="middle" iconName="add" />
@ -45,7 +45,7 @@ limitations under the License. -->
</el-tooltip> </el-tooltip>
</span> </span>
</div> </div>
<div class="operations" v-if="routeParams.entity"> <div class="operations" v-if="dashboardStore.editMode">
<el-popover <el-popover
placement="bottom" placement="bottom"
trigger="click" trigger="click"
@ -113,7 +113,6 @@ limitations under the License. -->
<script lang="ts"> <script lang="ts">
import { ref, watch, defineComponent, toRefs } from "vue"; import { ref, watch, defineComponent, toRefs } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router";
import type { PropType } from "vue"; import type { PropType } from "vue";
import { LayoutConfig } from "@/types/dashboard"; import { LayoutConfig } from "@/types/dashboard";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
@ -136,7 +135,6 @@ export default defineComponent({
props, props,
setup(props) { setup(props) {
const { t } = useI18n(); const { t } = useI18n();
const routeParams = useRoute().params;
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const activeTabIndex = ref<number>(0); const activeTabIndex = ref<number>(0);
const activeTabWidget = ref<string>(""); const activeTabWidget = ref<string>("");
@ -247,7 +245,6 @@ export default defineComponent({
needQuery, needQuery,
canEditTabName, canEditTabName,
showTools, showTools,
routeParams,
t, t,
}; };
}, },

View File

@ -19,7 +19,7 @@ limitations under the License. -->
placement="bottom" placement="bottom"
trigger="click" trigger="click"
:width="100" :width="100"
v-if="routeParams.entity" v-if="dashboardStore.editMode"
> >
<template #reference> <template #reference>
<span> <span>
@ -39,7 +39,6 @@ limitations under the License. -->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import type { PropType } from "vue"; import type { PropType } from "vue";
import { useRoute } from "vue-router";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import Topology from "../related/topology/Index.vue"; import Topology from "../related/topology/Index.vue";
@ -53,7 +52,6 @@ const props = defineProps({
activeIndex: { type: String, default: "" }, activeIndex: { type: String, default: "" },
}); });
const { t } = useI18n(); const { t } = useI18n();
const routeParams = useRoute().params;
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
function removeTopo() { function removeTopo() {

View File

@ -14,13 +14,18 @@ See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<div class="trace-wrapper flex-v"> <div class="trace-wrapper flex-v">
<el-popover placement="bottom" trigger="click" :width="100"> <el-popover
placement="bottom"
trigger="click"
:width="100"
v-if="dashboardStore.editMode"
>
<template #reference> <template #reference>
<span class="delete cp"> <span class="delete cp">
<Icon iconName="ellipsis_v" size="middle" class="operation" /> <Icon iconName="ellipsis_v" size="middle" class="operation" />
</span> </span>
</template> </template>
<div class="tools" @click="removeWidget" v-if="routeParams.entity"> <div class="tools" @click="removeWidget">
<span>{{ t("delete") }}</span> <span>{{ t("delete") }}</span>
</div> </div>
</el-popover> </el-popover>
@ -35,7 +40,6 @@ limitations under the License. -->
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import type { PropType } from "vue"; import type { PropType } from "vue";
import { useRoute } from "vue-router";
import Filter from "../related/trace/Filter.vue"; import Filter from "../related/trace/Filter.vue";
import TraceList from "../related/trace/TraceList.vue"; import TraceList from "../related/trace/TraceList.vue";
import TraceDetail from "../related/trace/Detail.vue"; import TraceDetail from "../related/trace/Detail.vue";
@ -51,7 +55,6 @@ const props = defineProps({
activeIndex: { type: String, default: "" }, activeIndex: { type: String, default: "" },
}); });
const { t } = useI18n(); const { t } = useI18n();
const routeParams = useRoute().params;
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
function removeWidget() { function removeWidget() {
dashboardStore.removeControls(props.data); dashboardStore.removeControls(props.data);

View File

@ -38,7 +38,7 @@ limitations under the License. -->
placement="bottom" placement="bottom"
trigger="click" trigger="click"
:width="100" :width="100"
v-if="routeParams.entity" v-if="dashboardStore.editMode"
> >
<template #reference> <template #reference>
<span> <span>
@ -74,7 +74,6 @@ limitations under the License. -->
<script lang="ts"> <script lang="ts">
import { toRefs, reactive, defineComponent, ref, watch } from "vue"; import { toRefs, reactive, defineComponent, ref, watch } from "vue";
import type { PropType } from "vue"; import type { PropType } from "vue";
import { useRoute } from "vue-router";
import { LayoutConfig } from "@/types/dashboard"; import { LayoutConfig } from "@/types/dashboard";
import { useDashboardStore } from "@/store/modules/dashboard"; import { useDashboardStore } from "@/store/modules/dashboard";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
@ -98,7 +97,6 @@ export default defineComponent({
props, props,
setup(props) { setup(props) {
const { t } = useI18n(); const { t } = useI18n();
const routeParams = useRoute().params;
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
const state = reactive<{ source: { [key: string]: unknown } }>({ const state = reactive<{ source: { [key: string]: unknown } }>({
source: {}, source: {},
@ -196,7 +194,7 @@ export default defineComponent({
editConfig, editConfig,
data, data,
loading, loading,
routeParams, dashboardStore,
t, t,
}; };
}, },

View File

@ -33,17 +33,13 @@ limitations under the License. -->
<el-table v-loading="chartLoading" :data="endpoints" style="width: 100%"> <el-table v-loading="chartLoading" :data="endpoints" style="width: 100%">
<el-table-column label="Endpoints"> <el-table-column label="Endpoints">
<template #default="scope"> <template #default="scope">
<router-link <span
class="link" class="link"
:to="`/dashboard/${dashboardStore.layerId}/${ @click="clickEndpoint"
EntityType[2].value
}/${selectorStore.currentService.id}/${
scope.row.id
}/${config.dashboardName.split(' ').join('-')}`"
:style="{ fontSize: `${config.fontSize}px` }" :style="{ fontSize: `${config.fontSize}px` }"
> >
{{ scope.row.label }} {{ scope.row.label }}
</router-link> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -94,6 +90,8 @@ import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
import Line from "./Line.vue"; import Line from "./Line.vue";
import Card from "./Card.vue"; import Card from "./Card.vue";
import { EntityType } from "../data"; import { EntityType } from "../data";
import router from "@/router";
import getDashboard from "@/hooks/useDashboardsSession";
/*global defineProps */ /*global defineProps */
const props = defineProps({ const props = defineProps({
@ -159,6 +157,20 @@ async function queryEndpointMetrics(currentPods: Endpoint[]) {
} }
endpoints.value = currentPods; endpoints.value = currentPods;
} }
function clickEndpoint(scope: any) {
const d = getDashboard({
name: props.config.dashboardName,
layer: dashboardStore.layerId,
entity: EntityType[2].value,
});
dashboardStore.setEntity(EntityType[2].value);
dashboardStore.setCurrentDashboard(d);
router.push(
`/dashboard/${d.layer}/${d.entity}/${selectorStore.currentService.id}/${
scope.row.id
}/${d.name.split(" ").join("-")}`
);
}
function changePage(pageIndex: number) { function changePage(pageIndex: number) {
endpoints.value = searchEndpoints.value.splice(pageIndex - 1, pageSize); endpoints.value = searchEndpoints.value.splice(pageIndex - 1, pageSize);
} }

View File

@ -33,17 +33,13 @@ limitations under the License. -->
<el-table v-loading="chartLoading" :data="instances" style="width: 100%"> <el-table v-loading="chartLoading" :data="instances" style="width: 100%">
<el-table-column label="Service Instances"> <el-table-column label="Service Instances">
<template #default="scope"> <template #default="scope">
<router-link <span
class="link" class="link"
:to="`/dashboard/${dashboardStore.layerId}/${ @click="clickInstance"
EntityType[3].value
}/${selectorStore.currentService.id}/${
scope.row.id
}/${config.dashboardName.split(' ').join('-')}`"
:style="{ fontSize: `${config.fontSize}px` }" :style="{ fontSize: `${config.fontSize}px` }"
> >
{{ scope.row.label }} {{ scope.row.label }}
</router-link> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -94,6 +90,8 @@ import { InstanceListConfig } from "@/types/dashboard";
import { Instance } from "@/types/selector"; import { Instance } from "@/types/selector";
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor"; import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
import { EntityType } from "../data"; import { EntityType } from "../data";
import router from "@/router";
import getDashboard from "@/hooks/useDashboardsSession";
/*global defineProps */ /*global defineProps */
const props = defineProps({ const props = defineProps({
@ -164,6 +162,21 @@ async function queryInstanceMetrics(currentInstances: Instance[]) {
instances.value = currentInstances; instances.value = currentInstances;
} }
function clickInstance(scope: any) {
const d = getDashboard({
name: props.config.dashboardName,
layer: dashboardStore.layerId,
entity: EntityType[3].value,
});
dashboardStore.setCurrentDashboard(d);
dashboardStore.setEntity(d.entity);
router.push(
`/dashboard/${d.layer}/${d.entity}/${selectorStore.currentService.id}/${
scope.row.id
}/${d.name.split(" ").join("-")}`
);
}
function changePage(pageIndex: number) { function changePage(pageIndex: number) {
instances.value = searchInstances.value.splice(pageIndex - 1, pageSize); instances.value = searchInstances.value.splice(pageIndex - 1, pageSize);
} }

View File

@ -45,16 +45,13 @@ limitations under the License. -->
</el-table-column> </el-table-column>
<el-table-column label="Service Names"> <el-table-column label="Service Names">
<template #default="scope"> <template #default="scope">
<router-link <span
class="link" class="link"
:to="`/dashboard/${dashboardStore.layerId}/${
EntityType[0].value
}/${scope.row.id}/${config.dashboardName.split(' ').join('-')}`"
:key="1"
:style="{ fontSize: `${config.fontSize}px` }" :style="{ fontSize: `${config.fontSize}px` }"
@click="clickService(scope)"
> >
{{ scope.row.label }} {{ scope.row.label }}
</router-link> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -105,6 +102,8 @@ import { useDashboardStore } from "@/store/modules/dashboard";
import { Service } from "@/types/selector"; import { Service } from "@/types/selector";
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor"; import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
import { EntityType } from "../data"; import { EntityType } from "../data";
import router from "@/router";
import getDashboard from "@/hooks/useDashboardsSession";
/*global defineProps */ /*global defineProps */
const props = defineProps({ const props = defineProps({
@ -173,6 +172,21 @@ async function queryServices() {
} }
queryServiceMetrics(services.value); queryServiceMetrics(services.value);
} }
function clickService(scope: any) {
const d = getDashboard({
name: props.config.dashboardName,
layer: dashboardStore.layerId,
entity: EntityType[0].value,
});
dashboardStore.setCurrentDashboard(d);
dashboardStore.setEntity(d.entity);
const path = `/dashboard/${d.layer}/${d.entity}/${scope.row.id}/${d.name
.split(" ")
.join("-")}`;
router.push(path);
}
async function queryServiceMetrics(currentServices: Service[]) { async function queryServiceMetrics(currentServices: Service[]) {
const { metrics } = props.config; const { metrics } = props.config;

View File

@ -72,15 +72,29 @@ limitations under the License. -->
/> />
</div> </div>
</div> </div>
<div class="tool-icons"> <div class="flex-h tools">
<span <div class="tool-icons flex-h" v-if="dashboardStore.editMode">
@click="clickIcons(t)" <span
v-for="(t, index) in toolIcons" @click="clickIcons(t)"
:key="index" v-for="(t, index) in toolIcons"
:title="t.content" :key="index"
> :title="t.content"
<Icon class="icon-btn" size="sm" :iconName="t.name" /> >
</span> <el-tooltip :content="t.content" placement="bottom">
<i>
<Icon class="icon-btn" size="sm" :iconName="t.name" />
</i>
</el-tooltip>
</span>
</div>
<div class="switch">
<el-switch
v-model="dashboardStore.editMode"
active-text="Edit"
inactive-text="View"
@change="changeMode"
/>
</div>
</div> </div>
</div> </div>
</template> </template>
@ -102,7 +116,9 @@ import {
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { Option } from "@/types/app"; import { Option } from "@/types/app";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const dashboardStore = useDashboardStore(); const dashboardStore = useDashboardStore();
const selectorStore = useSelectorStore(); const selectorStore = useSelectorStore();
const appStore = useAppStoreWithOut(); const appStore = useAppStoreWithOut();
@ -127,9 +143,10 @@ const states = reactive<{
currentDestService: "", currentDestService: "",
currentDestPod: "", currentDestPod: "",
}); });
if (params.layerId) {
dashboardStore.setLayer(params.layerId); dashboardStore.setLayer(params.layerId);
dashboardStore.setEntity(params.entity); dashboardStore.setEntity(params.entity);
}
appStore.setEventStack([initSelector]); appStore.setEventStack([initSelector]);
initSelector(); initSelector();
@ -286,6 +303,14 @@ function changePods(pod: any) {
} }
} }
function changeMode() {
if (dashboardStore.editMode) {
ElMessage.warning(t("editWarning"));
return;
}
ElMessage.warning(t("viewWarning"));
}
function clickIcons(t: { id: string; content: string; name: string }) { function clickIcons(t: { id: string; content: string; name: string }) {
if ( if (
dashboardStore.selectedGrid && dashboardStore.selectedGrid &&
@ -429,12 +454,17 @@ function getTools() {
<style lang="scss" scoped> <style lang="scss" scoped>
.dashboard-tool { .dashboard-tool {
text-align: right; text-align: right;
padding: 5px; padding: 3px 5px 5px 5px;
background: rgb(240, 242, 245); background: rgb(240, 242, 245);
border-bottom: 1px solid #dfe4e8; border-bottom: 1px solid #dfe4e8;
justify-content: space-between; justify-content: space-between;
} }
.switch {
padding-top: 2px;
margin: 0 10px;
}
.label { .label {
font-size: 12px; font-size: 12px;
display: inline-block; display: inline-block;
@ -445,6 +475,10 @@ function getTools() {
margin-top: 2px; margin-top: 2px;
} }
.tools {
justify-content: space-between;
}
.icon-btn { .icon-btn {
display: inline-block; display: inline-block;
padding: 3px; padding: 3px;

View File

@ -85,6 +85,7 @@ import Settings from "./Settings.vue";
import { Option } from "@/types/app"; import { Option } from "@/types/app";
import { Service } from "@/types/selector"; import { Service } from "@/types/selector";
import { useAppStoreWithOut } from "@/store/modules/app"; import { useAppStoreWithOut } from "@/store/modules/app";
import getDashboard from "@/hooks/useDashboardsSession";
/*global Nullable, defineProps */ /*global Nullable, defineProps */
const props = defineProps({ const props = defineProps({
@ -239,9 +240,15 @@ function handleLinkClick(event: any, d: Call) {
dashboardStore.entity === EntityType[1].value dashboardStore.entity === EntityType[1].value
? EntityType[0].value ? EntityType[0].value
: dashboardStore.entity; : dashboardStore.entity;
const path = `/dashboard/${dashboardStore.layerId}/${e}Relation/${ const p = getDashboard({
d.source.id name: settings.value.linkDashboard,
}/${d.target.id}/${settings.value.linkDashboard.split(" ").join("-")}`; layer: dashboardStore.layerId,
entity: `${e}Relation`,
});
dashboardStore.setEntity(p.entity);
const path = `/dashboard/${p.layer}/${e}Relation/${d.source.id}/${
d.target.id
}/${p.name.split(" ").join("-")}`;
const routeUrl = router.resolve({ path }); const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");
} }
@ -373,15 +380,27 @@ async function handleInspect() {
update(); update();
} }
function handleGoEndpoint(name: string) { function handleGoEndpoint(name: string) {
const path = `/dashboard/${dashboardStore.layerId}/Endpoint/${ const p = getDashboard({
topologyStore.node.id name,
}/${name.split(" ").join("-")}`; layer: dashboardStore.layerId,
entity: EntityType[2].value,
});
dashboardStore.setEntity(p.entity);
const path = `/dashboard/${p.layer}/Endpoint/${topologyStore.node.id}/${name
.split(" ")
.join("-")}`;
const routeUrl = router.resolve({ path }); const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");
} }
function handleGoInstance(name: string) { function handleGoInstance(name: string) {
const path = `/dashboard/${dashboardStore.layerId}/ServiceInstance/${ const p = getDashboard({
name,
layer: dashboardStore.layerId,
entity: EntityType[3].value,
});
dashboardStore.setEntity(p.entity);
const path = `/dashboard/${p.layer}/ServiceInstance/${
topologyStore.node.id topologyStore.node.id
}/${name.split(" ").join("-")}`; }/${name.split(" ").join("-")}`;
const routeUrl = router.resolve({ path }); const routeUrl = router.resolve({ path });
@ -389,9 +408,15 @@ function handleGoInstance(name: string) {
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");
} }
function handleGoDashboard(name: string) { function handleGoDashboard(name: string) {
const path = `/dashboard/${dashboardStore.layerId}/Service/${ const p = getDashboard({
topologyStore.node.id name,
}/${name.split(" ").join("-")}`; layer: dashboardStore.layerId,
entity: EntityType[0].value,
});
dashboardStore.setEntity(p.entity);
const path = `/dashboard/${p.layer}/Service/${topologyStore.node.id}/${name
.split(" ")
.join("-")}`;
const routeUrl = router.resolve({ path }); const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");

View File

@ -86,6 +86,7 @@ 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"; import router from "@/router";
import getDashboard from "@/hooks/useDashboardsSession";
/*global defineProps */ /*global defineProps */
const props = defineProps({ const props = defineProps({
@ -150,7 +151,14 @@ function goDashboard() {
dashboardStore.entity === EntityType[2].value dashboardStore.entity === EntityType[2].value
? EntityType[2].value ? EntityType[2].value
: EntityType[3].value; : EntityType[3].value;
const path = `/dashboard/${dashboardStore.layerId}/${entity}/${topologyStore.node.serviceId}/${topologyStore.node.id}/${settings.value.nodeDashboard}`; const d = getDashboard({
name: settings.value.nodeDashboard,
layer: dashboardStore.layerId,
entity,
});
dashboardStore.setEntity(entity);
dashboardStore.setCurrentDashboard(d);
const path = `/dashboard/${d.layer}/${entity}/${topologyStore.node.serviceId}/${topologyStore.node.id}/${d.name}`;
const routeUrl = router.resolve({ path }); const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");
topologyStore.setNode(null); topologyStore.setNode(null);
@ -182,7 +190,13 @@ function selectNodeLink(d: any) {
dashboardStore.entity === EntityType[2].value dashboardStore.entity === EntityType[2].value
? EntityType[6].value ? EntityType[6].value
: EntityType[5].value; : EntityType[5].value;
const path = `/dashboard/${dashboardStore.layerId}/${entity}/${sourceObj.serviceId}/${sourceObj.id}/${targetObj.serviceId}/${targetObj.id}/${settings.value.linkDashboard}`; const p = getDashboard({
name: settings.value.linkDashboard,
layer: dashboardStore.layerId,
entity,
});
dashboardStore.setEntity(entity);
const path = `/dashboard/${p.layer}/${entity}/${sourceObj.serviceId}/${sourceObj.id}/${targetObj.serviceId}/${targetObj.id}/${p.name}`;
const routeUrl = router.resolve({ path }); const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank"); window.open(routeUrl.href, "_blank");
return; return;

View File

@ -225,6 +225,7 @@ const states = reactive<{
linkDashboards: [], linkDashboards: [],
nodeDashboards: [], nodeDashboards: [],
}); });
console.log(dashboardStore.selectedGrid);
const isService = [EntityType[0].value, EntityType[1].value].includes( const isService = [EntityType[0].value, EntityType[1].value].includes(
dashboardStore.entity dashboardStore.entity
); );