Skip to content

Commit 8a86ddd

Browse files
youngbeom-shin申永范-UX
andauthored
feat(resource_console): add quick navigation tabs (#1338)
* feat(resource_console): add quick navigation tabs * feat(resource_console): add quick navigation tabs * feat(navbar): update sub-menu properties - Add index to more sub-menu - Use binding for expand icons - Remove unused annual tab pane - Remove conditional rendering for billing component - Clean up unused import for isSaas --------- Co-authored-by: 申永范-UX <[email protected]>
1 parent 7a7f502 commit 8a86ddd

File tree

7 files changed

+211
-48
lines changed

7 files changed

+211
-48
lines changed

frontend/src/components/navbar/MenuItems.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@
4242
<!-- more -->
4343
<el-sub-menu
4444
v-if="moreItems.length > 0"
45+
:index="'more'"
4546
:popper-class="popperClass"
4647
:class="subMenuClass"
47-
expand-close-icon="null"
48-
expand-open-icon="null"
48+
:expand-close-icon="null"
49+
:expand-open-icon="null"
4950
style="--el-menu-icon-width: 0px">
5051
<template #title>
5152
<SvgIcon
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<template>
2+
<!-- annual and monthly billing -->
3+
<h3 class="text-lg flex justify-between gap-2 mt-8">
4+
<span class="whitespace-nowrap">{{ $t('resourceConsole.yearMonthResources') }}</span>
5+
<CsgButton
6+
class="btn btn-primary btn-sm"
7+
@click="handleBuyClick"
8+
:name="$t('resourceConsole.buy')"
9+
:svgName="'plus'"
10+
/>
11+
</h3>
12+
<div class="mt-6 mb-4">
13+
<ResourceTable :resource="computingPowers"/>
14+
<div class="mt-3 flex justify-center">
15+
<CsgPagination
16+
:perPage="defaultTotal"
17+
:currentPage="computingPowersCurrentPage"
18+
@currentChange="fetchComputingData"
19+
:total="totalComputing" />
20+
</div>
21+
</div>
22+
</template>
23+
24+
<script setup>
25+
import { ref, watch, onMounted, computed } from 'vue'
26+
import ResourceTable from "./ResourceTable.vue"
27+
import useUserStore from '../../stores/UserStore.js'
28+
import useFetchApi from "../../packs/useFetchApi"
29+
import CsgButton from "../shared/CsgButton.vue"
30+
import { ElMessage } from "element-plus"
31+
32+
const defaultTotal = 6
33+
const totalComputing =ref(0)
34+
const computingPowersCurrentPage = ref(1)
35+
const computingPowers = ref([])
36+
37+
const userStore = useUserStore()
38+
39+
const handleBuyClick = () => {
40+
window.location.href = '/computing'
41+
}
42+
43+
const fetchComputingData = async (childCurrent) => {
44+
if(childCurrent){
45+
computingPowersCurrentPage.value = childCurrent
46+
}
47+
const params = new URLSearchParams()
48+
params.append("per", defaultTotal)
49+
params.append("page", computingPowersCurrentPage.value)
50+
51+
try {
52+
const { data, error } = await useFetchApi(`/user/${userStore.username}/order/resources?${params}`).json()
53+
if (error.value) {
54+
ElMessage({
55+
message: error.value.msg,
56+
type: "warning"
57+
})
58+
} else {
59+
computingPowers.value = data.value.data
60+
totalComputing.value = data.value.total
61+
}
62+
} catch (error) {
63+
console.log(error)
64+
}
65+
}
66+
67+
watch(
68+
() => userStore.initialized,
69+
() => {
70+
fetchComputingData()
71+
}
72+
)
73+
74+
onMounted(() => {
75+
if (userStore.initialized) {
76+
fetchComputingData()
77+
}
78+
})
79+
</script>

frontend/src/components/resource_console/ResourceConsoleIndex.vue

Lines changed: 115 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,65 @@
33
<div class="text-3xl leading-9 mb-6">
44
{{ $t("resourceConsole.title") }}
55
</div>
6+
7+
<!-- Quick Navigation Tabs -->
8+
<el-tabs
9+
v-model="activeTab"
10+
class="border-b border-gray-200 my-8 tabCont"
11+
>
12+
<el-tab-pane
13+
name=""
14+
:label="`&nbsp;${$t('resourceConsole.allProducts')}&nbsp;`"
15+
></el-tab-pane>
16+
<el-tab-pane
17+
name="finetune"
18+
:label="`&nbsp;${$t('finetune.title')}&nbsp;`"
19+
></el-tab-pane>
20+
<el-tab-pane
21+
name="endpoints"
22+
:label="`&nbsp;${$t('endpoints.title')}&nbsp;`"
23+
></el-tab-pane>
24+
<el-tab-pane
25+
name="evaluations"
26+
:label="`&nbsp;${$t('evaluation.list.title')}&nbsp;`"
27+
></el-tab-pane>
28+
</el-tabs>
29+
30+
631
<!-- finetunes -->
7-
<h3 class="text-lg flex justify-between gap-2">
8-
<span>{{ $t("finetune.title") }}</span>
9-
<a href="/finetune/new" class="btn btn-primary btn-md">
10-
<SvgIcon name="plus" />
11-
{{ $t('resourceConsole.new') }}
12-
</a>
32+
<h3 v-if="activeTab === '' || activeTab === 'finetune'" class="text-lg flex justify-between gap-2 mt-8">
33+
<span class="whitespace-nowrap">{{ $t("finetune.title") }}</span>
34+
<CsgButton
35+
class="btn btn-primary btn-sm"
36+
@click="handleNewClick"
37+
:name="$t('resourceConsole.new')"
38+
:svgName="'plus'"
39+
/>
1340
</h3>
14-
<div class="mt-4">
15-
<div v-if="hasFinetune" class="grid grid-cols-2 xl:grid-cols-1 gap-4 mb-8 mt-4">
16-
<FinetuneItem v-for="finetune in finetunes.data" :repo="finetune" repo-type="finetune" />
41+
<div v-if="activeTab === '' || activeTab === 'finetune'" class="mt-4">
42+
<div v-if="filteredFinetunes.length > 0" class="grid grid-cols-2 xl:grid-cols-1 gap-4 mb-8 mt-4">
43+
<FinetuneItem v-for="finetune in filteredFinetunes" :repo="finetune" repo-type="finetune" />
1744
</div>
1845
<div v-else class="flex flex-wrap gap-4 mb-8 mt-4">
1946
{{ $t("all.noData") }}
2047
</div>
2148
<view-more v-if="finetunes.more" target="finetunes" @view-more-targets="viewMoreTargets"></view-more>
2249
<el-skeleton class="pr-6" v-if="finetunesLoading" :rows="2" animated />
2350
</div>
51+
2452
<!-- endpoints -->
25-
<h3 class="text-lg flex justify-between gap-2">
26-
<span>{{ $t("endpoints.title") }}</span>
27-
<a href="/endpoints/new" class="btn btn-primary btn-md">
28-
<SvgIcon name="plus" />
29-
{{ $t('resourceConsole.new') }}
30-
</a>
53+
<h3 v-if="activeTab === '' || activeTab === 'endpoints'" class="text-lg flex justify-between gap-2 mt-8">
54+
<span class="whitespace-nowrap">{{ $t("endpoints.title") }}</span>
55+
<CsgButton
56+
class="btn btn-primary btn-sm"
57+
@click="handleNewClick"
58+
:name="$t('resourceConsole.new')"
59+
:svgName="'plus'"
60+
/>
3161
</h3>
32-
<div class="mt-4 w-full">
33-
<div v-if="hasEndpoints" class="grid grid-cols-2 lg:grid-cols-1 gap-4 mb-8 mt-4">
34-
<EndpointItem v-for="endpoint in endpoints.data" :endpoint="endpoint" :namespace="name" />
62+
<div v-if="activeTab === '' || activeTab === 'endpoints'" class="mt-4 w-full">
63+
<div v-if="filteredEndpoints.length > 0" class="grid grid-cols-2 lg:grid-cols-1 gap-4 mb-8 mt-4">
64+
<EndpointItem v-for="endpoint in filteredEndpoints" :endpoint="endpoint" :namespace="name" />
3565
</div>
3666
<div v-else class="flex flex-wrap gap-4 mb-8 mt-4">
3767
{{ $t("all.noData") }}
@@ -45,15 +75,17 @@
4575
</div>
4676

4777
<!-- evaluations -->
48-
<h3 class="text-lg flex justify-between gap-2">
49-
<span>{{ $t("evaluation.list.title") }}</span>
50-
<a href="/evaluations/new" class="btn btn-primary btn-md">
51-
<SvgIcon name="plus" />
52-
{{ $t('evaluation.list.new') }}
53-
</a>
78+
<h3 v-if="activeTab === '' || activeTab === 'evaluations'" class="text-lg flex justify-between gap-2 mt-8">
79+
<span class="whitespace-nowrap">{{ $t("evaluation.list.title") }}</span>
80+
<CsgButton
81+
class="btn btn-primary btn-sm"
82+
@click="handleNewClick"
83+
:name="$t('evaluation.list.new')"
84+
:svgName="'plus'"
85+
/>
5486
</h3>
55-
<div class="mt-4 w-full">
56-
<EvaluationTable :evaluations="evaluations" />
87+
<div v-if="activeTab === '' || activeTab === 'evaluations'" class="mt-4 w-full">
88+
<EvaluationTable :evaluations="filteredEvaluations" />
5789
</div>
5890
</div>
5991
</template>
@@ -67,22 +99,48 @@
6799
import EvaluationTable from "./EvaluationTable.vue"
68100
import useFetchApi from "../../packs/useFetchApi"
69101
import { ElMessage } from "element-plus"
102+
import CsgButton from "../shared/CsgButton.vue"
103+
import { useI18n } from 'vue-i18n'
70104
71105
const props = defineProps({
72106
name: String
73107
})
74108
109+
const { t: $t } = useI18n()
110+
111+
const handleNewClick = (event) => {
112+
// 获取最近的标题元素
113+
const titleElement = event.target.closest('h3')
114+
if (!titleElement) return
115+
116+
// 根据标题内容判断类型
117+
const titleText = titleElement.textContent.trim()
118+
if (titleText.includes($t("finetune.title"))) {
119+
window.location.href = '/finetune/new'
120+
} else if (titleText.includes($t("endpoints.title"))) {
121+
window.location.href = '/endpoints/new'
122+
} else if (titleText.includes($t("evaluation.list.title"))) {
123+
window.location.href = '/evaluations/new'
124+
}
125+
}
126+
75127
const userStore = useUserStore()
76128
const defaultTotal = 6
77129
const endpoints = ref([])
78130
const finetunes = ref([])
131+
const evaluations = ref([])
132+
const activeTab = ref('')
79133
80134
const endpointsLoading = ref(false)
81135
const finetunesLoading = ref(false)
82136
83137
const hasEndpoints = computed(() => endpoints.value?.total > 0)
84138
const hasFinetune = computed(() => finetunes.value?.total > 0)
85139
140+
const filteredFinetunes = computed(() => finetunes.value?.data || [])
141+
const filteredEndpoints = computed(() => endpoints.value?.data || [])
142+
const filteredEvaluations = computed(() => evaluations.value?.data || [])
143+
86144
const csghubServer = inject("csghubServer")
87145
88146
const getRepoData = async () =>{
@@ -165,10 +223,41 @@
165223
}
166224
)
167225
226+
168227
onMounted(() => {
169228
if (userStore.initialized) {
170229
getRepoData()
171230
}
172231
})
173232
174233
</script>
234+
235+
<style scoped>
236+
:deep(.tabCont) {
237+
.el-tabs__header {
238+
margin: 0;
239+
}
240+
.el-tabs__nav-wrap::after {
241+
height: 1px;
242+
background-color: #e5e7eb;
243+
}
244+
.el-tabs__item {
245+
font-size: 14px !important;
246+
color: #667085 !important;
247+
padding-bottom: 12px;
248+
height: auto;
249+
line-height: normal;
250+
&:hover {
251+
color: #223B99 !important;
252+
}
253+
&.is-active {
254+
color: #223B99 !important;
255+
font-weight: 500;
256+
}
257+
}
258+
.el-tabs__active-bar {
259+
background-color: #223B99 !important;
260+
height: 2px !important;
261+
}
262+
}
263+
</style>

