This is an automated email from the ASF dual-hosted git repository.
nicholasjiang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-celeborn.git
The following commit(s) were added to refs/heads/main by this push:
new 22c70124e [CELEBORN-1307][FOLLOWUP] Introduce worker detail module for
dashboard frontend
22c70124e is described below
commit 22c70124e973ff2a7852e3f638fa23abbe973699
Author: tiny-dust <[email protected]>
AuthorDate: Thu Mar 14 17:35:36 2024 +0800
[CELEBORN-1307][FOLLOWUP] Introduce worker detail module for dashboard
frontend
### What changes were proposed in this pull request?
Introduce worker detail module for dashboard frontend:
To detail page:

Storages:

Memory:

Application:

Configuration:

FlameGraph:

ThreadDump:

Metrics:

Logs:

LogList:

### Why are the changes needed?
Show more `worker` information.
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Local test.
Closes #2393 from tiny-dust/worker-detail.
Authored-by: tiny-dust <[email protected]>
Signed-off-by: SteNicholas <[email protected]>
---
web/LICENSE | 2 +-
web/licenses/LICENSE-@vicons-antd | 21 +++++++
web/licenses/LICENSE-dayjs | 21 -------
web/package.json | 2 +-
web/pnpm-lock.yaml | 14 ++---
.../api/models/application/types/application.ts | 7 +++
web/src/api/models/worker/index.ts | 6 +-
web/src/api/models/worker/types/detail.ts | 55 +++++++++++++++++
web/src/api/models/worker/types/index.ts | 1 +
web/src/composables/form.ts | 10 ++--
web/src/composables/pagination.ts | 5 ++
web/src/layouts/components/menus/index.vue | 2 +-
web/src/router/modules/worker.ts | 15 ++++-
web/src/utils/{datetime.ts => index.ts} | 6 +-
.../modules/worker.ts => utils/transform.ts} | 13 ++--
.../application/components/ApplicationList.vue | 6 +-
.../components/ApplicationSearchForm.vue | 29 +++++----
.../worker/components/WorkerDetailContent.vue | 65 ++++++++++++++++++++
.../components/WorkerDetailOverview.vue} | 55 ++++-------------
web/src/views/worker/components/WorkerForm.vue | 23 +++++---
web/src/views/worker/components/WorkerTable.vue | 66 ++++++++++++++-------
.../components/detail/WorkerDetailConfig.vue} | 69 ++++++++++------------
.../components/detail/WorkerDetailLogFile.vue} | 40 +++++++------
.../components/detail/WorkerDetailMemory.vue} | 40 +++++++------
.../components/detail/WorkerDetailStorage.vue} | 54 +++++++++++------
.../worker/components/detail}/index.ts | 20 +++----
web/src/views/worker/components/index.ts | 11 +++-
web/src/views/worker/detail.vue | 65 ++++++++++++++++++++
28 files changed, 483 insertions(+), 240 deletions(-)
diff --git a/web/LICENSE b/web/LICENSE
index 111d3221d..d2d9cc7f3 100644
--- a/web/LICENSE
+++ b/web/LICENSE
@@ -233,7 +233,7 @@ MIT licenses
unplugin-vue-components 0.26.0
https://www.npmjs.com/package/unplugin-vue-components/v/0.26.0 MIT
vite 5.0.12 https://www.npmjs.com/package/vite/v/5.0.12 MIT
vue-tsc 1.8.27 https://www.npmjs.com/package/vue-tsc/v/1.8.27 MIT
- dayjs 1.11.10 https://www.npmjs.com/package/dayjs/v/1.11.10 MIT
+ @vicons/antd 0.12.0 https://www.npmjs.com/package/@vicons/antd/v/0.12.0 MIT
========================================
Apache 2.0 licenses
diff --git a/web/licenses/LICENSE-@vicons-antd
b/web/licenses/LICENSE-@vicons-antd
new file mode 100644
index 000000000..8fad6ec3e
--- /dev/null
+++ b/web/licenses/LICENSE-@vicons-antd
@@ -0,0 +1,21 @@
+MIT LICENSE
+
+Copyright (c) 2018-present Ant UED, https://xtech.antfin.com/
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/web/licenses/LICENSE-dayjs b/web/licenses/LICENSE-dayjs
deleted file mode 100644
index caf931549..000000000
--- a/web/licenses/LICENSE-dayjs
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2018-present, iamkun
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/web/package.json b/web/package.json
index c8da831b5..fb154acda 100644
--- a/web/package.json
+++ b/web/package.json
@@ -13,7 +13,6 @@
"format": "prettier --write src/"
},
"dependencies": {
- "dayjs": "^1.11.10",
"pinia": "^2.1.7",
"vue": "^3.3.11",
"vue-router": "^4.2.5"
@@ -23,6 +22,7 @@
"@tsconfig/node18": "^18.2.2",
"@types/node": "^18.19.3",
"@varlet/axle": "^0.6.0",
+ "@vicons/antd": "^0.12.0",
"@vitejs/plugin-vue": "^4.5.2",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"@vue/eslint-config-prettier": "^8.0.0",
diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml
index 581542ee6..6132f69eb 100644
--- a/web/pnpm-lock.yaml
+++ b/web/pnpm-lock.yaml
@@ -22,9 +22,6 @@ settings:
excludeLinksFromLockfile: false
dependencies:
- dayjs:
- specifier: ^1.11.10
- version: 1.11.10
pinia:
specifier: ^2.1.7
version: 2.1.7([email protected])([email protected])
@@ -48,6 +45,9 @@ devDependencies:
'@varlet/axle':
specifier: ^0.6.0
version: 0.6.0([email protected])
+ '@vicons/antd':
+ specifier: ^0.12.0
+ version: 0.12.0
'@vitejs/plugin-vue':
specifier: ^4.5.2
version: 4.5.2([email protected])([email protected])
@@ -1063,6 +1063,10 @@ packages:
resolution: {integrity:
sha512-MgLDRYfrGgKqu8Vg2kfRVRGRZE2d8CH0f75vph5h4AG+Clm+A7FgUZLaVTriMWuS6wXrrrceSgX5kNmb/lFShQ==}
dev: true
+ /@vicons/[email protected]:
+ resolution: {integrity:
sha512-C0p6aO1EmGG1QHrqgUWQS1No20934OdWSRQshM5NIDK5H1On6tC26U0hT6Rmp40KfUsvhvX5YW8BoWJdNFifPg==}
+ dev: true
+
/@vitejs/[email protected]([email protected])([email protected]):
resolution: {integrity:
sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==}
engines: {node: ^14.18.0 || >=16.0.0}
@@ -1563,10 +1567,6 @@ packages:
'@babel/runtime': 7.23.8
dev: true
- /[email protected]:
- resolution: {integrity:
sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==}
- dev: false
-
/[email protected]:
resolution: {integrity:
sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
dev: true
diff --git a/web/src/api/models/application/types/application.ts
b/web/src/api/models/application/types/application.ts
index 7f329d12b..e3cf8d01b 100644
--- a/web/src/api/models/application/types/application.ts
+++ b/web/src/api/models/application/types/application.ts
@@ -15,6 +15,8 @@
* limitations under the License.
*/
+import type { PaginationProps } from 'naive-ui'
+
export interface ApplicationOverview {
runningNum: number
totalShuffleSize: string
@@ -39,3 +41,8 @@ export interface ApplicationResponse {
applicationInfos: Application[]
totalCount: number
}
+
+export interface ApplicationTab {
+ pagination: PaginationProps
+ data: Application[]
+}
diff --git a/web/src/api/models/worker/index.ts
b/web/src/api/models/worker/index.ts
index 0934472f3..1d0769e72 100644
--- a/web/src/api/models/worker/index.ts
+++ b/web/src/api/models/worker/index.ts
@@ -17,7 +17,7 @@
import { api } from '@/api/request'
import type { PaginationType } from '@/api/types'
-import type { Worker, WorkerOverview } from './types'
+import type { Worker, WorkerDetail, WorkerOverview } from './types'
export * from './types'
@@ -28,3 +28,7 @@ export const getWorkerOverview = () => {
export const getWorkerList = () => {
return api<PaginationType<{ workerInfos: Worker[] }>>('/worker/list', 'get')
}
+
+export const getWorkerDetail = () => {
+ return api<WorkerDetail>('/worker/detail', 'get')
+}
diff --git a/web/src/api/models/worker/types/detail.ts
b/web/src/api/models/worker/types/detail.ts
new file mode 100644
index 000000000..de3a10eeb
--- /dev/null
+++ b/web/src/api/models/worker/types/detail.ts
@@ -0,0 +1,55 @@
+/*
+ * 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 WorkerDetail {
+ diskInfos: WorkerDiskInfo[]
+ dynamicConfigs: Record<string, string>
+ fetchPort: number
+ flameGraph: string
+ hostname: string
+ ip: string
+ logFiles: Record<string, string>
+ logs: string
+ memoryInfo: WorkerMemoryInfo
+ metrics: string
+ pushPort: number
+ replicatePort: number
+ startTime: Date
+ state: string
+ staticConfigs: Record<string, string>
+ threadDump: string
+}
+
+export interface WorkerDiskInfo {
+ diskType: string
+ mountPoint: string
+ totalSpace: string
+ usedPercent: string
+ usedSpace: string
+}
+
+export interface WorkerMemoryInfo {
+ diskBuffer: string
+ pausePushDataThreshold: string
+ pauseReplicateThreshold: string
+ readBuffer: string
+ resumeThreshold: string
+ sortMemory: string
+ totalNativeMemory: string
+ usedDirectMemory: string
+ [key: string]: string
+}
diff --git a/web/src/api/models/worker/types/index.ts
b/web/src/api/models/worker/types/index.ts
index 5677157cc..ad4504000 100644
--- a/web/src/api/models/worker/types/index.ts
+++ b/web/src/api/models/worker/types/index.ts
@@ -15,4 +15,5 @@
* limitations under the License.
*/
+export * from './detail'
export * from './worker'
diff --git a/web/src/composables/form.ts b/web/src/composables/form.ts
index c51ae4e4c..128c45881 100644
--- a/web/src/composables/form.ts
+++ b/web/src/composables/form.ts
@@ -15,20 +15,18 @@
* limitations under the License.
*/
-import { getCurrentInstance, unref } from 'vue'
-
-export const useFormEvent = (formData: Record<string, any>) => {
- const instance = getCurrentInstance()
+import { unref, type SetupContext } from 'vue'
+export const useFormEvent = (formData: Record<string, any>, ctx: SetupContext)
=> {
const doSearch = () => {
- instance?.emit('search', formData)
+ ctx.emit('search', formData)
}
const resetSearch = () => {
Object.keys(formData).forEach((key) => {
formData[key] = ''
})
- instance?.emit('reset', unref(formData))
+ ctx.emit('reset', unref(formData))
}
return {
diff --git a/web/src/composables/pagination.ts
b/web/src/composables/pagination.ts
index 2719f5923..778e99f07 100644
--- a/web/src/composables/pagination.ts
+++ b/web/src/composables/pagination.ts
@@ -18,6 +18,7 @@
import type { PaginationProps } from 'naive-ui'
export interface UsePaginationOptions {
+ params?: Record<string, string>
currentPage?: number
pageSize?: number
onLoadData?: Function
@@ -25,6 +26,7 @@ export interface UsePaginationOptions {
export function usePagination(options: UsePaginationOptions) {
const {
+ params,
currentPage: defaultCurrentPage = 1,
pageSize: defaultPageSize = 30,
onLoadData
@@ -77,6 +79,9 @@ export function usePagination(options: UsePaginationOptions) {
}
onMounted(() => {
+ if (params) {
+ searchParams.value = params
+ }
loadData()
})
diff --git a/web/src/layouts/components/menus/index.vue
b/web/src/layouts/components/menus/index.vue
index 70b876ee1..1daa9e448 100644
--- a/web/src/layouts/components/menus/index.vue
+++ b/web/src/layouts/components/menus/index.vue
@@ -34,7 +34,7 @@ defineProps({
})
const path = computed(() => {
- return router.currentRoute.value.fullPath
+ return `/${router.currentRoute.value.fullPath.split('/')[1]}`
})
const updateValue = (value: string) => {
diff --git a/web/src/router/modules/worker.ts b/web/src/router/modules/worker.ts
index 965b50419..af679c7f9 100644
--- a/web/src/router/modules/worker.ts
+++ b/web/src/router/modules/worker.ts
@@ -19,5 +19,18 @@ export default {
path: '/worker',
name: 'worker',
meta: { title: 'Worker' },
- component: () => import('@/views/worker/index.vue')
+ children: [
+ {
+ path: '/worker',
+ name: 'worker',
+ meta: { title: 'Worker' },
+ component: () => import('@/views/worker/index.vue')
+ },
+ {
+ path: '/worker/detail',
+ name: 'workerDetail',
+ meta: { title: 'WorkerDetail' },
+ component: () => import('@/views/worker/detail.vue')
+ }
+ ]
}
diff --git a/web/src/utils/datetime.ts b/web/src/utils/index.ts
similarity index 83%
rename from web/src/utils/datetime.ts
rename to web/src/utils/index.ts
index 05147dc06..af9f968c6 100644
--- a/web/src/utils/datetime.ts
+++ b/web/src/utils/index.ts
@@ -15,8 +15,4 @@
* limitations under the License.
*/
-import dayjs from 'dayjs'
-
-export const normalizeDatetime = (datetime?: string) => {
- return datetime ? dayjs(datetime).format('YYYY-MM-DD HH:mm:ss') : ''
-}
+export * from './transform'
diff --git a/web/src/router/modules/worker.ts b/web/src/utils/transform.ts
similarity index 82%
copy from web/src/router/modules/worker.ts
copy to web/src/utils/transform.ts
index 965b50419..92494424d 100644
--- a/web/src/router/modules/worker.ts
+++ b/web/src/utils/transform.ts
@@ -15,9 +15,12 @@
* limitations under the License.
*/
-export default {
- path: '/worker',
- name: 'worker',
- meta: { title: 'Worker' },
- component: () => import('@/views/worker/index.vue')
+export function objectToArray(obj: Record<string, any>) {
+ const keys = Object.keys(obj)
+ return keys.map((key) => {
+ return {
+ key,
+ value: obj[key]
+ }
+ })
}
diff --git a/web/src/views/application/components/ApplicationList.vue
b/web/src/views/application/components/ApplicationList.vue
index 8e475a565..e5b526106 100644
--- a/web/src/views/application/components/ApplicationList.vue
+++ b/web/src/views/application/components/ApplicationList.vue
@@ -17,9 +17,9 @@
-->
<script setup lang="ts">
-import type { PropType } from 'vue'
+import type { Application } from '@/api'
import type { DataTableColumns, PaginationProps } from 'naive-ui'
-import type { Application } from '@/api/models/application/types'
+import type { PropType } from 'vue'
defineOptions({
name: 'ApplicationDataTable'
@@ -67,5 +67,5 @@ const columns: DataTableColumns<Application> = [
</script>
<template>
- <n-data-table :columns="columns" :data="data" :pagination="pagination" />
+ <n-data-table scroll-x="1000" :columns="columns" :data="data"
:pagination="pagination" />
</template>
diff --git a/web/src/views/application/components/ApplicationSearchForm.vue
b/web/src/views/application/components/ApplicationSearchForm.vue
index 6de56434b..7f13d2a70 100644
--- a/web/src/views/application/components/ApplicationSearchForm.vue
+++ b/web/src/views/application/components/ApplicationSearchForm.vue
@@ -16,20 +16,27 @@
* limitations under the License.
-->
-<script setup lang="ts">
+<script lang="ts">
import { useFormEvent } from '@/composables'
-defineOptions({
- name: 'ApplicationSearchForm'
-})
+export default defineComponent({
+ name: 'ApplicationSearchForm',
+ setup(_, ctx) {
+ const searchForm = reactive({
+ appId: '',
+ subUser: '',
+ tenant: ''
+ })
-const searchForm = reactive({
- appId: '',
- subUser: '',
- tenant: ''
-})
+ const { doSearch, resetSearch } = useFormEvent(searchForm, ctx)
-const { doSearch, resetSearch } = useFormEvent(searchForm)
+ return {
+ searchForm,
+ doSearch,
+ resetSearch
+ }
+ }
+})
</script>
<template>
@@ -39,7 +46,7 @@ const { doSearch, resetSearch } = useFormEvent(searchForm)
label-placement="left"
@keydown.enter="doSearch"
>
- <n-grid :x-gap="24" :y-gap="24" :cols="6">
+ <n-grid :x-gap="24" :y-gap="24" cols="1 400:2 800:4 1200:6">
<n-form-item-gi label="AppId" path="appId">
<n-input v-model:value="searchForm.appId" placeholder="" clearable />
</n-form-item-gi>
diff --git a/web/src/views/worker/components/WorkerDetailContent.vue
b/web/src/views/worker/components/WorkerDetailContent.vue
new file mode 100644
index 000000000..259fde526
--- /dev/null
+++ b/web/src/views/worker/components/WorkerDetailContent.vue
@@ -0,0 +1,65 @@
+<!--
+* 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.
+-->
+
+<script setup lang="ts">
+import type { ApplicationTab, WorkerDetail } from '@/api'
+import { ApplicationListService } from '@/views/application/components'
+import type { PropType } from 'vue'
+import {
+ WorkerDetailConfigService,
+ WorkerDetailLogFileService,
+ WorkerDetailMemoryService,
+ WorkerDetailStorageService
+} from '.'
+
+defineProps({
+ data: {
+ type: Object as PropType<WorkerDetail>,
+ default: () => ({})
+ },
+ application: {
+ type: Object as PropType<ApplicationTab>,
+ default: () => {}
+ }
+})
+</script>
+<template>
+ <n-card title="" style="margin-bottom: 16px">
+ <n-tabs type="line" animated>
+ <n-tab-pane name="Storages" tab="Storages">
+ <WorkerDetailStorageService :data="data.diskInfos" />
+ </n-tab-pane>
+ <n-tab-pane name="Memory" tab="Memory">
+ <WorkerDetailMemoryService :data="data.memoryInfo" />
+ </n-tab-pane>
+ <n-tab-pane name="Application" tab="Application">
+ <ApplicationListService :="application" />
+ </n-tab-pane>
+ <n-tab-pane name="Configuration" tab="Configuration">
+ <WorkerDetailConfigService :dynamic="data.dynamicConfigs"
:static="data.staticConfigs" />
+ </n-tab-pane>
+ <n-tab-pane name="FlameGraph" tab="FlameGraph"> {{ data.flameGraph }}
</n-tab-pane>
+ <n-tab-pane name="ThreadDump" tab="ThreadDump"> {{ data.threadDump }}
</n-tab-pane>
+ <n-tab-pane name="Metrics" tab="Metrics"> {{ data.metrics }}
</n-tab-pane>
+ <n-tab-pane name="Logs" tab="Logs"> {{ data.logs }} </n-tab-pane>
+ <n-tab-pane name="LogList" tab="LogList">
+ <WorkerDetailLogFileService :data="data.logFiles" />
+ </n-tab-pane>
+ </n-tabs>
+ </n-card>
+</template>
diff --git a/web/src/views/application/components/ApplicationList.vue
b/web/src/views/worker/components/WorkerDetailOverview.vue
similarity index 53%
copy from web/src/views/application/components/ApplicationList.vue
copy to web/src/views/worker/components/WorkerDetailOverview.vue
index 8e475a565..314513ab5 100644
--- a/web/src/views/application/components/ApplicationList.vue
+++ b/web/src/views/worker/components/WorkerDetailOverview.vue
@@ -17,55 +17,26 @@
-->
<script setup lang="ts">
+import type { WorkerDetail } from '@/api'
import type { PropType } from 'vue'
-import type { DataTableColumns, PaginationProps } from 'naive-ui'
-import type { Application } from '@/api/models/application/types'
-
-defineOptions({
- name: 'ApplicationDataTable'
-})
defineProps({
data: {
- type: Array as PropType<Application[]>,
- default: () => []
- },
- pagination: {
- type: Object as PropType<PaginationProps>,
+ type: Object as PropType<WorkerDetail>,
default: () => ({})
}
})
-
-const columns: DataTableColumns<Application> = [
- {
- title: 'AppId',
- key: 'appId',
- sorter: true
- },
- {
- title: 'SubUser',
- key: 'subUser'
- },
- {
- title: 'Tenant',
- key: 'tenant'
- },
- {
- title: 'HeartbeatTime',
- key: 'heartbeatTime'
- },
- {
- title: 'ShuffleSize',
- key: 'shuffleSize'
- },
- {
- title: 'ActiveShuffle',
- key: 'shuffleFileCount',
- sorter: true
- }
-]
</script>
-
<template>
- <n-data-table :columns="columns" :data="data" :pagination="pagination" />
+ <n-card hoverable>
+ <n-descriptions label-placement="left" title="Worker Detail" :column="4">
+ <n-descriptions-item label="HostName"> {{ data.hostname }}
</n-descriptions-item>
+ <n-descriptions-item label="IP"> {{ data.ip }} </n-descriptions-item>
+ <n-descriptions-item label="State"> {{ data.state }}
</n-descriptions-item>
+ <n-descriptions-item label="StartTime"> {{ data.startTime }}
</n-descriptions-item>
+ <n-descriptions-item label="FetchPort"> {{ data.fetchPort }}
</n-descriptions-item>
+ <n-descriptions-item label="PushPort"> {{ data.pushPort }}
</n-descriptions-item>
+ <n-descriptions-item label="ReplicatePort"> {{ data.replicatePort }}
</n-descriptions-item>
+ </n-descriptions>
+ </n-card>
</template>
diff --git a/web/src/views/worker/components/WorkerForm.vue
b/web/src/views/worker/components/WorkerForm.vue
index cb8c3eb3b..269bd3a88 100644
--- a/web/src/views/worker/components/WorkerForm.vue
+++ b/web/src/views/worker/components/WorkerForm.vue
@@ -16,20 +16,29 @@
* limitations under the License.
-->
-<script lang="ts" setup>
+<script lang="ts">
import { useFormEvent } from '@/composables'
-const formData = reactive({
- ip: '',
- state: ''
+export default defineComponent({
+ name: 'WorkerForm',
+ setup(_, ctx) {
+ const formData = reactive({
+ ip: '',
+ state: ''
+ })
+ const { doSearch, resetSearch } = useFormEvent(formData, ctx)
+ return {
+ formData,
+ doSearch,
+ resetSearch
+ }
+ }
})
-
-const { doSearch, resetSearch } = useFormEvent(formData)
</script>
<template>
<n-form :model="formData" :show-feedback="false" label-placement="left"
@keydown.enter="doSearch">
- <n-grid :x-gap="24" :y-gap="24" :cols="6">
+ <n-grid :x-gap="24" :y-gap="24" cols="1 400:2 800:4 1200:6">
<n-form-item-gi label="IP" path="ip">
<n-input v-model:value="formData.ip" placeholder="" clearable />
</n-form-item-gi>
diff --git a/web/src/views/worker/components/WorkerTable.vue
b/web/src/views/worker/components/WorkerTable.vue
index d4c6e8048..b5462bc8e 100644
--- a/web/src/views/worker/components/WorkerTable.vue
+++ b/web/src/views/worker/components/WorkerTable.vue
@@ -18,9 +18,19 @@
<script setup lang="ts">
import type { Worker } from '@/api'
-import { NButton, type DataTableColumns, type PaginationProps } from 'naive-ui'
+import { QuestionCircleOutlined } from '@vicons/antd'
+import {
+ NButton,
+ NIcon,
+ NSpace,
+ NTooltip,
+ type DataTableColumns,
+ type PaginationProps
+} from 'naive-ui'
import type { PropType } from 'vue'
+const router = useRouter()
+
defineOptions({
name: 'WorkerTable'
})
@@ -36,6 +46,27 @@ defineProps({
}
})
+const toWorkerDetail = ({ ip, rpcPort, pushPort, fetchPort, replicatePort }:
Worker) => {
+ const worker = `${ip}:${rpcPort}:${pushPort}:${fetchPort}:${replicatePort}`
+ router.push({
+ name: 'workerDetail',
+ query: { worker }
+ })
+}
+
+const renderToolTip = () => {
+ return h(NSpace, null, {
+ default: () => [
+ h('span', null, { default: () => 'Ports' }),
+ h(NTooltip, null, {
+ default: () => 'RpcPort:PushPort:FetchPort:ReplicatePort',
+ trigger: () =>
+ h(NIcon, { style: { paddingTop: '4px' } }, { default: () =>
h(QuestionCircleOutlined) })
+ })
+ ]
+ })
+}
+
const columns: DataTableColumns<Worker> = [
{
title: 'Hostname/IP',
@@ -57,24 +88,12 @@ const columns: DataTableColumns<Worker> = [
key: 'heartbeatTime'
},
{
- title: 'RPCPort',
- key: 'rpcPort'
- },
- {
- title: 'RestPort',
- key: 'restPort'
- },
- {
- title: 'FetchPort',
- key: 'fetchPort'
- },
- {
- title: 'PushPort',
- key: 'pushPort'
- },
- {
- title: 'ReplicatePort',
- key: 'replicatePort'
+ key: 'ports',
+ title: renderToolTip,
+ render({ rpcPort, pushPort, fetchPort, replicatePort }) {
+ const ports = `${rpcPort}:${pushPort}:${fetchPort}:${replicatePort}`
+ return ports
+ }
},
{
title: 'Version',
@@ -83,13 +102,16 @@ const columns: DataTableColumns<Worker> = [
{
title: 'More',
key: 'more',
- render: () => {
+ render: (row) => {
return h(
NButton,
{
text: true,
type: 'primary',
- size: 'small'
+ size: 'small',
+ onClick: () => {
+ toWorkerDetail(row)
+ }
},
{ default: () => 'More' }
)
@@ -99,5 +121,5 @@ const columns: DataTableColumns<Worker> = [
</script>
<template>
- <n-data-table :columns="columns" :data="data" remote
:pagination="pagination" />
+ <n-data-table :scroll-x="1000" :columns="columns" :data="data" remote
:pagination="pagination" />
</template>
diff --git a/web/src/views/application/components/ApplicationList.vue
b/web/src/views/worker/components/detail/WorkerDetailConfig.vue
similarity index 52%
copy from web/src/views/application/components/ApplicationList.vue
copy to web/src/views/worker/components/detail/WorkerDetailConfig.vue
index 8e475a565..3326c828d 100644
--- a/web/src/views/application/components/ApplicationList.vue
+++ b/web/src/views/worker/components/detail/WorkerDetailConfig.vue
@@ -16,56 +16,49 @@
* limitations under the License.
-->
-<script setup lang="ts">
+<script lang="ts" setup>
+import { objectToArray } from '@/utils'
import type { PropType } from 'vue'
-import type { DataTableColumns, PaginationProps } from 'naive-ui'
-import type { Application } from '@/api/models/application/types'
-defineOptions({
- name: 'ApplicationDataTable'
-})
-
-defineProps({
- data: {
- type: Array as PropType<Application[]>,
- default: () => []
+const props = defineProps({
+ static: {
+ type: Object as PropType<Record<string, string>>,
+ default: () => ({})
},
- pagination: {
- type: Object as PropType<PaginationProps>,
+ dynamic: {
+ type: Object as PropType<Record<string, string>>,
default: () => ({})
}
})
-const columns: DataTableColumns<Application> = [
- {
- title: 'AppId',
- key: 'appId',
- sorter: true
- },
- {
- title: 'SubUser',
- key: 'subUser'
- },
- {
- title: 'Tenant',
- key: 'tenant'
- },
- {
- title: 'HeartbeatTime',
- key: 'heartbeatTime'
- },
+const staticData = computed(() => {
+ return objectToArray(props.static)
+})
+
+const dynamicData = computed(() => {
+ return objectToArray(props.dynamic)
+})
+
+const columns = [
{
- title: 'ShuffleSize',
- key: 'shuffleSize'
+ title: 'Key',
+ key: 'key',
+ width: 150
},
{
- title: 'ActiveShuffle',
- key: 'shuffleFileCount',
- sorter: true
+ title: 'Value',
+ key: 'value',
+ width: 150
}
]
</script>
-
<template>
- <n-data-table :columns="columns" :data="data" :pagination="pagination" />
+ <n-flex :wrap="false">
+ <n-card title="Static Config">
+ <n-data-table :columns="columns" :data="staticData" :pagination="false"
/>
+ </n-card>
+ <n-card title="Dynamic Config">
+ <n-data-table :columns="columns" :data="dynamicData" :pagination="false"
/>
+ </n-card>
+ </n-flex>
</template>
diff --git a/web/src/layouts/components/menus/index.vue
b/web/src/views/worker/components/detail/WorkerDetailLogFile.vue
similarity index 65%
copy from web/src/layouts/components/menus/index.vue
copy to web/src/views/worker/components/detail/WorkerDetailLogFile.vue
index 70b876ee1..ffb04720b 100644
--- a/web/src/layouts/components/menus/index.vue
+++ b/web/src/views/worker/components/detail/WorkerDetailLogFile.vue
@@ -16,32 +16,34 @@
* limitations under the License.
-->
-<script setup lang="ts">
-import type { MenuOption } from 'naive-ui'
+<script lang="ts" setup>
+import { objectToArray } from '@/utils'
import type { PropType } from 'vue'
-const router = useRouter()
-
-defineOptions({
- name: 'SiderMenu'
-})
-
-defineProps({
- menus: {
- type: Array as PropType<MenuOption[]>,
- default: () => []
+const props = defineProps({
+ data: {
+ type: Object as PropType<Record<string, string>>,
+ default: () => ({})
}
})
-const path = computed(() => {
- return router.currentRoute.value.fullPath
+const tableData = computed(() => {
+ return objectToArray(props.data)
})
-const updateValue = (value: string) => {
- router.push(value)
-}
+const columns = [
+ {
+ title: 'Key',
+ key: 'key',
+ width: 150
+ },
+ {
+ title: 'Value',
+ key: 'value',
+ width: 150
+ }
+]
</script>
-
<template>
- <n-menu :options="menus" :default-value="path" @update:value="updateValue" />
+ <n-data-table :columns="columns" :data="tableData" :pagination="false" />
</template>
diff --git a/web/src/layouts/components/menus/index.vue
b/web/src/views/worker/components/detail/WorkerDetailMemory.vue
similarity index 63%
copy from web/src/layouts/components/menus/index.vue
copy to web/src/views/worker/components/detail/WorkerDetailMemory.vue
index 70b876ee1..6ac1d4b6a 100644
--- a/web/src/layouts/components/menus/index.vue
+++ b/web/src/views/worker/components/detail/WorkerDetailMemory.vue
@@ -16,32 +16,36 @@
* limitations under the License.
-->
-<script setup lang="ts">
-import type { MenuOption } from 'naive-ui'
+<script lang="ts" setup>
+import type { WorkerMemoryInfo } from '@/api'
+import { objectToArray } from '@/utils'
import type { PropType } from 'vue'
-const router = useRouter()
-
-defineOptions({
- name: 'SiderMenu'
-})
-
-defineProps({
- menus: {
- type: Array as PropType<MenuOption[]>,
- default: () => []
+const props = defineProps({
+ data: {
+ type: Object as PropType<WorkerMemoryInfo>,
+ default: () => ({})
}
})
-const path = computed(() => {
- return router.currentRoute.value.fullPath
+const tableData = computed(() => {
+ return objectToArray(props.data)
})
-const updateValue = (value: string) => {
- router.push(value)
-}
+const columns = [
+ {
+ title: 'Name',
+ key: 'key',
+ width: 150
+ },
+ {
+ title: 'Value',
+ key: 'value',
+ width: 150
+ }
+]
</script>
<template>
- <n-menu :options="menus" :default-value="path" @update:value="updateValue" />
+ <n-data-table :columns="columns" :data="tableData" :pagination="false" />
</template>
diff --git a/web/src/layouts/components/menus/index.vue
b/web/src/views/worker/components/detail/WorkerDetailStorage.vue
similarity index 56%
copy from web/src/layouts/components/menus/index.vue
copy to web/src/views/worker/components/detail/WorkerDetailStorage.vue
index 70b876ee1..27875f44e 100644
--- a/web/src/layouts/components/menus/index.vue
+++ b/web/src/views/worker/components/detail/WorkerDetailStorage.vue
@@ -16,32 +16,48 @@
* limitations under the License.
-->
-<script setup lang="ts">
-import type { MenuOption } from 'naive-ui'
+<script lang="ts" setup>
+import type { WorkerDiskInfo } from '@/api'
+import type { DataTableColumns } from 'naive-ui'
import type { PropType } from 'vue'
-const router = useRouter()
-
-defineOptions({
- name: 'SiderMenu'
-})
-
defineProps({
- menus: {
- type: Array as PropType<MenuOption[]>,
+ data: {
+ type: Array as PropType<WorkerDiskInfo[]>,
default: () => []
}
})
-const path = computed(() => {
- return router.currentRoute.value.fullPath
-})
-
-const updateValue = (value: string) => {
- router.push(value)
-}
+const columns: DataTableColumns<WorkerDiskInfo> = [
+ {
+ title: 'DiskInfo',
+ key: 'index',
+ render: (_, index) => {
+ return `DiskInfo${index + 1}`
+ }
+ },
+ {
+ title: 'MountPoint',
+ key: 'mountPoint'
+ },
+ {
+ title: 'TotalSpace',
+ key: 'totalSpace'
+ },
+ {
+ title: 'UsedSpace',
+ key: 'usedSpace'
+ },
+ {
+ title: 'UsedPercent',
+ key: 'usedPercent'
+ },
+ {
+ title: 'DiskType',
+ key: 'diskType'
+ }
+]
</script>
-
<template>
- <n-menu :options="menus" :default-value="path" @update:value="updateValue" />
+ <n-data-table scroll-x="800" :columns="columns" :data="data"
:pagination="false" />
</template>
diff --git a/web/src/api/models/worker/index.ts
b/web/src/views/worker/components/detail/index.ts
similarity index 67%
copy from web/src/api/models/worker/index.ts
copy to web/src/views/worker/components/detail/index.ts
index 0934472f3..ea2ac2e75 100644
--- a/web/src/api/models/worker/index.ts
+++ b/web/src/views/worker/components/detail/index.ts
@@ -15,16 +15,14 @@
* limitations under the License.
*/
-import { api } from '@/api/request'
-import type { PaginationType } from '@/api/types'
-import type { Worker, WorkerOverview } from './types'
+import WorkerDetailConfigService from './WorkerDetailConfig.vue'
+import WorkerDetailLogFileService from './WorkerDetailLogFile.vue'
+import WorkerDetailMemoryService from './WorkerDetailMemory.vue'
+import WorkerDetailStorageService from './WorkerDetailStorage.vue'
-export * from './types'
-
-export const getWorkerOverview = () => {
- return api<WorkerOverview>('/worker/overview', 'get')
-}
-
-export const getWorkerList = () => {
- return api<PaginationType<{ workerInfos: Worker[] }>>('/worker/list', 'get')
+export {
+ WorkerDetailConfigService,
+ WorkerDetailLogFileService,
+ WorkerDetailMemoryService,
+ WorkerDetailStorageService
}
diff --git a/web/src/views/worker/components/index.ts
b/web/src/views/worker/components/index.ts
index 843b8d446..bc843c4c9 100644
--- a/web/src/views/worker/components/index.ts
+++ b/web/src/views/worker/components/index.ts
@@ -15,7 +15,16 @@
* limitations under the License.
*/
+import WorkerDetailContentService from './WorkerDetailContent.vue'
+import WorkerDetailOverviewService from './WorkerDetailOverview.vue'
import WorkerFormService from './WorkerForm.vue'
import WorkerTableService from './WorkerTable.vue'
-export { WorkerFormService, WorkerTableService }
+export * from './detail'
+
+export {
+ WorkerDetailContentService,
+ WorkerDetailOverviewService,
+ WorkerFormService,
+ WorkerTableService
+}
diff --git a/web/src/views/worker/detail.vue b/web/src/views/worker/detail.vue
new file mode 100644
index 000000000..504b149c7
--- /dev/null
+++ b/web/src/views/worker/detail.vue
@@ -0,0 +1,65 @@
+<!--
+* 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.
+-->
+
+<script lang="ts" setup>
+import { getApplicationList, getWorkerDetail, type ApplicationTab } from
'@/api'
+import { usePagination } from '@/composables'
+import { useHasLoading } from '@varlet/axle/use'
+import { WorkerDetailContentService, WorkerDetailOverviewService } from
'./components'
+
+defineOptions({
+ name: 'WorkerDetail'
+})
+
+const route = useRoute()
+const worker = route.query.worker as string
+
+const { data, loading: isDetailLoading } = getWorkerDetail().use({
+ params: { worker }
+})
+
+const {
+ data: appResponse,
+ loading: isAppListLoading,
+ getData: loadApplicationList
+} = getApplicationList().use({ immediate: false })
+
+const { pagination } = usePagination({
+ onLoadData: loadApplicationList,
+ params: {
+ worker
+ }
+})
+
+const application = computed<ApplicationTab>(() => {
+ return {
+ data: appResponse.value?.applicationInfos ?? [],
+ pagination: pagination.value
+ }
+})
+
+const loading = useHasLoading(isDetailLoading, isAppListLoading)
+</script>
+<template>
+ <n-spin :show="loading">
+ <n-flex :style="{ gap: '24px' }" vertical>
+ <WorkerDetailOverviewService :data="data" />
+ <WorkerDetailContentService :data="data" :application="application" />
+ </n-flex>
+ </n-spin>
+</template>