mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-12 15:52:57 +00:00
Merge branch 'main' of github.com:apache/skywalking-booster-ui into feat/topology
This commit is contained in:
commit
1ef2fb3220
12
package-lock.json
generated
12
package-lock.json
generated
@ -7167,9 +7167,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.4",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@ -20411,9 +20411,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"follow-redirects": {
|
"follow-redirects": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.4",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
|
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw=="
|
||||||
},
|
},
|
||||||
"for-in": {
|
"for-in": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
@ -48,8 +48,14 @@ limitations under the License. -->
|
|||||||
@input="changeTimeRange"
|
@input="changeTimeRange"
|
||||||
/>
|
/>
|
||||||
<span> UTC{{ appStore.utcHour >= 0 ? "+" : "" }}{{ `${appStore.utcHour}:${appStore.utcMin}` }} </span>
|
<span> UTC{{ appStore.utcHour >= 0 ? "+" : "" }}{{ `${appStore.utcHour}:${appStore.utcMin}` }} </span>
|
||||||
<span class="ml-5">
|
<span class="ml-5" ref="themeSwitchRef">
|
||||||
<el-switch v-model="theme" :active-icon="Moon" :inactive-icon="Sunny" inline-prompt @change="changeTheme" />
|
<el-switch
|
||||||
|
v-model="theme"
|
||||||
|
:active-icon="Moon"
|
||||||
|
:inactive-icon="Sunny"
|
||||||
|
inline-prompt
|
||||||
|
@change="handleChangeTheme"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span title="refresh" class="ghost ml-5 cp" @click="handleReload">
|
<span title="refresh" class="ghost ml-5 cp" @click="handleReload">
|
||||||
<Icon iconName="retry" :loading="appStore.autoRefresh" class="middle" />
|
<Icon iconName="retry" :loading="appStore.autoRefresh" class="middle" />
|
||||||
@ -67,18 +73,18 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch } from "vue";
|
import { Themes } from "@/constants/data";
|
||||||
import { useRoute } from "vue-router";
|
import router from "@/router";
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import timeFormat from "@/utils/timeFormat";
|
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import { MetricCatalog } from "@/views/dashboard/data";
|
|
||||||
import type { DashboardItem } from "@/types/dashboard";
|
import type { DashboardItem } from "@/types/dashboard";
|
||||||
import router from "@/router";
|
import timeFormat from "@/utils/timeFormat";
|
||||||
|
import { MetricCatalog } from "@/views/dashboard/data";
|
||||||
import { ArrowRight, Moon, Sunny } from "@element-plus/icons-vue";
|
import { ArrowRight, Moon, Sunny } from "@element-plus/icons-vue";
|
||||||
import { Themes } from "@/constants/data";
|
import { ElMessage } from "element-plus";
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
/*global Indexable */
|
/*global Indexable */
|
||||||
const { t, te } = useI18n();
|
const { t, te } = useI18n();
|
||||||
@ -89,6 +95,7 @@ limitations under the License. -->
|
|||||||
const timeRange = ref<number>(0);
|
const timeRange = ref<number>(0);
|
||||||
const pageTitle = ref<string>("");
|
const pageTitle = ref<string>("");
|
||||||
const theme = ref<boolean>(true);
|
const theme = ref<boolean>(true);
|
||||||
|
const themeSwitchRef = ref<HTMLElement>();
|
||||||
|
|
||||||
const savedTheme = window.localStorage.getItem("theme-is-dark");
|
const savedTheme = window.localStorage.getItem("theme-is-dark");
|
||||||
if (savedTheme === "false") {
|
if (savedTheme === "false") {
|
||||||
@ -119,6 +126,35 @@ limitations under the License. -->
|
|||||||
window.localStorage.setItem("theme-is-dark", String(theme.value));
|
window.localStorage.setItem("theme-is-dark", String(theme.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleChangeTheme() {
|
||||||
|
const x = themeSwitchRef.value?.offsetLeft ?? 0;
|
||||||
|
const y = themeSwitchRef.value?.offsetTop ?? 0;
|
||||||
|
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y));
|
||||||
|
// compatibility handling
|
||||||
|
if (!document.startViewTransition) {
|
||||||
|
changeTheme();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// api: https://developer.chrome.com/docs/web-platform/view-transitions
|
||||||
|
const transition = document.startViewTransition(() => {
|
||||||
|
changeTheme();
|
||||||
|
});
|
||||||
|
|
||||||
|
transition.ready.then(() => {
|
||||||
|
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`];
|
||||||
|
document.documentElement.animate(
|
||||||
|
{
|
||||||
|
clipPath: !theme.value ? clipPath.reverse() : clipPath,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
duration: 500,
|
||||||
|
easing: "ease-in",
|
||||||
|
pseudoElement: !theme.value ? "::view-transition-old(root)" : "::view-transition-new(root)",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getName(list: any[]) {
|
function getName(list: any[]) {
|
||||||
return list.find((d: any) => d.selected) || {};
|
return list.find((d: any) => d.selected) || {};
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,8 @@ const msg = {
|
|||||||
editTab: "Enable editing tab names",
|
editTab: "Enable editing tab names",
|
||||||
label: "Service Name",
|
label: "Service Name",
|
||||||
id: "Service ID",
|
id: "Service ID",
|
||||||
setRoot: "Set this to root",
|
setRoot: "Set Normal to Root",
|
||||||
setNormal: "Set this to normal",
|
setNormal: "Set Root to Normal",
|
||||||
export: "Export Dashboard Templates",
|
export: "Export Dashboard Templates",
|
||||||
import: "Import Dashboard Templates",
|
import: "Import Dashboard Templates",
|
||||||
yes: "Yes",
|
yes: "Yes",
|
||||||
|
@ -47,7 +47,23 @@ router.beforeEach((to, from, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (to.path === "/") {
|
if (to.path === "/") {
|
||||||
const defaultPath = (routesLayers[0] && routesLayers[0].children[0].path) || "";
|
let defaultPath = "";
|
||||||
|
for (const route of routesLayers) {
|
||||||
|
for (const child of route.children) {
|
||||||
|
if (child.meta.activate) {
|
||||||
|
defaultPath = child.path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (defaultPath) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defaultPath) {
|
||||||
|
defaultPath = "/marketplace";
|
||||||
|
}
|
||||||
|
|
||||||
next({ path: defaultPath });
|
next({ path: defaultPath });
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
|
@ -260,3 +260,27 @@ div:has(> a.menu-title) {
|
|||||||
.el-input-number .el-input__inner {
|
.el-input-number .el-input__inner {
|
||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
&::view-transition-old(root),
|
||||||
|
&::view-transition-new(root) {
|
||||||
|
animation: none;
|
||||||
|
mix-blend-mode: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
&::view-transition-old(root) {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
&::view-transition-new(root) {
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::view-transition-old(root) {
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
&::view-transition-new(root) {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1
src/types/dashboard.d.ts
vendored
1
src/types/dashboard.d.ts
vendored
@ -21,6 +21,7 @@ export type DashboardItem = {
|
|||||||
layer: string;
|
layer: string;
|
||||||
isRoot: boolean;
|
isRoot: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
|
isDefault: boolean;
|
||||||
};
|
};
|
||||||
export interface LayoutConfig {
|
export interface LayoutConfig {
|
||||||
x: number;
|
x: number;
|
||||||
|
9
src/types/global.d.ts
vendored
9
src/types/global.d.ts
vendored
@ -15,11 +15,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import type {
|
import type {
|
||||||
|
ComponentPublicInstance,
|
||||||
ComponentRenderProxy,
|
ComponentRenderProxy,
|
||||||
|
FunctionalComponent,
|
||||||
VNode,
|
VNode,
|
||||||
VNodeChild,
|
VNodeChild,
|
||||||
ComponentPublicInstance,
|
|
||||||
FunctionalComponent,
|
|
||||||
PropType as VuePropType,
|
PropType as VuePropType,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
|
|
||||||
@ -39,6 +39,11 @@ declare global {
|
|||||||
lastBuildTime: string;
|
lastBuildTime: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Document
|
||||||
|
interface Document {
|
||||||
|
startViewTransition(callback: () => void): any;
|
||||||
|
}
|
||||||
|
|
||||||
// vue
|
// vue
|
||||||
declare type PropType<T> = VuePropType<T>;
|
declare type PropType<T> = VuePropType<T>;
|
||||||
declare type VueNode = VNodeChild | JSX.Element;
|
declare type VueNode = VNodeChild | JSX.Element;
|
||||||
|
@ -57,14 +57,39 @@ limitations under the License. -->
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="layer" label="Layer" width="160" />
|
<el-table-column prop="layer" label="Layer" width="160" />
|
||||||
<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="60">
|
<el-table-column prop="isRoot" label="Root" width="150">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>
|
<el-popconfirm
|
||||||
{{ scope.row.isRoot ? t("yes") : t("no") }}
|
:title="t('rootTitle')"
|
||||||
</span>
|
@confirm="setRoot(scope.row)"
|
||||||
|
v-if="[EntityType[0].value, EntityType[1].value].includes(scope.row.entity)"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<el-button size="small" style="width: 110px">
|
||||||
|
{{ scope.row.isRoot ? t("setNormal") : t("setRoot") }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
<span v-else> -- </span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="Operations" width="350">
|
<el-table-column prop="isDefault" label="Default Dashboard" width="140">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-popconfirm
|
||||||
|
:title="t('rootTitle')"
|
||||||
|
@confirm="handleTopLevel(scope.row)"
|
||||||
|
v-if="[EntityType[0].value].includes(scope.row.entity)"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<el-button size="small" style="width: 80px">
|
||||||
|
{{ scope.row.isDefault ? "Disable" : "Enable" }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
<span v-else> -- </span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="Operations" width="300">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" @click="handleEdit(scope.row)">
|
<el-button size="small" @click="handleEdit(scope.row)">
|
||||||
{{ t("edit") }}
|
{{ t("edit") }}
|
||||||
@ -79,17 +104,6 @@ limitations under the License. -->
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-popconfirm>
|
</el-popconfirm>
|
||||||
<el-popconfirm
|
|
||||||
:title="t('rootTitle')"
|
|
||||||
@confirm="setRoot(scope.row)"
|
|
||||||
v-if="[EntityType[0].value, EntityType[1].value].includes(scope.row.entity)"
|
|
||||||
>
|
|
||||||
<template #reference>
|
|
||||||
<el-button size="small" style="width: 110px" type="danger">
|
|
||||||
{{ scope.row.isRoot ? t("setNormal") : t("setRoot") }}
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-popconfirm>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -175,17 +189,19 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
for (const item of arr) {
|
for (const item of arr) {
|
||||||
const { layer, name, entity, isRoot, children } = item.configuration;
|
const { layer, name, entity, isRoot, children, isDefault } = item.configuration;
|
||||||
const index = dashboardStore.dashboards.findIndex((d: DashboardItem) => d.id === item.id);
|
const index = dashboardStore.dashboards.findIndex((d: DashboardItem) => d.id === item.id);
|
||||||
const p: DashboardItem = {
|
const p: DashboardItem = {
|
||||||
name: name.split(" ").join("-"),
|
name: name.split(" ").join("-"),
|
||||||
layer: layer,
|
layer: layer,
|
||||||
entity: entity,
|
entity: entity,
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
|
isDefault: false,
|
||||||
};
|
};
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
p.id = item.id;
|
p.id = item.id;
|
||||||
p.isRoot = isRoot;
|
p.isRoot = isRoot;
|
||||||
|
p.isDefault = isDefault;
|
||||||
}
|
}
|
||||||
dashboardStore.setCurrentDashboard(p);
|
dashboardStore.setCurrentDashboard(p);
|
||||||
dashboardStore.setLayout(children);
|
dashboardStore.setLayout(children);
|
||||||
@ -328,7 +344,7 @@ limitations under the License. -->
|
|||||||
configuration: JSON.stringify(c),
|
configuration: JSON.stringify(c),
|
||||||
};
|
};
|
||||||
const res = await dashboardStore.updateDashboard(setting);
|
const res = await dashboardStore.updateDashboard(setting);
|
||||||
if (res.data.changeTemplate.id) {
|
if (res.data.changeTemplate.status) {
|
||||||
sessionStorage.setItem(
|
sessionStorage.setItem(
|
||||||
key,
|
key,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@ -356,7 +372,66 @@ limitations under the License. -->
|
|||||||
configuration: JSON.stringify(c),
|
configuration: JSON.stringify(c),
|
||||||
};
|
};
|
||||||
const res = await dashboardStore.updateDashboard(setting);
|
const res = await dashboardStore.updateDashboard(setting);
|
||||||
if (res.data.changeTemplate.id) {
|
if (res.data.changeTemplate.status) {
|
||||||
|
sessionStorage.setItem(
|
||||||
|
key,
|
||||||
|
JSON.stringify({
|
||||||
|
id: d.id,
|
||||||
|
configuration: c,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.push(d);
|
||||||
|
}
|
||||||
|
dashboardStore.resetDashboards(items);
|
||||||
|
searchDashboards(1);
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
async function handleTopLevel(row: DashboardItem) {
|
||||||
|
const items: DashboardItem[] = [];
|
||||||
|
loading.value = true;
|
||||||
|
for (const d of dashboardStore.dashboards) {
|
||||||
|
if (d.id === row.id) {
|
||||||
|
d.isDefault = !row.isDefault;
|
||||||
|
const key = [d.layer, d.entity, d.name].join("_");
|
||||||
|
const layout = sessionStorage.getItem(key) || "{}";
|
||||||
|
const c = {
|
||||||
|
...JSON.parse(layout).configuration,
|
||||||
|
...d,
|
||||||
|
};
|
||||||
|
delete c.id;
|
||||||
|
const setting = {
|
||||||
|
id: d.id,
|
||||||
|
configuration: JSON.stringify(c),
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await dashboardStore.updateDashboard(setting);
|
||||||
|
if (res.data.changeTemplate.status) {
|
||||||
|
sessionStorage.setItem(
|
||||||
|
key,
|
||||||
|
JSON.stringify({
|
||||||
|
id: d.id,
|
||||||
|
configuration: c,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (d.layer === row.layer && [EntityType[0].value].includes(d.entity) && !row.isDefault && d.isDefault) {
|
||||||
|
d.isDefault = false;
|
||||||
|
const key = [d.layer, d.entity, d.name].join("_");
|
||||||
|
const layout = sessionStorage.getItem(key) || "{}";
|
||||||
|
const c = {
|
||||||
|
...JSON.parse(layout).configuration,
|
||||||
|
...d,
|
||||||
|
};
|
||||||
|
const setting = {
|
||||||
|
id: d.id,
|
||||||
|
configuration: JSON.stringify(c),
|
||||||
|
};
|
||||||
|
const res = await dashboardStore.updateDashboard(setting);
|
||||||
|
if (res.data.changeTemplate.status) {
|
||||||
sessionStorage.setItem(
|
sessionStorage.setItem(
|
||||||
key,
|
key,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
Loading…
Reference in New Issue
Block a user