frontend/src/components/shared/ViewMore.vue

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
<template>
2-
<div class="flex items-center pr-6">
3-
<div class="flex-1 border-b"></div>
4-
<div
5-
class="mx-2 flex h-8 flex-none items-center cursor-pointer rounded-lg px-2 hover:bg-gray-100"
2+
<div class="flex items-center gap-4">
3+
<div class="flex-1 border-b border-gray-200"></div>
4+
<CsgButton
5+
class="btn btn-tertiary-gray btn-sm"
66
@click="viewMore"
7-
>
8-
<svg width="12" height="8" viewBox="0 0 12 8" fill="none" xmlns="http://www.w3.org/2000/svg">
9-
<path d="M1 1.5L6 6.5L11 1.5" stroke="#475467" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
10-
</svg>
11-
<div class="text-sm leading-[20px] text-gray-600 font-medium ml-2">{{ $t('all.viewMore') }}</div>
12-
</div>
13-
<div class="flex-1 border-b"></div>
7+
:name="$t('all.viewMore')"
8+
:svgName="'chevron-down'"
9+
/>
10+
<div class="flex-1 border-b border-gray-200"></div>
1411
</div>
1512
</template>
1613

frontend/src/locales/en_js/resource_console.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ export const resourceConsole = {
55
others:"Others",
66
title: "Resource Management",
77
new:'Create',
8-
instance:'Instance'
8+
instance:'Instance',
9+
allProducts: 'All Products'
910
}

frontend/src/locales/zh_hant_js/resource_console.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ export const resourceConsole = {
77
yearMonthResources:'包年包月資源',
88
buy:'購買資源',
99
new:'新建實例',
10-
resourceType:'資源類型',
11-
resourceId:'資源ID',
12-
resource:'配置',
13-
startTime:'啟動時間',
14-
endTime:'到期時間',
15-
price:'價格',
16-
instance:'實例'
10+
instance:'實例',
11+
allProducts: '全部產品'
1712
}

frontend/src/locales/zh_js/resource_console.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ export const resourceConsole = {
55
others:"其他",
66
title: "资源管理",
77
new:'新建实例',
8-
instance:'实例'
8+
instance:'实例',
9+
allProducts: '全部产品'
910
}

0 commit comments

Comments
 (0)