mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-09-20 21:22:03 +00:00
feat: refactor the configuration view and implement the optional config for displaying timestamp
in Log widget (#492)
This commit is contained in:
@@ -43,7 +43,7 @@ limitations under the License. -->
|
|||||||
import { ref, watch } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
|
|
||||||
/*global defineProps, defineEmits, Indexable*/
|
/*global defineProps, defineEmits, Indexable*/
|
||||||
const emit = defineEmits(["change", "query"]);
|
const emit = defineEmits(["change", "query"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
options: {
|
options: {
|
||||||
|
@@ -296,7 +296,7 @@ const msg = {
|
|||||||
return: "Return",
|
return: "Return",
|
||||||
isError: "Error",
|
isError: "Error",
|
||||||
contentType: "Content Type",
|
contentType: "Content Type",
|
||||||
content: "Timestamp - Content",
|
content: "Content",
|
||||||
level: "Level",
|
level: "Level",
|
||||||
viewLogs: "View Logs",
|
viewLogs: "View Logs",
|
||||||
logsTagsTip: `Only tags defined in the core/default/searchableLogsTags are searchable.
|
logsTagsTip: `Only tags defined in the core/default/searchableLogsTags are searchable.
|
||||||
|
@@ -293,7 +293,7 @@ const msg = {
|
|||||||
return: "返回",
|
return: "返回",
|
||||||
isError: "错误",
|
isError: "错误",
|
||||||
contentType: "内容类型",
|
contentType: "内容类型",
|
||||||
content: "时间戳 - 内容",
|
content: "内容",
|
||||||
level: "Level",
|
level: "Level",
|
||||||
viewLogs: "查看日志",
|
viewLogs: "查看日志",
|
||||||
logsTagsTip: "只有core/default/searchableLogsTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
|
logsTagsTip: "只有core/default/searchableLogsTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
|
||||||
|
@@ -33,6 +33,7 @@ interface LogState {
|
|||||||
supportQueryLogsByKeywords: boolean;
|
supportQueryLogsByKeywords: boolean;
|
||||||
logs: Recordable[];
|
logs: Recordable[];
|
||||||
loadLogs: boolean;
|
loadLogs: boolean;
|
||||||
|
logHeaderType: string;
|
||||||
}
|
}
|
||||||
const { getDurationTime } = useDuration();
|
const { getDurationTime } = useDuration();
|
||||||
|
|
||||||
@@ -50,6 +51,7 @@ export const logStore = defineStore({
|
|||||||
selectorStore: useSelectorStore(),
|
selectorStore: useSelectorStore(),
|
||||||
logs: [],
|
logs: [],
|
||||||
loadLogs: false,
|
loadLogs: false,
|
||||||
|
logHeaderType: localStorage.getItem("log-header-type") || "content",
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setLogCondition(data: Recordable) {
|
setLogCondition(data: Recordable) {
|
||||||
@@ -62,6 +64,9 @@ export const logStore = defineStore({
|
|||||||
paging: { pageNum: 1, pageSize: 15 },
|
paging: { pageNum: 1, pageSize: 15 },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
setLogHeaderType(type: string) {
|
||||||
|
this.logHeaderType = type;
|
||||||
|
},
|
||||||
async getServices(layer: string) {
|
async getServices(layer: string) {
|
||||||
const response = await graphql.query("queryServices").params({
|
const response = await graphql.query("queryServices").params({
|
||||||
layer,
|
layer,
|
||||||
|
@@ -24,6 +24,7 @@ import { useSelectorStore } from "@/store/modules/selectors";
|
|||||||
import { QueryOrders } from "@/views/dashboard/data";
|
import { QueryOrders } from "@/views/dashboard/data";
|
||||||
import { EndpointsTopNDefault } from "../data";
|
import { EndpointsTopNDefault } from "../data";
|
||||||
import { useDuration } from "@/hooks/useDuration";
|
import { useDuration } from "@/hooks/useDuration";
|
||||||
|
import { LogItem } from "@/types/log";
|
||||||
interface TraceState {
|
interface TraceState {
|
||||||
services: Service[];
|
services: Service[];
|
||||||
instances: Instance[];
|
instances: Instance[];
|
||||||
@@ -32,7 +33,7 @@ interface TraceState {
|
|||||||
traceSpans: Span[];
|
traceSpans: Span[];
|
||||||
currentTrace: Nullable<Trace>;
|
currentTrace: Nullable<Trace>;
|
||||||
conditions: Recordable;
|
conditions: Recordable;
|
||||||
traceSpanLogs: Recordable[];
|
traceSpanLogs: LogItem[];
|
||||||
selectorStore: Recordable;
|
selectorStore: Recordable;
|
||||||
selectedSpan: Recordable<Span>;
|
selectedSpan: Recordable<Span>;
|
||||||
serviceList: string[];
|
serviceList: string[];
|
||||||
|
30
src/types/log.ts
Normal file
30
src/types/log.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* 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 interface LogItem {
|
||||||
|
timestamp: number;
|
||||||
|
content: string;
|
||||||
|
tags: { key: string; value: string }[];
|
||||||
|
serviceId: string;
|
||||||
|
traceId: string;
|
||||||
|
spanId: string;
|
||||||
|
parentSpanId: string;
|
||||||
|
processId: string;
|
||||||
|
processName: string;
|
||||||
|
processTags: { key: string; value: string }[];
|
||||||
|
processStartTime: string;
|
||||||
|
processEndTime: string;
|
||||||
|
}
|
@@ -15,6 +15,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import utc from "dayjs/plugin/utc";
|
||||||
|
import timezone from "dayjs/plugin/timezone";
|
||||||
|
|
||||||
|
dayjs.extend(utc);
|
||||||
|
dayjs.extend(timezone);
|
||||||
export default function dateFormatStep(date: Date, step: string, monthDayDiff?: boolean): string {
|
export default function dateFormatStep(date: Date, step: string, monthDayDiff?: boolean): string {
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
const monthTemp = date.getMonth() + 1;
|
const monthTemp = date.getMonth() + 1;
|
||||||
@@ -97,4 +102,10 @@ export const dateFormatTime = (date: Date, step: string): string => {
|
|||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
export const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") => dayjs(new Date(date)).format(pattern);
|
export const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss", timezone?: string) => {
|
||||||
|
const dayjsInstance = dayjs(new Date(date));
|
||||||
|
if (timezone) {
|
||||||
|
return dayjsInstance.tz(timezone).format(pattern);
|
||||||
|
}
|
||||||
|
return dayjsInstance.format(pattern);
|
||||||
|
};
|
||||||
|
@@ -11,8 +11,8 @@ 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>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<div>{{ t("instanceDashboards") }}</div>
|
<div class="config-label flex-h mr-20">{{ t("instanceDashboards") }}</div>
|
||||||
<Selector
|
<Selector
|
||||||
:value="instanceDashboardName || ''"
|
:value="instanceDashboardName || ''"
|
||||||
:options="instanceDashboards"
|
:options="instanceDashboards"
|
||||||
@@ -23,8 +23,8 @@ limitations under the License. -->
|
|||||||
:clearable="true"
|
:clearable="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<div>{{ t("processDashboards") }}</div>
|
<div class="config-label flex-h mr-20">{{ t("processDashboards") }}</div>
|
||||||
<Selector
|
<Selector
|
||||||
:value="processDashboardName || ''"
|
:value="processDashboardName || ''"
|
||||||
:options="processDashboards"
|
:options="processDashboards"
|
||||||
@@ -35,14 +35,7 @@ limitations under the License. -->
|
|||||||
:clearable="true"
|
:clearable="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<ConfigurationFooter />
|
||||||
<el-button size="small">
|
|
||||||
{{ t("cancel") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button size="small" type="primary" @click="applyConfig">
|
|
||||||
{{ t("apply") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
@@ -50,6 +43,8 @@ limitations under the License. -->
|
|||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { EntityType } from "../data";
|
import { EntityType } from "../data";
|
||||||
import type { DashboardItem, LayoutConfig } from "@/types/dashboard";
|
import type { DashboardItem, LayoutConfig } from "@/types/dashboard";
|
||||||
|
import ConfigurationFooter from "./components/ConfigurationFooter.vue";
|
||||||
|
import "./style.scss";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
@@ -74,11 +69,6 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyConfig() {
|
|
||||||
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
}
|
|
||||||
function changeDashboard(param: { [key: string]: unknown }) {
|
function changeDashboard(param: { [key: string]: unknown }) {
|
||||||
dashboardStore.selectWidget({
|
dashboardStore.selectWidget({
|
||||||
...dashboardStore.selectedGrid,
|
...dashboardStore.selectedGrid,
|
||||||
@@ -87,21 +77,6 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.footer {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
border-top: 1px solid $border-color;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: right;
|
|
||||||
width: 100%;
|
|
||||||
background-color: $theme-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selectors {
|
.selectors {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
}
|
}
|
||||||
|
@@ -11,28 +11,22 @@ 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>
|
||||||
<div>
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("enableAssociate") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("enableAssociate") }}</div>
|
||||||
<el-switch v-model="eventAssociate" active-text="Yes" inactive-text="No" @change="updateConfig" />
|
<el-switch v-model="eventAssociate" active-text="Yes" inactive-text="No" @change="updateConfig" />
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<ConfigurationFooter />
|
||||||
<el-button size="small" @click="cancelConfig">
|
|
||||||
{{ t("cancel") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button size="small" type="primary" @click="applyConfig">
|
|
||||||
{{ t("apply") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
|
import ConfigurationFooter from "./components/ConfigurationFooter.vue";
|
||||||
|
import "./style.scss";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const originConfig = dashboardStore.selectedGrid;
|
|
||||||
const eventAssociate = ref(dashboardStore.selectedGrid?.eventAssociate || false);
|
const eventAssociate = ref(dashboardStore.selectedGrid?.eventAssociate || false);
|
||||||
|
|
||||||
function updateConfig() {
|
function updateConfig() {
|
||||||
@@ -40,37 +34,4 @@ limitations under the License. -->
|
|||||||
|
|
||||||
dashboardStore.selectWidget({ ...selectedGrid, eventAssociate: eventAssociate.value } as LayoutConfig);
|
dashboardStore.selectWidget({ ...selectedGrid, eventAssociate: eventAssociate.value } as LayoutConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyConfig() {
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelConfig() {
|
|
||||||
dashboardStore.selectWidget(originConfig);
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
|
||||||
.label {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
border-top: 1px solid $border-color-primary;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: right;
|
|
||||||
width: 100%;
|
|
||||||
background-color: $theme-background;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@@ -11,21 +11,14 @@ 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>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("tabExpressions") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("tabExpressions") }}</div>
|
||||||
<div class="mt-10" v-for="(child, index) in widgetTabs || []" :key="index">
|
<div class="mt-10" v-for="(child, index) in widgetTabs || []" :key="index">
|
||||||
<span class="name">{{ child.name }}</span>
|
<span class="name">{{ child.name }}</span>
|
||||||
<el-input class="input" size="small" v-model="expressions[child.name]" @change="changeExpression(child.name)" />
|
<el-input class="input" size="small" v-model="expressions[child.name]" @change="changeExpression(child.name)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<ConfigurationFooter />
|
||||||
<el-button size="small" @click="cancelConfig">
|
|
||||||
{{ t("cancel") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button size="small" type="primary" @click="applyConfig">
|
|
||||||
{{ t("apply") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
@@ -34,6 +27,8 @@ limitations under the License. -->
|
|||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { WidgetType, ListEntity } from "@/views/dashboard/data";
|
import { WidgetType, ListEntity } from "@/views/dashboard/data";
|
||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
|
import ConfigurationFooter from "./components/ConfigurationFooter.vue";
|
||||||
|
import "./style.scss";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
@@ -67,43 +62,12 @@ limitations under the License. -->
|
|||||||
|
|
||||||
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, children } as LayoutConfig);
|
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, children } as LayoutConfig);
|
||||||
}
|
}
|
||||||
function applyConfig() {
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelConfig() {
|
|
||||||
dashboardStore.selectWidget(originConfig);
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.label {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
border-top: 1px solid $border-color-primary;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: right;
|
|
||||||
width: 100%;
|
|
||||||
background-color: $theme-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@@ -11,16 +11,16 @@ 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>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("textUrl") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("textUrl") }}</div>
|
||||||
<el-input class="input" v-model="url" size="small" @change="changeConfig({ url })" />
|
<el-input class="input" v-model="url" size="small" @change="changeConfig({ url })" />
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("content") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("content") }}</div>
|
||||||
<el-input class="input" v-model="content" size="small" @change="changeConfig({ content })" />
|
<el-input class="input" v-model="content" size="small" @change="changeConfig({ content })" />
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("textAlign") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("textAlign") }}</div>
|
||||||
<Selector
|
<Selector
|
||||||
:value="textAlign"
|
:value="textAlign"
|
||||||
:options="AlignStyle"
|
:options="AlignStyle"
|
||||||
@@ -30,8 +30,8 @@ limitations under the License. -->
|
|||||||
@change="changeConfig({ textAlign: $event[0].value })"
|
@change="changeConfig({ textAlign: $event[0].value })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("backgroundColors") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("backgroundColors") }}</div>
|
||||||
<Selector
|
<Selector
|
||||||
:value="backgroundColor"
|
:value="backgroundColor"
|
||||||
:options="Colors"
|
:options="Colors"
|
||||||
@@ -41,8 +41,8 @@ limitations under the License. -->
|
|||||||
@change="changeConfig({ backgroundColor: $event[0].value })"
|
@change="changeConfig({ backgroundColor: $event[0].value })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("fontSize") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("fontSize") }}</div>
|
||||||
<el-slider
|
<el-slider
|
||||||
class="slider"
|
class="slider"
|
||||||
v-model="fontSize"
|
v-model="fontSize"
|
||||||
@@ -54,8 +54,8 @@ limitations under the License. -->
|
|||||||
@change="changeConfig({ fontSize })"
|
@change="changeConfig({ fontSize })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("fontColors") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("fontColors") }}</div>
|
||||||
<Selector
|
<Selector
|
||||||
:value="fontColor"
|
:value="fontColor"
|
||||||
:options="Colors"
|
:options="Colors"
|
||||||
@@ -65,20 +65,15 @@ limitations under the License. -->
|
|||||||
@change="changeConfig({ fontColor: $event[0].value })"
|
@change="changeConfig({ fontColor: $event[0].value })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<ConfigurationFooter />
|
||||||
<el-button size="small" @click="cancelConfig">
|
|
||||||
{{ t("cancel") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button size="small" type="primary" @click="applyConfig">
|
|
||||||
{{ t("apply") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import type { LayoutConfig, TextConfig } from "@/types/dashboard";
|
import type { LayoutConfig, TextConfig } from "@/types/dashboard";
|
||||||
|
import ConfigurationFooter from "./components/ConfigurationFooter.vue";
|
||||||
|
import "./style.scss";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
@@ -119,15 +114,6 @@ limitations under the License. -->
|
|||||||
};
|
};
|
||||||
dashboardStore.selectWidget({ ...selectedGrid, graph } as LayoutConfig);
|
dashboardStore.selectWidget({ ...selectedGrid, graph } as LayoutConfig);
|
||||||
}
|
}
|
||||||
function applyConfig() {
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelConfig() {
|
|
||||||
dashboardStore.selectWidget(originConfig);
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.slider {
|
.slider {
|
||||||
@@ -135,29 +121,7 @@ limitations under the License. -->
|
|||||||
margin-top: -3px;
|
margin-top: -3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
border-top: 1px solid $border-color-primary;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: right;
|
|
||||||
width: 100%;
|
|
||||||
background-color: $theme-background;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@@ -11,19 +11,12 @@ 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>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("iframeSrc") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("iframeSrc") }}</div>
|
||||||
<el-input class="input" v-model="url" size="small" @change="handleUrlChange" :class="{ error: urlError }" />
|
<el-input class="input" v-model="url" size="small" @change="handleUrlChange" :class="{ error: urlError }" />
|
||||||
<div v-if="urlError" class="error-message">{{ urlError }}</div>
|
<div v-if="urlError" class="error-message">{{ urlError }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<ConfigurationFooter />
|
||||||
<el-button size="small" @click="cancelConfig">
|
|
||||||
{{ t("cancel") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button size="small" type="primary" @click="applyConfig" :disabled="!!urlError">
|
|
||||||
{{ t("apply") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
@@ -31,6 +24,8 @@ limitations under the License. -->
|
|||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { validateAndSanitizeUrl } from "@/utils/validateAndSanitizeUrl";
|
import { validateAndSanitizeUrl } from "@/utils/validateAndSanitizeUrl";
|
||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
|
import ConfigurationFooter from "./components/ConfigurationFooter.vue";
|
||||||
|
import "./style.scss";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
@@ -61,19 +56,6 @@ limitations under the License. -->
|
|||||||
};
|
};
|
||||||
dashboardStore.selectWidget({ ...selectedGrid, widget } as LayoutConfig);
|
dashboardStore.selectWidget({ ...selectedGrid, widget } as LayoutConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyConfig() {
|
|
||||||
if (urlError.value) {
|
|
||||||
return; // Don't apply if there's a validation error
|
|
||||||
}
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelConfig() {
|
|
||||||
dashboardStore.selectWidget(originConfig);
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.slider {
|
.slider {
|
||||||
@@ -81,21 +63,10 @@ limitations under the License. -->
|
|||||||
margin-top: -3px;
|
margin-top: -3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.url-input.error {
|
.url-input.error {
|
||||||
:deep(.el-input__inner) {
|
:deep(.el-input__inner) {
|
||||||
border-color: $error-color;
|
border-color: $error-color;
|
||||||
@@ -107,15 +78,4 @@ limitations under the License. -->
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
border-top: 1px solid $border-color-primary;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: right;
|
|
||||||
width: 100%;
|
|
||||||
background-color: $theme-background;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@@ -11,12 +11,12 @@ 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>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("text") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("text") }}</div>
|
||||||
<el-input class="input" v-model="text" size="small" @change="changeConfig({ text })" />
|
<el-input class="input" v-model="text" size="small" @change="changeConfig({ text })" />
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("textAlign") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("textAlign") }}</div>
|
||||||
<Selector
|
<Selector
|
||||||
:value="textAlign"
|
:value="textAlign"
|
||||||
:options="AlignStyle"
|
:options="AlignStyle"
|
||||||
@@ -26,8 +26,8 @@ limitations under the License. -->
|
|||||||
@change="changeConfig({ textAlign: $event[0].value })"
|
@change="changeConfig({ textAlign: $event[0].value })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("backgroundColors") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("backgroundColors") }}</div>
|
||||||
<Selector
|
<Selector
|
||||||
:value="backgroundColor"
|
:value="backgroundColor"
|
||||||
:options="Colors"
|
:options="Colors"
|
||||||
@@ -37,8 +37,8 @@ limitations under the License. -->
|
|||||||
@change="changeConfig({ backgroundColor: $event[0].value })"
|
@change="changeConfig({ backgroundColor: $event[0].value })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("fontSize") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("fontSize") }}</div>
|
||||||
<el-slider
|
<el-slider
|
||||||
class="slider"
|
class="slider"
|
||||||
v-model="fontSize"
|
v-model="fontSize"
|
||||||
@@ -50,8 +50,8 @@ limitations under the License. -->
|
|||||||
@change="changeConfig({ fontSize })"
|
@change="changeConfig({ fontSize })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("fontColors") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("fontColors") }}</div>
|
||||||
<Selector
|
<Selector
|
||||||
:value="fontColor"
|
:value="fontColor"
|
||||||
:options="Colors"
|
:options="Colors"
|
||||||
@@ -61,20 +61,15 @@ limitations under the License. -->
|
|||||||
@change="changeConfig({ fontColor: $event[0].value })"
|
@change="changeConfig({ fontColor: $event[0].value })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<ConfigurationFooter />
|
||||||
<el-button size="small" @click="cancelConfig">
|
|
||||||
{{ t("cancel") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button size="small" type="primary" @click="applyConfig">
|
|
||||||
{{ t("apply") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import type { TimeRangeConfig, LayoutConfig } from "@/types/dashboard";
|
import type { TimeRangeConfig, LayoutConfig } from "@/types/dashboard";
|
||||||
|
import ConfigurationFooter from "./components/ConfigurationFooter.vue";
|
||||||
|
import "./style.scss";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
@@ -113,15 +108,6 @@ limitations under the License. -->
|
|||||||
};
|
};
|
||||||
dashboardStore.selectWidget({ ...selectedGrid, graph } as LayoutConfig);
|
dashboardStore.selectWidget({ ...selectedGrid, graph } as LayoutConfig);
|
||||||
}
|
}
|
||||||
function applyConfig() {
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelConfig() {
|
|
||||||
dashboardStore.selectWidget(originConfig);
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.slider {
|
.slider {
|
||||||
@@ -129,29 +115,7 @@ limitations under the License. -->
|
|||||||
margin-top: -3px;
|
margin-top: -3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
width: 500px;
|
width: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
border-top: 1px solid $border-color-primary;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: right;
|
|
||||||
width: 100%;
|
|
||||||
background-color: $theme-background;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@@ -11,22 +11,15 @@ 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>
|
||||||
<div class="item">
|
<div class="config-item flex-h">
|
||||||
<span class="label">{{ t("showDepth") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("showDepth") }}</div>
|
||||||
<el-switch v-model="showDepth" active-text="Yes" inactive-text="No" @change="changeConfig({ showDepth })" />
|
<el-switch v-model="showDepth" active-text="Yes" inactive-text="No" @change="changeConfig({ showDepth })" />
|
||||||
</div>
|
</div>
|
||||||
<div class="item" v-show="showDepth">
|
<div class="config-item flex-h" v-show="showDepth">
|
||||||
<span class="label">{{ t("defaultDepth") }}</span>
|
<div class="config-label flex-h mr-20">{{ t("defaultDepth") }}</div>
|
||||||
<Selector class="input" size="small" :value="depth" :options="DepthList" @change="changeDepth($event)" />
|
<Selector class="input" size="small" :value="depth" :options="DepthList" @change="changeDepth($event)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<ConfigurationFooter />
|
||||||
<el-button size="small">
|
|
||||||
{{ t("cancel") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button size="small" type="primary" @click="applyConfig">
|
|
||||||
{{ t("apply") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
@@ -35,6 +28,7 @@ limitations under the License. -->
|
|||||||
import { DepthList } from "../data";
|
import { DepthList } from "../data";
|
||||||
import type { Option } from "@/types/app";
|
import type { Option } from "@/types/app";
|
||||||
import type { TopologyConfig, LayoutConfig } from "@/types/dashboard";
|
import type { TopologyConfig, LayoutConfig } from "@/types/dashboard";
|
||||||
|
import ConfigurationFooter from "./components/ConfigurationFooter.vue";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
@@ -42,10 +36,6 @@ limitations under the License. -->
|
|||||||
const showDepth = ref<boolean>(graph?.showDepth || false);
|
const showDepth = ref<boolean>(graph?.showDepth || false);
|
||||||
const depth = ref<number>(graph?.depth || 2);
|
const depth = ref<number>(graph?.depth || 2);
|
||||||
|
|
||||||
function applyConfig() {
|
|
||||||
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
}
|
|
||||||
function changeConfig(param: { [key: string]: unknown }) {
|
function changeConfig(param: { [key: string]: unknown }) {
|
||||||
const { selectedGrid } = dashboardStore;
|
const { selectedGrid } = dashboardStore;
|
||||||
const graph = {
|
const graph = {
|
||||||
@@ -60,25 +50,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.footer {
|
.input {
|
||||||
position: fixed;
|
width: 300px;
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
border-top: 1px solid $border-color-primary;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: right;
|
|
||||||
width: 100%;
|
|
||||||
background-color: $theme-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 500;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -70,14 +70,7 @@ limitations under the License. -->
|
|||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<ConfigurationFooter />
|
||||||
<el-button size="small" @click="cancelConfig">
|
|
||||||
{{ t("cancel") }}
|
|
||||||
</el-button>
|
|
||||||
<el-button size="small" type="primary" @click="applyConfig">
|
|
||||||
{{ t("apply") }}
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -88,13 +81,15 @@ limitations under the License. -->
|
|||||||
import type { Option } from "@/types/app";
|
import type { Option } from "@/types/app";
|
||||||
import graphs from "../graphs";
|
import graphs from "../graphs";
|
||||||
import CustomOptions from "./widget/index";
|
import CustomOptions from "./widget/index";
|
||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import ConfigurationFooter from "./components/ConfigurationFooter.vue";
|
||||||
|
import "./style.scss";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "WidgetEdit",
|
name: "WidgetEdit",
|
||||||
components: {
|
components: {
|
||||||
...graphs,
|
...graphs,
|
||||||
...CustomOptions,
|
...CustomOptions,
|
||||||
|
ConfigurationFooter,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const configHeight = document.documentElement.clientHeight - 540;
|
const configHeight = document.documentElement.clientHeight - 540;
|
||||||
@@ -115,7 +110,6 @@ limitations under the License. -->
|
|||||||
index: dashboardStore.selectedGrid?.i,
|
index: dashboardStore.selectedGrid?.i,
|
||||||
visType: [],
|
visType: [],
|
||||||
});
|
});
|
||||||
const originConfig = dashboardStore.selectedGrid;
|
|
||||||
const widget = computed(() => dashboardStore.selectedGrid?.widget || {});
|
const widget = computed(() => dashboardStore.selectedGrid?.widget || {});
|
||||||
const graph = computed(() => dashboardStore.selectedGrid?.graph || {});
|
const graph = computed(() => dashboardStore.selectedGrid?.graph || {});
|
||||||
const title = computed(() => encodeURIComponent(widget.value.title || ""));
|
const title = computed(() => encodeURIComponent(widget.value.title || ""));
|
||||||
@@ -137,16 +131,6 @@ limitations under the License. -->
|
|||||||
loading.value = load;
|
loading.value = load;
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyConfig() {
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelConfig() {
|
|
||||||
dashboardStore.selectWidget(originConfig);
|
|
||||||
dashboardStore.setConfigPanel(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
states,
|
states,
|
||||||
loading,
|
loading,
|
||||||
@@ -154,8 +138,6 @@ limitations under the License. -->
|
|||||||
appStoreWithOut,
|
appStoreWithOut,
|
||||||
configHeight,
|
configHeight,
|
||||||
dashboardStore,
|
dashboardStore,
|
||||||
applyConfig,
|
|
||||||
cancelConfig,
|
|
||||||
getSource,
|
getSource,
|
||||||
getErrors,
|
getErrors,
|
||||||
setLoading,
|
setLoading,
|
||||||
@@ -225,17 +207,6 @@ limitations under the License. -->
|
|||||||
line-height: 400px;
|
line-height: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
border-top: 1px solid $border-color-primary;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: right;
|
|
||||||
width: 100%;
|
|
||||||
background-color: $theme-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collapse {
|
.collapse {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@@ -0,0 +1,53 @@
|
|||||||
|
<!-- 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="config-page-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 { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const originConfig = dashboardStore.selectedGrid;
|
||||||
|
|
||||||
|
function applyConfig() {
|
||||||
|
dashboardStore.setConfigPanel(false);
|
||||||
|
dashboardStore.setConfigs(dashboardStore.selectedGrid as LayoutConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelConfig() {
|
||||||
|
dashboardStore.selectWidget(originConfig);
|
||||||
|
dashboardStore.setConfigPanel(false);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.config-page-footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
border-top: 1px solid $border-color-primary;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: right;
|
||||||
|
width: 100%;
|
||||||
|
background-color: $theme-background;
|
||||||
|
}
|
||||||
|
</style>
|
26
src/views/dashboard/configuration/style.scss
Normal file
26
src/views/dashboard/configuration/style.scss
Normal 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.
|
||||||
|
*/
|
||||||
|
.config-item {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
align-items: center;
|
||||||
|
width: 200px;
|
||||||
|
}
|
@@ -28,7 +28,7 @@ limitations under the License. -->
|
|||||||
<Header :needQuery="needQuery" :data="data" />
|
<Header :needQuery="needQuery" :data="data" />
|
||||||
</div>
|
</div>
|
||||||
<div class="log">
|
<div class="log">
|
||||||
<List />
|
<List :data="data" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -438,7 +438,7 @@ limitations under the License. -->
|
|||||||
top: 0;
|
top: 0;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 120px;
|
width: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tips {
|
.tips {
|
||||||
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<LogTable v-loading="logStore.loadLogs" :tableData="logStore.logs || []" :type="type" :noLink="false">
|
<LogTable v-loading="logStore.loadLogs" :tableData="logStore.logs || []" :type="type" :noLink="false" :data="data">
|
||||||
<div class="log-tips" v-if="!logStore.logs.length">{{ t("noData") }}</div>
|
<div class="log-tips" v-if="!logStore.logs.length">{{ t("noData") }}</div>
|
||||||
</LogTable>
|
</LogTable>
|
||||||
<div class="mt-5 mb-5">
|
<div class="mt-5 mb-5">
|
||||||
@@ -34,11 +34,22 @@ limitations under the License. -->
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
import LogTable from "./LogTable/Index.vue";
|
import LogTable from "./LogTable/Index.vue";
|
||||||
import { useLogStore } from "@/store/modules/log";
|
import { useLogStore } from "@/store/modules/log";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
/*global defineProps*/
|
||||||
|
defineProps({
|
||||||
|
needQuery: { type: Boolean, default: false },
|
||||||
|
data: {
|
||||||
|
type: Object as PropType<LayoutConfig>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const logStore = useLogStore();
|
const logStore = useLogStore();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
@@ -17,7 +17,19 @@ limitations under the License. -->
|
|||||||
<div class="log">
|
<div class="log">
|
||||||
<div class="log-header flex-h" :class="type === 'browser' ? ['browser-header', 'flex-h'] : 'service-header'">
|
<div class="log-header flex-h" :class="type === 'browser' ? ['browser-header', 'flex-h'] : 'service-header'">
|
||||||
<template v-for="(item, index) in columns" :key="`col${index}`">
|
<template v-for="(item, index) in columns" :key="`col${index}`">
|
||||||
<div :class="[item.label, ['message', 'stack'].includes(item.label) ? 'max-item' : '']">
|
<div v-if="item.label === 'content'" class="content">
|
||||||
|
<Selector
|
||||||
|
:options="[
|
||||||
|
{ label: 'Content', value: 'content' },
|
||||||
|
{ label: 'Timestamp - Content', value: 'contentTimestamp' },
|
||||||
|
]"
|
||||||
|
v-model="headerType"
|
||||||
|
size="small"
|
||||||
|
@change="handleHeaderType"
|
||||||
|
class="content-selector"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else :class="[item.label, ['message', 'stack'].includes(item.label) ? 'max-item' : '']">
|
||||||
{{ item.value && t(item.value) }}
|
{{ item.value && t(item.value) }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -27,11 +39,12 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<LogService
|
<LogService
|
||||||
v-for="(item, index) in tableData"
|
v-for="(item, index) in logTableData"
|
||||||
:data="item"
|
:data="item"
|
||||||
:key="'service' + index"
|
:key="'service' + index"
|
||||||
:noLink="noLink"
|
:noLink="noLink"
|
||||||
@select="setCurrentLog"
|
@select="setCurrentLog"
|
||||||
|
:config="data"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
@@ -47,28 +60,54 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
import { ServiceLogConstants, BrowserLogConstants, ServiceLogDetail } from "./data";
|
import { ServiceLogConstants, BrowserLogConstants, ServiceLogDetail } from "./data";
|
||||||
import LogBrowser from "./LogBrowser.vue";
|
import LogBrowser from "./LogBrowser.vue";
|
||||||
import LogService from "./LogService.vue";
|
import LogService from "./LogService.vue";
|
||||||
import LogDetail from "./LogDetail.vue";
|
import LogDetail from "./LogDetail.vue";
|
||||||
|
import { useLogStore } from "@/store/modules/log";
|
||||||
|
import { dateFormat } from "@/utils/dateFormat";
|
||||||
|
import type { LogItem } from "@/types/log";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
type: { type: String, default: "service" },
|
type: { type: String, default: "service" },
|
||||||
tableData: { type: Array, default: () => [] },
|
tableData: { type: Array as PropType<LogItem[]>, default: () => [] },
|
||||||
noLink: { type: Boolean, default: true },
|
noLink: { type: Boolean, default: true },
|
||||||
|
data: {
|
||||||
|
type: Object as PropType<LayoutConfig>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const currentLog = ref<any>({});
|
const logStore = useLogStore();
|
||||||
|
const currentLog = ref<LogItem>({} as LogItem);
|
||||||
const showDetail = ref<boolean>(false);
|
const showDetail = ref<boolean>(false);
|
||||||
const columns: any[] = props.type === "browser" ? BrowserLogConstants : ServiceLogConstants;
|
const columns: Record<string, string>[] = props.type === "browser" ? BrowserLogConstants : ServiceLogConstants;
|
||||||
|
const headerType = ref<string>(localStorage.getItem("log-header-type") || "content");
|
||||||
|
const logTableData = computed(() => {
|
||||||
|
const logs = props.tableData.map((item: LogItem) => ({ ...item }));
|
||||||
|
return logs.map((item: LogItem) => {
|
||||||
|
item.content =
|
||||||
|
logStore.logHeaderType === "contentTimestamp"
|
||||||
|
? `${dateFormat(item.timestamp, "YYYY-MM-DD HH:mm:ss", "UTC")} ${item.content}`
|
||||||
|
: item.content;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function setCurrentLog(log: any) {
|
function setCurrentLog(log: LogItem) {
|
||||||
showDetail.value = true;
|
showDetail.value = true;
|
||||||
currentLog.value = log;
|
currentLog.value = log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleHeaderType(param: { value: string }[]) {
|
||||||
|
localStorage.setItem("log-header-type", param[0].value);
|
||||||
|
logStore.setLogHeaderType(param[0].value);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.log {
|
.log {
|
||||||
@@ -127,6 +166,11 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.service-header div {
|
.service-header div {
|
||||||
width: 140px;
|
width: 200px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-selector {
|
||||||
|
width: 200px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -21,10 +21,7 @@ limitations under the License. -->
|
|||||||
:class="item.label"
|
:class="item.label"
|
||||||
@click="selectLog(item.label, data[item.label])"
|
@click="selectLog(item.label, data[item.label])"
|
||||||
>
|
>
|
||||||
<span v-if="item.label === 'timestamp'">
|
<span v-if="item.label === 'tags'" :class="level.toLowerCase()"> > </span>
|
||||||
{{ dateFormat(data.timestamp) }}
|
|
||||||
</span>
|
|
||||||
<span v-else-if="item.label === 'tags'" :class="level.toLowerCase()"> > </span>
|
|
||||||
<span class="blue" v-else-if="item.label === 'traceId'">
|
<span class="blue" v-else-if="item.label === 'traceId'">
|
||||||
<el-tooltip content="Trace Link" v-if="!noLink && data[item.label]">
|
<el-tooltip content="Trace Link" v-if="!noLink && data[item.label]">
|
||||||
<Icon iconName="merge" />
|
<Icon iconName="merge" />
|
||||||
@@ -36,20 +33,21 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject } from "vue";
|
import { computed, inject } from "vue";
|
||||||
|
import type { PropType } from "vue";
|
||||||
import { ServiceLogConstants } from "./data";
|
import { ServiceLogConstants } from "./data";
|
||||||
import getDashboard from "@/hooks/useDashboardsSession";
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import type { LayoutConfig, DashboardItem } from "@/types/dashboard";
|
import type { LayoutConfig, DashboardItem } from "@/types/dashboard";
|
||||||
import { dateFormat } from "@/utils/dateFormat";
|
|
||||||
import { WidgetType } from "@/views/dashboard/data";
|
import { WidgetType } from "@/views/dashboard/data";
|
||||||
import { useLogStore } from "@/store/modules/log";
|
import { useLogStore } from "@/store/modules/log";
|
||||||
const logStore = useLogStore();
|
|
||||||
|
|
||||||
/*global defineProps, defineEmits */
|
/*global defineProps, defineEmits */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: { type: Object as any, default: () => ({}) },
|
data: { type: Object as any, default: () => ({}) },
|
||||||
noLink: { type: Boolean, default: true },
|
noLink: { type: Boolean, default: true },
|
||||||
|
config: { type: Object as PropType<LayoutConfig>, default: () => ({}) },
|
||||||
});
|
});
|
||||||
|
const logStore = useLogStore();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const options: LayoutConfig | null = inject("options") || null;
|
const options: LayoutConfig | null = inject("options") || null;
|
||||||
const emit = defineEmits(["select"]);
|
const emit = defineEmits(["select"]);
|
||||||
@@ -60,10 +58,10 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
return (props.data.tags.find((d: { key: string; value: string }) => d.key === "level") || {}).value || "";
|
return (props.data.tags.find((d: { key: string; value: string }) => d.key === "level") || {}).value || "";
|
||||||
});
|
});
|
||||||
const highlightKeywords = (data: string) => {
|
const highlightKeywords = (content: string) => {
|
||||||
const keywords = Object.values(logStore.conditions.keywordsOfContent || {});
|
const keywords = Object.values(logStore.conditions.keywordsOfContent || {});
|
||||||
const regex = new RegExp(keywords.join("|"), "gi");
|
const regex = new RegExp(keywords.join("|"), "gi");
|
||||||
return data.replace(regex, (match) => `<span style="color: red">${match}</span>`);
|
return `${content}`.replace(regex, (match) => `<span style="color: red">${match}</span>`);
|
||||||
};
|
};
|
||||||
|
|
||||||
function selectLog(label: string, value: string) {
|
function selectLog(label: string, value: string) {
|
||||||
|
@@ -26,7 +26,7 @@ export const ServiceLogConstants = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "content",
|
label: "content",
|
||||||
value: "content",
|
value: "contentTimestamp",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
export const ServiceLogDetail = [
|
export const ServiceLogDetail = [
|
||||||
|
@@ -354,7 +354,7 @@ limitations under the License. -->
|
|||||||
|
|
||||||
.search-btn {
|
.search-btn {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 120px;
|
width: 80px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
|
Reference in New Issue
Block a user