You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kyuubi.apache.org by ch...@apache.org on 2023/03/24 03:43:25 UTC
[kyuubi] branch master updated: [KYUUBI #3646][UI] Init Session Statistic Page
This is an automated email from the ASF dual-hosted git repository.
chengpan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kyuubi.git
The following commit(s) were added to refs/heads/master by this push:
new 0d5eaa2d0 [KYUUBI #3646][UI] Init Session Statistic Page
0d5eaa2d0 is described below
commit 0d5eaa2d0b6fc58348aef23c7407e7529c2873ab
Author: He Zhao <he...@cisco.com>
AuthorDate: Fri Mar 24 11:43:15 2023 +0800
[KYUUBI #3646][UI] Init Session Statistic Page
### _Why are the changes needed?_
Init Session Statistic Page
Close #3646
### _How was this patch tested?_
- [ ] Add some test cases that check the changes thoroughly including negative and positive cases if possible
- [ ] Add screenshots for manual tests if appropriate
- [ ] [Run test](https://kyuubi.readthedocs.io/en/master/develop_tools/testing.html#running-tests) locally before make a pull request
![popo_2023-03-20 17-47-24](https://user-images.githubusercontent.com/52876270/226303508-ab55d7d5-62c5-4062-bfab-70c483517e99.jpg)
Closes #4564 from zwangsheng/KYUUBI_3646.
Closes #3646
cbe0842ba [zwangsheng] [KYUUBI #3646] fix style
930cbb12a [zwangsheng] [KYUUBI #3646] bracket same line
d2ab1d5fd [zwangsheng] [KYUUBI #3646] Fix i18n about status
7f059e2df [zwangsheng] [KYUUBI #3646] Fix i18n about status
452c3ee5a [zwangsheng] [KYUUBI #3646] Remove unused style class
8967652bc [zwangsheng] [KYUUBI #3646] Add date fns license
70f2472c2 [zwangsheng] [KYUUBI #3646] install date-fns
8a3e845ff [zwangsheng] [KYUUBI #3646][UI] Init Session Statistic Page
Lead-authored-by: He Zhao <he...@cisco.com>
Co-authored-by: zwangsheng <22...@qq.com>
Signed-off-by: Cheng Pan <ch...@apache.org>
---
LICENSE-binary | 2 +
kyuubi-server/web-ui/.eslintrc | 3 +
kyuubi-server/web-ui/package.json | 1 +
kyuubi-server/web-ui/pnpm-lock.yaml | 7 ++
.../src/{locales/en_US => api/session}/index.ts | 16 +++-
kyuubi-server/web-ui/src/locales/en_US/index.ts | 13 ++-
kyuubi-server/web-ui/src/locales/zh_CN/index.ts | 13 ++-
kyuubi-server/web-ui/src/router/index.ts | 2 +
.../src/{locales/en_US => router/session}/index.ts | 12 ++-
kyuubi-server/web-ui/src/views/common/use-table.ts | 78 ++++++++++++++++
.../src/views/layout/components/aside/types.ts | 10 ++
.../src/views/session/session-statistics/index.vue | 104 +++++++++++++++++++++
12 files changed, 254 insertions(+), 7 deletions(-)
diff --git a/LICENSE-binary b/LICENSE-binary
index feab9965e..a52ea95fb 100644
--- a/LICENSE-binary
+++ b/LICENSE-binary
@@ -456,6 +456,8 @@ is auto-generated by `pnpm licenses list --prod`.
├────────────────────────────────────┼──────────────┤
│ csstype │ MIT │
├────────────────────────────────────┼──────────────┤
+│ date-fns │ MIT │
+├────────────────────────────────────┼──────────────┤
│ dayjs │ MIT │
├────────────────────────────────────┼──────────────┤
│ delayed-stream │ MIT │
diff --git a/kyuubi-server/web-ui/.eslintrc b/kyuubi-server/web-ui/.eslintrc
index ebbf40199..f2bff2cd6 100644
--- a/kyuubi-server/web-ui/.eslintrc
+++ b/kyuubi-server/web-ui/.eslintrc
@@ -69,6 +69,9 @@
"exports": "never",
"functions": "never"
}],
+ "prettier/prettier": ["error", {
+ "bracketSameLine": true
+ }],
"vue/multi-word-component-names": "off",
"vue/component-definition-name-casing": "off",
"vue/require-valid-default-prop": "off",
diff --git a/kyuubi-server/web-ui/package.json b/kyuubi-server/web-ui/package.json
index 63fdc7221..131e69b7f 100644
--- a/kyuubi-server/web-ui/package.json
+++ b/kyuubi-server/web-ui/package.json
@@ -17,6 +17,7 @@
"dependencies": {
"@element-plus/icons-vue": "^2.0.9",
"axios": "^0.27.2",
+ "date-fns": "^2.29.3",
"element-plus": "^2.2.12",
"pinia": "^2.0.18",
"pinia-plugin-persistedstate": "^2.1.1",
diff --git a/kyuubi-server/web-ui/pnpm-lock.yaml b/kyuubi-server/web-ui/pnpm-lock.yaml
index 61fc5124d..1926352ab 100644
--- a/kyuubi-server/web-ui/pnpm-lock.yaml
+++ b/kyuubi-server/web-ui/pnpm-lock.yaml
@@ -12,6 +12,7 @@ specifiers:
'@vue/eslint-config-typescript': ^11.0.0
'@vue/test-utils': ^2.0.2
axios: ^0.27.2
+ date-fns: ^2.29.3
element-plus: ^2.2.12
eslint: ^8.21.0
eslint-plugin-prettier: ^4.2.1
@@ -32,6 +33,7 @@ specifiers:
dependencies:
'@element-plus/icons-vue': 2.0.9_vue@3.2.37
axios: 0.27.2
+ date-fns: 2.29.3
element-plus: 2.2.13_vue@3.2.37
pinia: 2.0.18_j6bzmzd4ujpabbp5objtwxyjp4
pinia-plugin-persistedstate: 2.1.1_pinia@2.0.18
@@ -907,6 +909,11 @@ packages:
whatwg-url: 11.0.0
dev: true
+ /date-fns/2.29.3:
+ resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==}
+ engines: {node: '>=0.11'}
+ dev: false
+
/dayjs/1.11.5:
resolution: {integrity: sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==}
dev: false
diff --git a/kyuubi-server/web-ui/src/locales/en_US/index.ts b/kyuubi-server/web-ui/src/api/session/index.ts
similarity index 73%
copy from kyuubi-server/web-ui/src/locales/en_US/index.ts
copy to kyuubi-server/web-ui/src/api/session/index.ts
index 92df340d8..6af5a817f 100644
--- a/kyuubi-server/web-ui/src/locales/en_US/index.ts
+++ b/kyuubi-server/web-ui/src/api/session/index.ts
@@ -15,6 +15,18 @@
* limitations under the License.
*/
-export default {
- test: 'test'
+import request from '@/utils/request'
+
+export function getAllSessions() {
+ return request({
+ url: 'api/v1/sessions',
+ method: 'get'
+ })
+}
+
+export function deleteSession(sessionId: string) {
+ return request({
+ url: `api/v1/sessions/${sessionId}`,
+ method: 'delete'
+ })
}
diff --git a/kyuubi-server/web-ui/src/locales/en_US/index.ts b/kyuubi-server/web-ui/src/locales/en_US/index.ts
index 92df340d8..99e851651 100644
--- a/kyuubi-server/web-ui/src/locales/en_US/index.ts
+++ b/kyuubi-server/web-ui/src/locales/en_US/index.ts
@@ -16,5 +16,16 @@
*/
export default {
- test: 'test'
+ test: 'test',
+ user: 'User',
+ client_ip: 'Client IP',
+ kyuubi_instance: 'Kyuubi Instance',
+ session_id: 'Session ID',
+ create_time: 'Create Time',
+ operation: 'Operation',
+ delete_confirm: 'Delete Confirm',
+ message: {
+ delete_succeeded: 'Delete {name} Succeeded',
+ delete_failed: 'Delete {name} Failed'
+ }
}
diff --git a/kyuubi-server/web-ui/src/locales/zh_CN/index.ts b/kyuubi-server/web-ui/src/locales/zh_CN/index.ts
index 7272109f5..016aaa8e7 100644
--- a/kyuubi-server/web-ui/src/locales/zh_CN/index.ts
+++ b/kyuubi-server/web-ui/src/locales/zh_CN/index.ts
@@ -16,5 +16,16 @@
*/
export default {
- test: '测试'
+ test: '测试',
+ user: '用户',
+ client_ip: '客户端地址',
+ kyuubi_instance: '服务端地址',
+ session_id: 'Session ID',
+ create_time: '创建时间',
+ operation: '操作',
+ delete_confirm: '确认删除',
+ message: {
+ delete_succeeded: '删除 {name} 成功',
+ delete_failed: '删除 {name} 失败'
+ }
}
diff --git a/kyuubi-server/web-ui/src/router/index.ts b/kyuubi-server/web-ui/src/router/index.ts
index 207a22d56..4d01da552 100644
--- a/kyuubi-server/web-ui/src/router/index.ts
+++ b/kyuubi-server/web-ui/src/router/index.ts
@@ -20,6 +20,7 @@ import overviewRoutes from './overview'
import workloadRoutes from './workload'
import operationRoutes from './operation'
import contactRoutes from './contact'
+import sessionRoutes from './session'
const routes = [
{
@@ -36,6 +37,7 @@ const routes = [
redirect: 'overview',
children: [
...overviewRoutes,
+ ...sessionRoutes,
...workloadRoutes,
...operationRoutes,
...contactRoutes
diff --git a/kyuubi-server/web-ui/src/locales/en_US/index.ts b/kyuubi-server/web-ui/src/router/session/index.ts
similarity index 80%
copy from kyuubi-server/web-ui/src/locales/en_US/index.ts
copy to kyuubi-server/web-ui/src/router/session/index.ts
index 92df340d8..fca49f211 100644
--- a/kyuubi-server/web-ui/src/locales/en_US/index.ts
+++ b/kyuubi-server/web-ui/src/router/session/index.ts
@@ -15,6 +15,12 @@
* limitations under the License.
*/
-export default {
- test: 'test'
-}
+const routes = [
+ {
+ path: '/session/session-statistics',
+ name: 'session-statistics',
+ component: () => import('@/views/session/session-statistics/index.vue')
+ }
+]
+
+export default routes
diff --git a/kyuubi-server/web-ui/src/views/common/use-table.ts b/kyuubi-server/web-ui/src/views/common/use-table.ts
new file mode 100644
index 000000000..441feb1f1
--- /dev/null
+++ b/kyuubi-server/web-ui/src/views/common/use-table.ts
@@ -0,0 +1,78 @@
+/*
+ * 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 { ref, Ref } from 'vue'
+
+export function useTable() {
+ const list: Ref<any[]> = ref([])
+ const tableData: Ref<any[]> = ref([])
+ const loading = ref(false)
+ const currentPage = ref(1)
+ const pageSize = ref(10)
+ const totalPage = ref(1)
+
+ const handleSizeChange = (val: number) => {
+ if (
+ currentPage.value === 1 ||
+ (currentPage.value > 1 && totalPage.value > (currentPage.value - 1) * val)
+ ) {
+ loading.value = true
+ setTimeout(() => {
+ setTableData()
+ }, 200)
+ }
+ }
+
+ const handleCurrentChange = () => {
+ loading.value = true
+ setTimeout(() => {
+ setTableData()
+ }, 200)
+ }
+
+ const setTableData = () => {
+ tableData.value = [...list.value].splice(
+ (currentPage.value - 1) * pageSize.value,
+ pageSize.value
+ )
+ loading.value = false
+ }
+
+ const getList = (func: Function, data?: any) => {
+ loading.value = true
+ func(data)
+ .then((res: any[]) => (list.value = res || []))
+ .catch(() => (list.value = []))
+ .finally(() => {
+ currentPage.value = 1
+ pageSize.value = 10
+ totalPage.value = list.value.length
+ setTableData()
+ })
+ }
+
+ return {
+ tableData,
+ loading,
+ currentPage,
+ pageSize,
+ totalPage,
+ handleSizeChange,
+ handleCurrentChange,
+ getList
+ }
+}
diff --git a/kyuubi-server/web-ui/src/views/layout/components/aside/types.ts b/kyuubi-server/web-ui/src/views/layout/components/aside/types.ts
index ddd32bef4..71d1d0128 100644
--- a/kyuubi-server/web-ui/src/views/layout/components/aside/types.ts
+++ b/kyuubi-server/web-ui/src/views/layout/components/aside/types.ts
@@ -21,6 +21,16 @@ export const MENUS = [
icon: 'Odometer',
router: '/overview'
},
+ {
+ label: 'Session Management',
+ icon: 'List',
+ children: [
+ {
+ label: 'Session Statistics',
+ router: '/session/session-statistics'
+ }
+ ]
+ },
{
label: 'Workload',
icon: 'List',
diff --git a/kyuubi-server/web-ui/src/views/session/session-statistics/index.vue b/kyuubi-server/web-ui/src/views/session/session-statistics/index.vue
new file mode 100644
index 000000000..40a9b7568
--- /dev/null
+++ b/kyuubi-server/web-ui/src/views/session/session-statistics/index.vue
@@ -0,0 +1,104 @@
+<!--
+* 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>
+ <!-- TODO we need search here -->
+ <el-card>
+ <el-table
+ v-loading="loading"
+ :data="tableData"
+ max-height="500px"
+ style="width: 100%">
+ <el-table-column prop="user" :label="$t('user')" width="160px" />
+ <!-- TODO need jump to engine page -->
+ <el-table-column prop="engineId" :label="$t('engine_ip')" width="160px" />
+ <el-table-column prop="ipAddr" :label="$t('client_ip')" width="160px" />
+ <el-table-column
+ prop="kyuubiInstance"
+ :label="$t('kyuubi_instance')"
+ width="180px" />
+ <!-- TODO need jump to session page -->
+ <el-table-column
+ prop="identifier"
+ :label="$t('session_id')"
+ width="300px" />
+ <el-table-column :label="$t('create_time')" width="200">
+ <template #default="scope">
+ {{
+ scope.row.createTime != null && scope.row.createTime > -1
+ ? format(scope.row.createTime, 'yyyy-MM-dd HH:mm:ss')
+ : '-'
+ }}
+ </template>
+ </el-table-column>
+ <el-table-column fixed="right" :label="$t('operation')">
+ <template #default="scope">
+ <el-popconfirm
+ :title="$t('delete_confirm')"
+ @confirm="handleDeleteSession(scope.row.identifier)">
+ <template #reference>
+ <span>
+ <el-tooltip
+ effect="dark"
+ :content="$t('delete')"
+ placement="top">
+ <template #default>
+ <el-button type="danger" icon="Delete" circle />
+ </template>
+ </el-tooltip>
+ </span>
+ </template>
+ </el-popconfirm>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-card>
+</template>
+
+<script lang="ts" setup>
+ import { format } from 'date-fns'
+ import { getAllSessions, deleteSession } from '@/api/session'
+ import { ElMessage } from 'element-plus'
+ import { useI18n } from 'vue-i18n'
+ import { useTable } from '@/views/common/use-table'
+ const { t } = useI18n()
+ const { tableData, loading, getList: _getList } = useTable()
+ const handleDeleteSession = (sessionId: string) => {
+ deleteSession(sessionId)
+ .then(() => {
+ // need add delete success or failed logic after api support
+ ElMessage({
+ message: t('message.delete_succeeded', { name: 'session' }),
+ type: 'success'
+ })
+ })
+ .catch(() => {
+ ElMessage({
+ message: t('message.delete_failed', { name: 'session' }),
+ type: 'error'
+ })
+ })
+ .finally(() => {
+ getList()
+ })
+ }
+ const getList = () => {
+ _getList(getAllSessions)
+ }
+ getList()
+</script>