Merge branch 'master' of https://github.com/apache/dubbo-kubernetes
diff --git a/ui-vue3/src/api/mock/mockApp.ts b/ui-vue3/src/api/mock/mockApp.ts
index 9a01e18..821f144 100644
--- a/ui-vue3/src/api/mock/mockApp.ts
+++ b/ui-vue3/src/api/mock/mockApp.ts
@@ -22,7 +22,7 @@
return {
code: 200,
message: 'success',
- data: 'http://101.201.225.179:3000/d/a0b114ca-edf7-4dfe-ac2c-34a4fc545fed/application?orgId=1&refresh=1m&from=1710644821536&to=1710731221536&theme=light'
+ data: 'http://8.147.104.101:3000/d/a0b114ca-edf7-4dfe-ac2c-34a4fc545fed/application?orgId=1&refresh=1m&from=1711855893859&to=1711877493859&theme=light'
}
})
@@ -136,3 +136,22 @@
}
}
})
+
+Mock.mock('/mock/application/event', 'get', () => {
+ let list = Mock.mock({
+ 'list|10': [
+ {
+ desc: `Scaled down replica set shop-detail-v1-5847b7cdfd to @integer(3,10) from @integer(3,10)`,
+ time: '@DATETIME("yyyy-MM-dd HH:mm:ss")',
+ type: 'deployment-controller'
+ }
+ ]
+ })
+ return {
+ code: 200,
+ message: 'success',
+ data: {
+ ...list
+ }
+ }
+})
diff --git a/ui-vue3/src/api/mock/mockDestinationRule.ts b/ui-vue3/src/api/mock/mockDestinationRule.ts
new file mode 100644
index 0000000..4206b29
--- /dev/null
+++ b/ui-vue3/src/api/mock/mockDestinationRule.ts
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Mock from 'mockjs'
+
+Mock.mock('/mock/destinationRule/search', 'get', () => {
+ const total = Mock.mock('@integer(8, 1000)')
+ const list = []
+ for (let i = 0; i < total; i++) {
+ list.push({
+ ruleName: 'app_' + Mock.mock('@string(2,10)'),
+ createTime: Mock.mock('@datetime')
+ })
+ }
+ return {
+ code: 200,
+ message: 'success',
+ data: Mock.mock({
+ total: total,
+ curPage: 1,
+ pageSize: 10,
+ data: list
+ })
+ }
+})
diff --git a/ui-vue3/src/api/mock/mockDynamicConfig.ts b/ui-vue3/src/api/mock/mockDynamicConfig.ts
new file mode 100644
index 0000000..879df89
--- /dev/null
+++ b/ui-vue3/src/api/mock/mockDynamicConfig.ts
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Mock from 'mockjs'
+
+Mock.mock('/mock/dynamicConfig/search', 'get', () => {
+ const total = Mock.mock('@integer(8, 1000)')
+ const list = []
+ for (let i = 0; i < total; i++) {
+ list.push({
+ ruleName: 'app_' + Mock.mock('@string(2,10)'),
+ ruleGranularity: Mock.mock('@boolean'),
+ enable: Mock.mock('@boolean'),
+ createTime: Mock.mock('@datetime')
+ })
+ }
+ return {
+ code: 200,
+ message: 'success',
+ data: Mock.mock({
+ total: total,
+ curPage: 1,
+ pageSize: 10,
+ data: list
+ })
+ }
+})
diff --git a/ui-vue3/src/api/mock/mockRoutingRule.ts b/ui-vue3/src/api/mock/mockRoutingRule.ts
index bd352da..e9fe0b5 100644
--- a/ui-vue3/src/api/mock/mockRoutingRule.ts
+++ b/ui-vue3/src/api/mock/mockRoutingRule.ts
@@ -23,10 +23,9 @@
for (let i = 0; i < total; i++) {
list.push({
ruleName: 'app_' + Mock.mock('@string(2,10)'),
- ruleGranularity: Mock.mock('@integer(80, 200)'),
+ ruleGranularity: Mock.mock('@boolean'),
enable: Mock.mock('@boolean'),
- effectiveTime: Mock.mock('@datetime'),
- protection: Mock.mock('@boolean')
+ createTime: Mock.mock('@datetime')
})
}
return {
diff --git a/ui-vue3/src/api/mock/mockTagRule.ts b/ui-vue3/src/api/mock/mockTagRule.ts
new file mode 100644
index 0000000..6dd1984
--- /dev/null
+++ b/ui-vue3/src/api/mock/mockTagRule.ts
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Mock from 'mockjs'
+
+Mock.mock('/mock/tagRule/search', 'get', () => {
+ const total = Mock.mock('@integer(8, 1000)')
+ const list = []
+ for (let i = 0; i < total; i++) {
+ list.push({
+ ruleName: 'app_' + Mock.mock('@string(2,10)'),
+ enable: Mock.mock('@boolean'),
+ createTime: Mock.mock('@datetime')
+ })
+ }
+ return {
+ code: 200,
+ message: 'success',
+ data: Mock.mock({
+ total: total,
+ curPage: 1,
+ pageSize: 10,
+ data: list
+ })
+ }
+})
diff --git a/ui-vue3/src/api/mock/mockVirtualService.ts b/ui-vue3/src/api/mock/mockVirtualService.ts
new file mode 100644
index 0000000..5469277
--- /dev/null
+++ b/ui-vue3/src/api/mock/mockVirtualService.ts
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import Mock from 'mockjs'
+
+Mock.mock('/mock/virtualService/search', 'get', () => {
+ const total = Mock.mock('@integer(8, 1000)')
+ const list = []
+ for (let i = 0; i < total; i++) {
+ list.push({
+ ruleName: 'app_' + Mock.mock('@string(2,10)'),
+ createTime: Mock.mock('@datetime'),
+ lastModifiedTime: Mock.mock('@datetime')
+ })
+ }
+ return {
+ code: 200,
+ message: 'success',
+ data: Mock.mock({
+ total: total,
+ curPage: 1,
+ pageSize: 10,
+ data: list
+ })
+ }
+})
diff --git a/ui-vue3/src/api/service/app.ts b/ui-vue3/src/api/service/app.ts
index 44c32a7..6bc08ae 100644
--- a/ui-vue3/src/api/service/app.ts
+++ b/ui-vue3/src/api/service/app.ts
@@ -54,3 +54,10 @@
params
})
}
+export const listApplicationEvent = (params: any): Promise<any> => {
+ return request({
+ url: '/application/event',
+ method: 'get',
+ params
+ })
+}
diff --git a/ui-vue3/src/api/service/metricInfo.ts b/ui-vue3/src/api/service/metricInfo.ts
new file mode 100644
index 0000000..3cf499f
--- /dev/null
+++ b/ui-vue3/src/api/service/metricInfo.ts
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import request from '@/base/http/request'
+
+export const queryPromSql = (params: any): Promise<any> => {
+ return request({
+ url: 'http://123.56.255.156:9090/api/v1/query',
+ method: 'get',
+ params
+ })
+}
diff --git a/ui-vue3/src/api/service/traffic.ts b/ui-vue3/src/api/service/traffic.ts
index 380f230..24f97d6 100644
--- a/ui-vue3/src/api/service/traffic.ts
+++ b/ui-vue3/src/api/service/traffic.ts
@@ -24,3 +24,35 @@
params
})
}
+
+export const searchTagRule = (params: any): Promise<any> => {
+ return request({
+ url: '/tagRule/search',
+ method: 'get',
+ params
+ })
+}
+
+export const searchDynamicConfig = (params: any): Promise<any> => {
+ return request({
+ url: '/dynamicConfig/search',
+ method: 'get',
+ params
+ })
+}
+
+export const searchVirtualService = (params: any): Promise<any> => {
+ return request({
+ url: '/virtualService/search',
+ method: 'get',
+ params
+ })
+}
+
+export const searchDestinationRule = (params: any): Promise<any> => {
+ return request({
+ url: '/destinationRule/search',
+ method: 'get',
+ params
+ })
+}
diff --git a/ui-vue3/src/base/constants.ts b/ui-vue3/src/base/constants.ts
index 08aa943..5fbe6ff 100644
--- a/ui-vue3/src/base/constants.ts
+++ b/ui-vue3/src/base/constants.ts
@@ -15,8 +15,12 @@
* limitations under the License.
*/
+import type { Component } from 'vue'
import { computed, h, reactive, ref } from 'vue'
+import type { RouteRecordType } from '@/router/defaultRoutes'
+import type { RouteLocationNormalizedLoaded } from 'vue-router'
+// 2aacb8
export const PRIMARY_COLOR_DEFAULT = '#17b392'
export const LOCAL_STORAGE_LOCALE = 'LOCAL_STORAGE_LOCALE'
@@ -31,13 +35,17 @@
HEALTHY: 'green'
}
-export const TAB_HEADER_TITLE_VNODE = reactive({
- vnode: h('div', 'something')
-})
-export const TAB_HEADER_TITLE = {
+export const TAB_HEADER_TITLE: Component = {
functional: true,
- render: () => {
- return TAB_HEADER_TITLE_VNODE.vnode
+ props: ['route'],
+ render: (
+ a: any,
+ b: any,
+ c: { [key: string]: RouteRecordType & RouteLocationNormalizedLoaded }
+ ) => {
+ let route = c.route
+ let header: any = route.meta?.slots?.header
+ return h(header) || h('div', route.params?.pathId)
// console.log(h)
// return h("div", "foo")
}
diff --git a/ui-vue3/src/base/i18n/en.ts b/ui-vue3/src/base/i18n/en.ts
index c95132c..03deca7 100644
--- a/ui-vue3/src/base/i18n/en.ts
+++ b/ui-vue3/src/base/i18n/en.ts
@@ -332,6 +332,8 @@
editMockRule: 'Edit Mock Rule',
deleteRuleTitle: 'Are you sure to delete this mock rule?',
+ createTime: 'Create Time',
+ lastModifiedTime: 'Last Modified Time',
trafficTimeout: 'Timeout',
trafficRetry: 'Retry',
trafficRegion: 'Region Aware',
diff --git a/ui-vue3/src/base/i18n/zh.ts b/ui-vue3/src/base/i18n/zh.ts
index aa36396..8428a8c 100644
--- a/ui-vue3/src/base/i18n/zh.ts
+++ b/ui-vue3/src/base/i18n/zh.ts
@@ -291,7 +291,8 @@
ruleName: '规则名',
ruleGranularity: '规则粒度',
- effectiveTime: '生效时间',
+ createTime: '创建时间',
+ lastModifiedTime: '最后修改时间',
enable: '是否启用',
protection: '容错保护',
trafficTimeout: '超时时间',
diff --git a/ui-vue3/src/components/ConfigPage.vue b/ui-vue3/src/components/ConfigPage.vue
index 2fb3c0a..4a535ac 100644
--- a/ui-vue3/src/components/ConfigPage.vue
+++ b/ui-vue3/src/components/ConfigPage.vue
@@ -49,6 +49,11 @@
<a-card>
<template #title>
{{ $t(currentOption.title) }}
+ <div v-if="currentOption?.ext" style="float: right">
+ <a-button type="primary" @click="currentOption?.ext?.fun">{{
+ currentOption?.ext?.title
+ }}</a-button>
+ </div>
</template>
<a-spin :spinning="waitResponse">
<a-form
@@ -60,7 +65,7 @@
layout="horizontal"
>
<slot :name="'form_' + currentOption.key" :current="currentOption"></slot>
- <a-form-item style="margin-left: 100px">
+ <a-form-item style="margin: 20px 0 0 100px">
<a-button type="primary" @click="submit">{{ $t('submit') }}</a-button>
<a-button style="margin-left: 10px" @click="reset">{{ $t('reset') }}</a-button>
</a-form-item>
@@ -108,7 +113,7 @@
waitResponse.value = false
})
- let cur = currentOption.value
+ let cur = props.options.list[props.options.current[0]]
await cur.submit(cur.form).catch((e: any) => {
message.error('submit failed [server error]: ' + e)
})
diff --git a/ui-vue3/src/components/SearchTable.vue b/ui-vue3/src/components/SearchTable.vue
index db40551..7a6d4bf 100644
--- a/ui-vue3/src/components/SearchTable.vue
+++ b/ui-vue3/src/components/SearchTable.vue
@@ -68,26 +68,27 @@
</a-form>
</a-col>
<a-col :span="4">
- <div class="common-tool">
- <a-dropdown placement="bottom" :trigger="['click']">
- <div class="custom-column button">
- <Icon icon="material-symbols-light:format-list-bulleted-rounded"></Icon>
- </div>
-
- <template #overlay>
- <a-card title="Custom Column">
- <a-menu>
- <a-menu-item>
- <Icon
- style="margin-bottom: -3px; font-size: 1rem"
- icon="material-symbols-light:format-list-bulleted-rounded"
- ></Icon>
- 3
- </a-menu-item>
- </a-menu>
- </a-card>
- </template>
- </a-dropdown>
+ <div class="common-tool" @click="commonTool.customColumns = !commonTool.customColumns">
+ <div class="custom-column button">
+ <Icon icon="material-symbols-light:format-list-bulleted-rounded"></Icon>
+ </div>
+ <div class="dropdown" v-show="commonTool.customColumns">
+ <a-card style="max-width: 300px" title="Custom Column">
+ <div class="body">
+ <div
+ class="item"
+ @click.stop="hideColumn(item)"
+ v-for="(item, i) in searchDomain?.table.columns"
+ >
+ <Icon
+ style="margin-bottom: -4px; font-size: 1rem; margin-right: 2px"
+ :icon="item.__hide ? 'zondicons:view-hide' : 'zondicons:view-show'"
+ ></Icon>
+ {{ item.title }}
+ </div>
+ </div>
+ </a-card>
+ </div>
</div>
</a-col>
</a-row>
@@ -102,7 +103,7 @@
y: searchDomain.tableStyle?.scrollY || '',
x: searchDomain.tableStyle?.scrollX || ''
}"
- :columns="searchDomain?.table.columns"
+ :columns="searchDomain?.table.columns.filter((x: any) => !x.__hide)"
:data-source="searchDomain?.result"
@change="handleTableChange"
>
@@ -131,6 +132,7 @@
import type { SearchDomain } from '@/utils/SearchUtil'
import { Icon } from '@iconify/vue'
import { PRIMARY_COLOR } from '@/base/constants'
+import { message } from 'ant-design-vue'
const commonTool = reactive({
customColumns: false
@@ -150,8 +152,10 @@
column.title = computed(() => globalProperties.$t(tmp))
}
})
-const pagination = computed(() => {
- console.log(pagination)
+const pagination: any = computed(() => {
+ if (searchDomain.noPaged) {
+ return false
+ }
return {
pageSize: searchDomain.paged.pageSize,
current: searchDomain.paged.curPage,
@@ -174,6 +178,14 @@
searchDomain.onSearch()
return
}
+function hideColumn(item: any) {
+ let filter = searchDomain?.table.columns.filter((x: any) => !x.__hide)
+ if (!item.__hide && filter.length <= 1) {
+ message.warn('must show at least one column')
+ return
+ }
+ item.__hide = !item.__hide
+}
</script>
<style lang="less" scoped>
.__container_search_table {
@@ -197,13 +209,11 @@
background: #fafafa;
}
- :deep(.ant-popover-arrow) {
- display: none;
- }
-
.common-tool {
margin-top: 5px;
-
+ width: 200px;
+ cursor: pointer;
+ position: relative;
.button {
vertical-align: center;
line-height: 24px;
@@ -218,6 +228,24 @@
margin-left: 10px;
}
}
+ .dropdown {
+ top: 40px;
+ right: -40px;
+ position: absolute;
+ height: auto;
+ z-index: 1000;
+ .body {
+ max-height: 200px;
+ overflow: auto;
+ }
+
+ .item {
+ line-height: 30px;
+ &:hover {
+ color: v-bind('PRIMARY_COLOR');
+ }
+ }
+ }
}
}
</style>
diff --git a/ui-vue3/src/layout/index.vue b/ui-vue3/src/layout/index.vue
index 06f9199..82be705 100644
--- a/ui-vue3/src/layout/index.vue
+++ b/ui-vue3/src/layout/index.vue
@@ -70,10 +70,12 @@
transitionFlag.value = true
}, 500)
})
-TAB_HEADER_TITLE_VNODE.vnode = h('div', route.params?.pathId)
</script>
<style lang="less" scoped>
.__container_layout_index {
+ :deep(.ant-layout-content) {
+ padding: 16px !important;
+ }
.logo {
height: 40px;
width: auto;
diff --git a/ui-vue3/src/layout/tab/layout_tab.vue b/ui-vue3/src/layout/tab/layout_tab.vue
index 45f5e11..33bc6c0 100644
--- a/ui-vue3/src/layout/tab/layout_tab.vue
+++ b/ui-vue3/src/layout/tab/layout_tab.vue
@@ -95,7 +95,7 @@
}
.back {
- font-size: 20px;
+ font-size: 24px;
margin-bottom: -2px;
color: v-bind('PRIMARY_COLOR');
}
diff --git a/ui-vue3/src/router/RouterMeta.ts b/ui-vue3/src/router/RouterMeta.ts
index f3a407b..0950b87 100644
--- a/ui-vue3/src/router/RouterMeta.ts
+++ b/ui-vue3/src/router/RouterMeta.ts
@@ -16,6 +16,7 @@
*/
import type { RouteMeta } from 'vue-router'
import type { RouteRecordType } from '@/router/defaultRoutes'
+import type { Component } from 'vue'
export interface RouterMeta extends RouteMeta {
icon?: string
@@ -25,4 +26,5 @@
tab?: boolean
_router_key?: string
parent?: RouteRecordType
+ slots?: { [key: string]: Component }
}
diff --git a/ui-vue3/src/router/defaultRoutes.ts b/ui-vue3/src/router/defaultRoutes.ts
index 70884b9..d67c200 100644
--- a/ui-vue3/src/router/defaultRoutes.ts
+++ b/ui-vue3/src/router/defaultRoutes.ts
@@ -19,6 +19,7 @@
import type { RouteRecordRaw } from 'vue-router'
import LayoutTab from '../layout/tab/layout_tab.vue'
import _ from 'lodash'
+import AppTabHeaderSlot from '@/views/resources/applications/slots/AppTabHeaderSlot.vue'
export declare type RouteRecordType = RouteRecordRaw & {
key?: string
@@ -58,7 +59,10 @@
component: LayoutTab,
redirect: 'index',
meta: {
- tab_parent: true
+ tab_parent: true,
+ slots: {
+ header: AppTabHeaderSlot
+ }
},
children: [
{
@@ -290,6 +294,22 @@
name: 'dynamicConfig',
component: () => import('../views/traffic/dynamicConfig/index.vue'),
meta: {}
+ },
+ {
+ path: '/meshRule',
+ name: 'meshRule',
+ children: [
+ {
+ path: '/virtualService',
+ name: 'virtualService',
+ component: () => import('../views/traffic/virtualService/index.vue')
+ },
+ {
+ path: '/destinationRule',
+ name: 'destinationRule',
+ component: () => import('../views/traffic/destinationRule/index.vue')
+ }
+ ]
}
]
},
diff --git a/ui-vue3/src/utils/SearchUtil.ts b/ui-vue3/src/utils/SearchUtil.ts
index 31e4980..aeb39ec 100644
--- a/ui-vue3/src/utils/SearchUtil.ts
+++ b/ui-vue3/src/utils/SearchUtil.ts
@@ -22,6 +22,7 @@
export class SearchDomain {
// form of search
+ noPaged?: boolean
queryForm: any
params: [
{
@@ -43,7 +44,7 @@
tableStyle: any
table: {
loading?: boolean
- columns: TableColumnsType
+ columns: (TableColumnsType & { __hide: boolean }) | any
} = { columns: [] }
paged = {
curPage: 1,
@@ -55,9 +56,11 @@
query: any,
searchApi: any,
columns: TableColumnsType | any,
- paged?: any | undefined
+ paged?: any | undefined,
+ noPaged?: boolean
) {
this.params = query
+ this.noPaged = noPaged
this.queryForm = reactive({})
this.table.columns = columns
query.forEach((c: any) => {
diff --git a/ui-vue3/src/views/home/index.vue b/ui-vue3/src/views/home/index.vue
index 54d0a23..0d427f4 100644
--- a/ui-vue3/src/views/home/index.vue
+++ b/ui-vue3/src/views/home/index.vue
@@ -32,37 +32,43 @@
</a-flex>
</a-card>
</a-flex>
- <a-descriptions
- title=" "
- bordered
- :column="{ xxl: 2, xl: 2, lg: 2, md: 2, sm: 1, xs: 1 }"
- layout="horizontal"
- >
- <a-descriptions-item label="versions">
- <a-tag :color="PRIMARY_COLOR" v-for="v in metricsMetadata.info.versions">{{ v }}</a-tag>
- </a-descriptions-item>
- <a-descriptions-item label="protocols">
- <a-tag :color="PRIMARY_COLOR" v-for="v in metricsMetadata.info.protocols">{{ v }}</a-tag>
- </a-descriptions-item>
- <a-descriptions-item label="configCenter">{{
- metricsMetadata.info.configCenter
- }}</a-descriptions-item>
- <a-descriptions-item label="registry">{{
- metricsMetadata.info.registry
- }}</a-descriptions-item>
- <a-descriptions-item label="metadataCenter">{{
- metricsMetadata.info.metadataCenter
- }}</a-descriptions-item>
- <a-descriptions-item label="grafana">{{ metricsMetadata.info.grafana }}</a-descriptions-item>
- <a-descriptions-item label="prometheus">{{
- metricsMetadata.info.prometheus
- }}</a-descriptions-item>
- <a-descriptions-item label="Remark">empty</a-descriptions-item>
- <a-descriptions-item label="rules">
- <a-tag :color="PRIMARY_COLOR" v-for="v in metricsMetadata.info.rules">{{ v }}</a-tag>
- </a-descriptions-item>
- </a-descriptions>
- <div id="report_container"></div>
+ <a-card class="card">
+ <a-descriptions
+ title=" "
+ bordered
+ :column="{ xxl: 2, xl: 2, lg: 2, md: 2, sm: 1, xs: 1 }"
+ layout="horizontal"
+ >
+ <a-descriptions-item label="versions">
+ <a-tag :color="PRIMARY_COLOR" v-for="v in metricsMetadata.info.versions">{{ v }}</a-tag>
+ </a-descriptions-item>
+ <a-descriptions-item label="protocols">
+ <a-tag :color="PRIMARY_COLOR" v-for="v in metricsMetadata.info.protocols">{{ v }}</a-tag>
+ </a-descriptions-item>
+ <a-descriptions-item label="configCenter">{{
+ metricsMetadata.info.configCenter
+ }}</a-descriptions-item>
+ <a-descriptions-item label="registry">{{
+ metricsMetadata.info.registry
+ }}</a-descriptions-item>
+ <a-descriptions-item label="metadataCenter">{{
+ metricsMetadata.info.metadataCenter
+ }}</a-descriptions-item>
+ <a-descriptions-item label="grafana">{{
+ metricsMetadata.info.grafana
+ }}</a-descriptions-item>
+ <a-descriptions-item label="prometheus">{{
+ metricsMetadata.info.prometheus
+ }}</a-descriptions-item>
+ <a-descriptions-item label="Remark">empty</a-descriptions-item>
+ <a-descriptions-item label="rules">
+ <a-tag :color="PRIMARY_COLOR" v-for="v in metricsMetadata.info.rules">{{ v }}</a-tag>
+ </a-descriptions-item>
+ </a-descriptions>
+ </a-card>
+ <a-card class="card">
+ <div id="report_container"></div>
+ </a-card>
</div>
</template>
@@ -74,6 +80,7 @@
import { getMetricsMetadata } from '@/api/service/serverInfo'
import { useRoute } from 'vue-router'
import { Chart } from '@antv/g2'
+import { queryPromSql } from '@/api/service/metricInfo'
let __null = PRIMARY_COLOR
@@ -88,6 +95,12 @@
})
onMounted(async () => {
+ console.log(
+ await queryPromSql({
+ query:
+ '((node_memory_MemTotal_bytes - node_memory_MemFree_bytes - node_memory_Buffers_bytes - node_memory_Cached_bytes) / (node_memory_MemTotal_bytes)) * 100'
+ })
+ )
let clusterData = (await getClusterInfo({})).data
metricsMetadata.info = <{ [key: string]: string }>(await getMetricsMetadata({})).data
clusterInfo.info = <{ [key: string]: string }>clusterData
@@ -165,5 +178,8 @@
font-size: 20px;
color: white;
}
+ .card {
+ margin-top: 10px;
+ }
}
</style>
diff --git a/ui-vue3/src/views/resources/applications/index.vue b/ui-vue3/src/views/resources/applications/index.vue
index a0f3808..e23b0d9 100644
--- a/ui-vue3/src/views/resources/applications/index.vue
+++ b/ui-vue3/src/views/resources/applications/index.vue
@@ -19,7 +19,7 @@
<search-table :search-domain="searchDomain">
<template #bodyCell="{ text, record, index, column }">
<template v-if="column.dataIndex === 'registerClusters'">
- <a-tag v-for="t in text" color="grey">
+ <a-tag v-for="t in text">
{{ t }}
</a-tag>
</template>
diff --git a/ui-vue3/src/views/resources/applications/slots/AppTabHeaderSlot.vue b/ui-vue3/src/views/resources/applications/slots/AppTabHeaderSlot.vue
new file mode 100644
index 0000000..8c92eeb
--- /dev/null
+++ b/ui-vue3/src/views/resources/applications/slots/AppTabHeaderSlot.vue
@@ -0,0 +1,44 @@
+<!--
+ ~ 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>
+ <!-- example like blow-->
+ <div class="__container_AppTabHeaderSlot">
+ <a-row>
+ <a-col :span="12">
+ <span class="header-desc"
+ >{{ $t('applicationDomain.name') }}: {{ route.params?.pathId }}</span
+ >
+ </a-col>
+ <!-- <a-col :span="12">-->
+ <!-- <a-button>custom function</a-button>-->
+ <!-- </a-col>-->
+ </a-row>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { useRoute } from 'vue-router'
+const route = useRoute()
+</script>
+<style lang="less" scoped>
+.__container_AppTabHeaderSlot {
+ .header-desc {
+ line-height: 30px;
+ vertical-align: center;
+ }
+}
+</style>
diff --git a/ui-vue3/src/views/resources/applications/tabs/config.vue b/ui-vue3/src/views/resources/applications/tabs/config.vue
index 080cbc1..149e972 100644
--- a/ui-vue3/src/views/resources/applications/tabs/config.vue
+++ b/ui-vue3/src/views/resources/applications/tabs/config.vue
@@ -22,15 +22,135 @@
<a-switch v-model:checked="current.form.logFlag"></a-switch>
</a-form-item>
</template>
- <template v-slot:form_flow="{ current }"> 2 </template>
- <template v-slot:form_gray="{ current }"> 3 </template>
+ <template v-slot:form_flow="{ current }">
+ <a-space>
+ <a-card v-for="(item, i) in current.form.rules">
+ <template #title>
+ {{ $t('applicationDomain.flowWeight') }} {{ i + 1 }}
+ <div style="float: right">
+ <a-space>
+ <a-button type="dashed" @click="">
+ <Icon
+ style="font-size: 20px"
+ icon="material-symbols-light:contract-edit"
+ ></Icon>
+ </a-button>
+ <a-button danger type="dashed" @click="">
+ <Icon style="font-size: 20px" icon="fluent:delete-12-filled"></Icon>
+ </a-button>
+ </a-space>
+ </div>
+ </template>
+
+ <a-form-item :name="'rules[' + i + '].weight'" label="权重">
+ <a-input-number v-model:value="item.weight"></a-input-number>
+ </a-form-item>
+ <a-form-item label="作用范围">
+ <a-table
+ style="width: 40vw"
+ :pagination="false"
+ :columns="[
+ { key: 'label', title: 'label' },
+ { key: 'condition', title: 'condition' },
+ { key: 'value', title: 'value' }
+ ]"
+ :data-source="[item.scope]"
+ >
+ <template #bodyCell="{ column, record, index }">
+ <a-form-item
+ v-if="column.key === 'condition'"
+ :name="'rules[' + i + '].scope.condition'"
+ label=""
+ >
+ <a-select v-model:value="item.scope.condition">
+ <a-select-option value="=">=</a-select-option>
+ <a-select-option value="!=">!=</a-select-option>
+ <a-select-option value=">">></a-select-option>
+ <a-select-option value="<">{{ '<' }}</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item
+ v-else
+ :name="'rules[' + i + '].scope.condition.' + column.key"
+ label=""
+ >
+ <a-input v-model:value="item.scope[column.key]"></a-input>
+ </a-form-item>
+ </template>
+ </a-table>
+ </a-form-item>
+ </a-card>
+ </a-space>
+ </template>
+ <template v-slot:form_gray="{ current }">
+ <a-space>
+ <a-card v-for="(item, i) in current.form.rules">
+ <template #title>
+ {{ $t('applicationDomain.gray') }} {{ i + 1 }}
+ <div style="float: right">
+ <a-space>
+ <a-button type="dashed" @click="">
+ <Icon
+ style="font-size: 20px"
+ icon="material-symbols-light:contract-edit"
+ ></Icon>
+ </a-button>
+ <a-button danger type="dashed" @click="">
+ <Icon style="font-size: 20px" icon="fluent:delete-12-filled"></Icon>
+ </a-button>
+ </a-space>
+ </div>
+ </template>
+
+ <a-form-item :name="'rules[' + i + '].name'" label="环境名称">
+ <a-input v-model:value="item.name"></a-input>
+ </a-form-item>
+ <a-form-item label="作用范围">
+ <a-table
+ style="width: 40vw"
+ :pagination="false"
+ :columns="[
+ { key: 'label', title: 'label' },
+ { key: 'condition', title: 'condition' },
+ { key: 'value', title: 'value' }
+ ]"
+ :data-source="[item.scope]"
+ >
+ <template #bodyCell="{ column, record, index }">
+ <a-form-item
+ v-if="column.key === 'condition'"
+ :name="'rules[' + i + '].scope.condition'"
+ label=""
+ >
+ <a-select v-model:value="item.scope.condition">
+ <a-select-option value="=">=</a-select-option>
+ <a-select-option value="!=">!=</a-select-option>
+ <a-select-option value=">">></a-select-option>
+ <a-select-option value="<">{{ '<' }}</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item
+ v-else
+ :name="'rules[' + i + '].scope.condition.' + column.key"
+ label=""
+ >
+ <a-input v-model:value="item.scope[column.key]"></a-input>
+ </a-form-item>
+ </template>
+ </a-table>
+ </a-form-item>
+ </a-card>
+ </a-space>
+ </template>
</config-page>
</div>
</template>
<script setup lang="ts">
-import { onMounted, reactive, ref } from 'vue'
+import { onMounted, reactive } from 'vue'
import ConfigPage from '@/components/ConfigPage.vue'
+import { Icon } from '@iconify/vue'
+
let options: any = reactive({
list: [
{
@@ -52,18 +172,57 @@
},
{
title: 'applicationDomain.flowWeight',
- form: {},
key: 'flow',
+ ext: {
+ title: '添加权重配置',
+ fun() {}
+ },
+ form: {
+ rules: [
+ {
+ weight: '100',
+ scope: {
+ label: 'key1',
+ condition: '=',
+ value: 'value1'
+ }
+ }
+ ]
+ },
submit(form: {}) {
- console.log(form)
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(1)
+ }, 1000)
+ })
}
},
+
{
title: 'applicationDomain.gray',
- form: {},
key: 'gray',
+ ext: {
+ title: '添加灰度环境',
+ fun() {}
+ },
+ form: {
+ rules: [
+ {
+ name: '100',
+ scope: {
+ label: 'key1',
+ condition: '=',
+ value: 'value1'
+ }
+ }
+ ]
+ },
submit(form: {}) {
- console.log(form)
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(1)
+ }, 1000)
+ })
}
}
],
diff --git a/ui-vue3/src/views/resources/applications/tabs/event.vue b/ui-vue3/src/views/resources/applications/tabs/event.vue
index f584d4a..a91a2d2 100644
--- a/ui-vue3/src/views/resources/applications/tabs/event.vue
+++ b/ui-vue3/src/views/resources/applications/tabs/event.vue
@@ -15,14 +15,142 @@
~ limitations under the License.
-->
<template>
- <div class="__container_app_event">Event</div>
+ <div class="__container_app_event">
+ <a-timeline mode="left">
+ <a-timeline-item v-for="(item, i) in events.list">
+ <div class="box">
+ <div class="label" :class="{ yellow: i === 0 }">
+ <div class="type"></div>
+ <div class="body">
+ <b class="title">{{ item.type }}</b>
+ <p>{{ item.desc }}</p>
+ </div>
+ </div>
+ <span class="time">
+ {{ item.time }}
+ </span>
+ </div>
+ <template v-if="i === 0" #dot>
+ <clock-circle-outlined style="font-size: 16px; color: red" />
+ </template>
+
+ <!-- <a-card>-->
+ <!-- <a-row>-->
+ <!-- <a-col :span="4">-->
+ <!--<!– <div class="box">–>-->
+ <!--<!– <div class="type"></div>–>-->
+ <!--<!– <div class="body"></div>–>-->
+ <!--<!– </div>–>-->
+ <!-- </a-col>-->
+ <!-- <a-col :span="10">{{item.desc}}</a-col>-->
+ <!-- </a-row>-->
+ <!-- </a-card>-->
+ </a-timeline-item>
+ </a-timeline>
+ </div>
</template>
<script setup lang="ts">
-import { onMounted } from 'vue'
+import { onMounted, reactive } from 'vue'
+import { listApplicationEvent } from '@/api/service/app'
+import { ClockCircleOutlined } from '@ant-design/icons-vue'
+import { PRIMARY_COLOR } from '@/base/constants'
-onMounted(() => {
- console.log(333)
+let __ = PRIMARY_COLOR
+let events: any = reactive({ list: [] })
+onMounted(async () => {
+ let eventsRes = await listApplicationEvent({})
+ events.list = eventsRes.data.list
+ console.log(events)
})
</script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.__container_app_event {
+ :deep(.ant-timeline-item-label) {
+ width: 200px;
+ }
+
+ background: #fafafa;
+ border-radius: 10px;
+ padding: 80px 300px 20px;
+
+ .box {
+ position: relative;
+ height: 100px;
+ margin-bottom: 20px;
+ //top:-38px;
+
+ .label {
+ position: absolute;
+ height: 100px;
+ top: -40px;
+
+ &.yellow {
+ .type {
+ border-right-color: #f8d347;
+ }
+ .body {
+ background: #f8d347;
+ }
+ }
+ &.red {
+ .type {
+ border-right-color: #eb4325;
+ }
+ .body {
+ background: #eb4325;
+ }
+ }
+ &.blue {
+ .type {
+ border-right-color: #3d89f6;
+ }
+ .body {
+ background: #3d89f6;
+ }
+ }
+ &.green {
+ .type {
+ border-right-color: #9cac35;
+ }
+ .body {
+ background: #9cac35;
+ }
+ }
+ .type {
+ position: absolute;
+ width: 50px;
+ height: 50px;
+ border-style: solid;
+ border-color: transparent;
+ border-width: 50px 26px 50px 0px;
+ border-right-color: v-bind('PRIMARY_COLOR');
+ display: inline;
+ border-radius: 4px;
+ }
+ .body {
+ position: absolute;
+ left: 49px;
+ width: 50vw;
+ border-radius: 3px 5px 5px 3px;
+ height: 100%;
+ display: inline;
+ color: white;
+ padding-left: 20px;
+ background: v-bind('PRIMARY_COLOR');
+ box-shadow: 8px 5px 10px #9f9c9c;
+
+ .title {
+ font-size: 30px;
+ line-height: 40px;
+ }
+ }
+ }
+ .time {
+ position: absolute;
+ left: -200px;
+ //top: 38px;
+ }
+ }
+}
+</style>
diff --git a/ui-vue3/src/views/resources/applications/tabs/instance.vue b/ui-vue3/src/views/resources/applications/tabs/instance.vue
index 3ca62cf..7d7f9ac 100644
--- a/ui-vue3/src/views/resources/applications/tabs/instance.vue
+++ b/ui-vue3/src/views/resources/applications/tabs/instance.vue
@@ -40,9 +40,9 @@
<a-tag :color="INSTANCE_DEPLOY_COLOR[text.toUpperCase()]">{{ text }}</a-tag>
</template>
<template v-if="column.dataIndex === 'registerStates'">
- <a-tag :color="INSTANCE_REGISTER_COLOR[t.level.toUpperCase()]" v-for="t in text">{{
- t.label
- }}</a-tag>
+ <a-tag :color="INSTANCE_REGISTER_COLOR[t.level.toUpperCase()]" v-for="t in text"
+ >{{ t.label }}
+ </a-tag>
</template>
<template v-if="column.dataIndex === 'registerClusters'">
<a-tag v-for="t in text">{{ t }}</a-tag>
@@ -57,14 +57,10 @@
<script setup lang="ts">
import { onMounted, provide, reactive } from 'vue'
-import { getClusterInfo } from '@/api/service/clusterInfo'
-import { getMetricsMetadata } from '@/api/service/serverInfo'
-import { Chart } from '@antv/g2'
import { INSTANCE_DEPLOY_COLOR, INSTANCE_REGISTER_COLOR, PRIMARY_COLOR } from '@/base/constants'
import { Icon } from '@iconify/vue'
import SearchTable from '@/components/SearchTable.vue'
import { SearchDomain } from '@/utils/SearchUtil'
-import { searchService } from '@/api/service/service'
import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
import { useRoute, useRouter } from 'vue-router'
import { getApplicationInstanceInfo, getApplicationInstanceStatistics } from '@/api/service/app'
@@ -206,13 +202,15 @@
],
getApplicationInstanceInfo,
columns,
- { pageSize: 4 }
+ { pageSize: 4 },
+ true
)
)
onMounted(() => {
searchDomain.tableStyle = {
- scrollX: '100'
+ scrollX: '100',
+ scrollY: '500px'
}
searchDomain.onSearch()
})
diff --git a/ui-vue3/src/views/resources/applications/tabs/service.vue b/ui-vue3/src/views/resources/applications/tabs/service.vue
index 7dbd356..9841b6c 100644
--- a/ui-vue3/src/views/resources/applications/tabs/service.vue
+++ b/ui-vue3/src/views/resources/applications/tabs/service.vue
@@ -67,6 +67,10 @@
})
onMounted(async () => {
+ searchDomain.tableStyle = {
+ scrollX: '100',
+ scrollY: 'calc(100vh - 600px)'
+ }
let clusterData = (await getClusterInfo({})).data
metricsMetadata.info = <{ [key: string]: string }>(await getMetricsMetadata({})).data
clusterInfo.info = <{ [key: string]: string }>clusterData
@@ -144,7 +148,8 @@
],
searchService,
columns,
- { pageSize: 4 }
+ { pageSize: 4 },
+ true
)
)
searchDomain.onSearch()
diff --git a/ui-vue3/src/views/traffic/destinationRule/index.vue b/ui-vue3/src/views/traffic/destinationRule/index.vue
new file mode 100644
index 0000000..05b92be
--- /dev/null
+++ b/ui-vue3/src/views/traffic/destinationRule/index.vue
@@ -0,0 +1,103 @@
+<!--
+ ~ 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="__container_resources_application_index">
+ <search-table :search-domain="searchDomain">
+ <template #customOperation>
+ <a-button type="primary">新增 Destination Rule</a-button>
+ </template>
+ <template #bodyCell="{ text, column }">
+ <template v-if="column.dataIndex === 'ruleName'">
+ <a-button type="link">{{ text }}</a-button>
+ </template>
+ <template v-if="column.dataIndex === 'operation'">
+ <a-button type="link">查看</a-button>
+ <a-button type="link">修改</a-button>
+ <a-popconfirm
+ title="确认删除该动态配置?"
+ ok-text="Yes"
+ cancel-text="No"
+ @confirm="confirm"
+ >
+ <a-button type="link">删除</a-button>
+ </a-popconfirm>
+ </template>
+ </template>
+ </search-table>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, provide, reactive } from 'vue'
+import { searchDestinationRule } from '@/api/service/traffic'
+import SearchTable from '@/components/SearchTable.vue'
+import { SearchDomain, sortString } from '@/utils/SearchUtil'
+import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
+
+let columns = [
+ {
+ title: 'ruleName',
+ key: 'ruleName',
+ dataIndex: 'ruleName',
+ sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+ width: 140
+ },
+ {
+ title: 'createTime',
+ key: 'createTime',
+ dataIndex: 'createTime',
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'operation',
+ key: 'operation',
+ dataIndex: 'operation',
+ width: 200
+ }
+]
+const searchDomain = reactive(
+ new SearchDomain(
+ [
+ {
+ label: 'serviceGovernance',
+ param: 'serviceGovernance',
+ placeholder: 'typeRoutingRules',
+ style: {
+ width: '200px'
+ }
+ }
+ ],
+ searchDestinationRule,
+ columns
+ )
+)
+
+onMounted(() => {
+ searchDomain.onSearch()
+})
+
+const confirm = () => {}
+
+provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
+</script>
+<style lang="less" scoped>
+.search-table-container {
+ min-height: 60vh;
+ //max-height: 70vh; //overflow: auto;
+}
+</style>
diff --git a/ui-vue3/src/views/traffic/dynamicConfig/index.vue b/ui-vue3/src/views/traffic/dynamicConfig/index.vue
index c97d821..fbef790 100644
--- a/ui-vue3/src/views/traffic/dynamicConfig/index.vue
+++ b/ui-vue3/src/views/traffic/dynamicConfig/index.vue
@@ -15,15 +15,112 @@
~ limitations under the License.
-->
<template>
- <div class="__container_home_index">
- <h1>{{ $t(routeName) }}</h1>
+ <div class="__container_resources_application_index">
+ <search-table :search-domain="searchDomain">
+ <template #customOperation>
+ <a-button type="primary">新增动态配置</a-button>
+ <a-button type="primary" style="margin-left: 10px">从模版创建</a-button>
+ </template>
+ <template #bodyCell="{ text, column }">
+ <template v-if="column.dataIndex === 'ruleName'">
+ <a-button type="link">{{ text }}</a-button>
+ </template>
+ <template v-if="column.dataIndex === 'ruleGranularity'">
+ {{ text ? '服务' : '应用' }}
+ </template>
+ <template v-if="column.dataIndex === 'enable'">
+ {{ text ? '启用' : '禁用' }}
+ </template>
+ <template v-if="column.dataIndex === 'operation'">
+ <a-button type="link">查看</a-button>
+ <a-button type="link">修改</a-button>
+ <a-popconfirm
+ title="确认删除该动态配置?"
+ ok-text="Yes"
+ cancel-text="No"
+ @confirm="confirm"
+ >
+ <a-button type="link">删除</a-button>
+ </a-popconfirm>
+ </template>
+ </template>
+ </search-table>
</div>
</template>
<script setup lang="ts">
-import { Icon } from '@iconify/vue'
+import { onMounted, provide, reactive } from 'vue'
+import { searchDynamicConfig } from '@/api/service/traffic'
+import SearchTable from '@/components/SearchTable.vue'
+import { SearchDomain, sortString } from '@/utils/SearchUtil'
+import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
-import { useRoute } from 'vue-router'
-const routeName = <string>useRoute().name
+let columns = [
+ {
+ title: 'ruleName',
+ key: 'ruleName',
+ dataIndex: 'ruleName',
+ sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+ width: 140
+ },
+ {
+ title: 'ruleGranularity',
+ key: 'ruleGranularity',
+ dataIndex: 'ruleGranularity',
+ render: (text, record) => (record.isService ? '服务' : '应用'),
+ width: 100,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'createTime',
+ key: 'createTime',
+ dataIndex: 'createTime',
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'enable',
+ key: 'enable',
+ dataIndex: 'enable',
+ render: (text, record) => (record.enable ? '是' : '否'),
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'operation',
+ key: 'operation',
+ dataIndex: 'operation',
+ width: 200
+ }
+]
+const searchDomain = reactive(
+ new SearchDomain(
+ [
+ {
+ label: 'serviceGovernance',
+ param: 'serviceGovernance',
+ placeholder: 'typeRoutingRules',
+ style: {
+ width: '200px'
+ }
+ }
+ ],
+ searchDynamicConfig,
+ columns
+ )
+)
+
+onMounted(() => {
+ searchDomain.onSearch()
+})
+
+const confirm = () => {}
+
+provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
</script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.search-table-container {
+ min-height: 60vh;
+ //max-height: 70vh; //overflow: auto;
+}
+</style>
diff --git a/ui-vue3/src/views/traffic/routingRule/index.vue b/ui-vue3/src/views/traffic/routingRule/index.vue
index c899666..14e82ed 100644
--- a/ui-vue3/src/views/traffic/routingRule/index.vue
+++ b/ui-vue3/src/views/traffic/routingRule/index.vue
@@ -17,12 +17,30 @@
<template>
<div class="__container_resources_application_index">
<search-table :search-domain="searchDomain">
- <template #bodyCell="{ text, record, index, column }">
- <template v-if="column.dataIndex === 'enable'">
- {{ text ? '是' : '否' }}
+ <template #customOperation>
+ <a-button type="primary">新增条件路由规则</a-button>
+ </template>
+ <template #bodyCell="{ text, column }">
+ <template v-if="column.dataIndex === 'ruleName'">
+ <a-button type="link">{{ text }}</a-button>
</template>
- <template v-if="column.dataIndex === 'protection'">
- {{ text ? '是' : '否' }}
+ <template v-if="column.dataIndex === 'ruleGranularity'">
+ {{ text ? '服务' : '应用' }}
+ </template>
+ <template v-if="column.dataIndex === 'enable'">
+ {{ text ? '启用' : '禁用' }}
+ </template>
+ <template v-if="column.dataIndex === 'operation'">
+ <a-button type="link">查看</a-button>
+ <a-button type="link">修改</a-button>
+ <a-popconfirm
+ title="确认删除该条件路由规则?"
+ ok-text="Yes"
+ cancel-text="No"
+ @confirm="confirm"
+ >
+ <a-button type="link">删除</a-button>
+ </a-popconfirm>
</template>
</template>
</search-table>
@@ -48,27 +66,29 @@
title: 'ruleGranularity',
key: 'ruleGranularity',
dataIndex: 'ruleGranularity',
+ render: (text, record) => (record.isService ? '服务' : '应用'),
width: 100,
sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
},
{
+ title: 'createTime',
+ key: 'createTime',
+ dataIndex: 'createTime',
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
title: 'enable',
key: 'enable',
dataIndex: 'enable',
render: (text, record) => (record.enable ? '是' : '否'),
- width: 120
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
},
{
- title: 'effectiveTime',
- key: 'effectiveTime',
- dataIndex: 'effectiveTime',
- width: 120
- },
- {
- title: 'protection',
- key: 'protection',
- dataIndex: 'protection',
- render: (text, record) => (record.protection ? '是' : '否'),
+ title: 'operation',
+ key: 'operation',
+ dataIndex: 'operation',
width: 200
}
]
@@ -93,6 +113,8 @@
searchDomain.onSearch()
})
+const confirm = () => {}
+
provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
</script>
<style lang="less" scoped>
diff --git a/ui-vue3/src/views/traffic/tagRule/index.vue b/ui-vue3/src/views/traffic/tagRule/index.vue
index c97d821..d72618b 100644
--- a/ui-vue3/src/views/traffic/tagRule/index.vue
+++ b/ui-vue3/src/views/traffic/tagRule/index.vue
@@ -15,15 +15,100 @@
~ limitations under the License.
-->
<template>
- <div class="__container_home_index">
- <h1>{{ $t(routeName) }}</h1>
+ <div class="__container_resources_application_index">
+ <search-table :search-domain="searchDomain">
+ <template #customOperation>
+ <a-button type="primary">新增标签路由规则</a-button>
+ </template>
+ <template #bodyCell="{ text, column }">
+ <template v-if="column.dataIndex === 'ruleName'">
+ <a-button type="link">{{ text }}</a-button>
+ </template>
+ <template v-if="column.dataIndex === 'enable'">
+ {{ text ? '启用' : '禁用' }}
+ </template>
+ <template v-if="column.dataIndex === 'operation'">
+ <a-button type="link">查看</a-button>
+ <a-button type="link">修改</a-button>
+ <a-popconfirm
+ title="确认删除该标签路由规则?"
+ ok-text="Yes"
+ cancel-text="No"
+ @confirm="confirm"
+ >
+ <a-button type="link">删除</a-button>
+ </a-popconfirm>
+ </template>
+ </template>
+ </search-table>
</div>
</template>
<script setup lang="ts">
-import { Icon } from '@iconify/vue'
+import { onMounted, provide, reactive } from 'vue'
+import { searchTagRule } from '@/api/service/traffic'
+import SearchTable from '@/components/SearchTable.vue'
+import { SearchDomain, sortString } from '@/utils/SearchUtil'
+import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
-import { useRoute } from 'vue-router'
-const routeName = <string>useRoute().name
+let columns = [
+ {
+ title: 'ruleName',
+ key: 'ruleName',
+ dataIndex: 'ruleName',
+ sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+ width: 140
+ },
+ {
+ title: 'createTime',
+ key: 'createTime',
+ dataIndex: 'createTime',
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'enable',
+ key: 'enable',
+ dataIndex: 'enable',
+ render: (text, record) => (record.enable ? '是' : '否'),
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'operation',
+ key: 'operation',
+ dataIndex: 'operation',
+ width: 200
+ }
+]
+const searchDomain = reactive(
+ new SearchDomain(
+ [
+ {
+ label: 'serviceGovernance',
+ param: 'serviceGovernance',
+ placeholder: 'typeRoutingRules',
+ style: {
+ width: '200px'
+ }
+ }
+ ],
+ searchTagRule,
+ columns
+ )
+)
+
+onMounted(() => {
+ searchDomain.onSearch()
+})
+
+const confirm = () => {}
+
+provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
</script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.search-table-container {
+ min-height: 60vh;
+ //max-height: 70vh; //overflow: auto;
+}
+</style>
diff --git a/ui-vue3/src/views/traffic/virtualService/index.vue b/ui-vue3/src/views/traffic/virtualService/index.vue
new file mode 100644
index 0000000..4e1f049
--- /dev/null
+++ b/ui-vue3/src/views/traffic/virtualService/index.vue
@@ -0,0 +1,110 @@
+<!--
+ ~ 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="__container_resources_application_index">
+ <search-table :search-domain="searchDomain">
+ <template #customOperation>
+ <a-button type="primary">新增路由规则</a-button>
+ </template>
+ <template #bodyCell="{ text, column }">
+ <template v-if="column.dataIndex === 'ruleName'">
+ <a-button type="link">{{ text }}</a-button>
+ </template>
+ <template v-if="column.dataIndex === 'operation'">
+ <a-button type="link">查看</a-button>
+ <a-button type="link">修改</a-button>
+ <a-popconfirm
+ title="确认删除该动态配置?"
+ ok-text="Yes"
+ cancel-text="No"
+ @confirm="confirm"
+ >
+ <a-button type="link">删除</a-button>
+ </a-popconfirm>
+ </template>
+ </template>
+ </search-table>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, provide, reactive } from 'vue'
+import { searchVirtualService } from '@/api/service/traffic'
+import SearchTable from '@/components/SearchTable.vue'
+import { SearchDomain, sortString } from '@/utils/SearchUtil'
+import { PROVIDE_INJECT_KEY } from '@/base/enums/ProvideInject'
+
+let columns = [
+ {
+ title: 'ruleName',
+ key: 'ruleName',
+ dataIndex: 'ruleName',
+ sorter: (a: any, b: any) => sortString(a.appName, b.appName),
+ width: 140
+ },
+ {
+ title: 'createTime',
+ key: 'createTime',
+ dataIndex: 'createTime',
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'lastModifiedTime',
+ key: 'lastModifiedTime',
+ dataIndex: 'lastModifiedTime',
+ width: 120,
+ sorter: (a: any, b: any) => sortString(a.instanceNum, b.instanceNum)
+ },
+ {
+ title: 'operation',
+ key: 'operation',
+ dataIndex: 'operation',
+ width: 200
+ }
+]
+const searchDomain = reactive(
+ new SearchDomain(
+ [
+ {
+ label: 'serviceGovernance',
+ param: 'serviceGovernance',
+ placeholder: 'typeRoutingRules',
+ style: {
+ width: '200px'
+ }
+ }
+ ],
+ searchVirtualService,
+ columns
+ )
+)
+
+onMounted(() => {
+ searchDomain.onSearch()
+})
+
+const confirm = () => {}
+
+provide(PROVIDE_INJECT_KEY.SEARCH_DOMAIN, searchDomain)
+</script>
+<style lang="less" scoped>
+.search-table-container {
+ min-height: 60vh;
+ //max-height: 70vh; //overflow: auto;
+}
+</style>