blob: 9e8b3c74b37576ac203e5facb1180fff764e7214 [file] [log] [blame]
<!--
~ 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 { useMenuStore } from '@/store/menu/index'
import { useClusterStore } from '@/store/cluster'
import { useStackStore } from '@/store/stack'
import type { ClusterStatusType } from '@/api/cluster/types'
const { t } = useI18n()
const router = useRouter()
const route = useRoute()
const stackStore = useStackStore()
const menuStore = useMenuStore()
const clusterStore = useClusterStore()
const routeParamsLen = ref(0)
const openKeys = ref<string[]>(['clusters'])
const { siderMenuSelectedKey, headerSelectedKey, siderMenus, routePathFromClusters } = storeToRefs(menuStore)
const { clusterCount, clusterMap } = storeToRefs(clusterStore)
const showCreateClusterBtn = computed(() => headerSelectedKey.value === '/cluster-manage')
const selectMenuKeyFromClusters = computed(() => siderMenuSelectedKey.value.includes(routePathFromClusters.value))
const clusterStatus = computed(
(): Record<ClusterStatusType, string> => ({
1: 'success',
2: 'error',
3: 'warning'
})
)
/**
* Handles route changes and updates the selected menu key.
*/
const handleRouteChange = async (newRoute: typeof route) => {
const token = localStorage.getItem('Token') ?? sessionStorage.getItem('Token') ?? undefined
const { params, path, meta, name: RouteName } = newRoute
if (!token) {
return
}
routeParamsLen.value = Object.keys(params).length
if (path.includes(routePathFromClusters.value) && RouteName !== 'CreateCluster') {
if (params.id && clusterMap.value[`${params.id}`]) {
siderMenuSelectedKey.value = `${routePathFromClusters.value}/${params.id}`
openKeys.value.push(siderMenuSelectedKey.value)
return
}
siderMenuSelectedKey.value = ''
menuStore.setupSider()
return
}
siderMenuSelectedKey.value = meta.activeMenu ?? path
}
/**
* Toggles the activated icon for menu items.
*/
const toggleActivatedIcon = (menuItem: { key: string; icon: string }) => {
const { key } = menuItem
const matchedRouteFromClusters = selectMenuKeyFromClusters.value && routeParamsLen.value > 0
return key === siderMenuSelectedKey.value || (matchedRouteFromClusters && key === 'clusters')
}
const addCluster = () => {
router.push({ name: 'CreateCluster' })
}
onMounted(() => {
stackStore.loadStacks()
clusterStore.loadClusters()
})
watch(
() => [route, clusterCount],
(val) => {
const [newRoute] = val
handleRouteChange(newRoute as typeof route)
},
{ deep: true, immediate: true }
)
</script>
<template>
<a-layout-sider class="sider">
<a-menu
:open-keys="openKeys"
:selected-keys="[siderMenuSelectedKey]"
mode="inline"
@click="({ key }) => menuStore.onSiderClick(key as string)"
>
<template v-for="menuItem in siderMenus" :key="menuItem.path">
<a-sub-menu v-if="menuItem.name === 'Clusters'" :key="menuItem.path">
<template #icon>
<svg-icon
color="inherit"
style="height: 16px; width: 16px"
:highlight="toggleActivatedIcon({ key: menuItem.path, icon: menuItem.meta?.icon || '' })"
:name="menuItem.meta?.icon || ''"
/>
</template>
<template #title>
<span>{{ t(menuItem.meta!.title!) }}</span>
</template>
<a-menu-item
v-for="child of clusterMap"
:key="`${routePathFromClusters}/${child.id}`"
:title="child.displayName"
>
<template #icon>
<div class="cluster-status">
<status-dot :size="8" :color="clusterStatus[child.status as ClusterStatusType] as any" />
</div>
</template>
<div>
<span>{{ child.displayName }}</span>
</div>
</a-menu-item>
</a-sub-menu>
<template v-else>
<a-menu-item v-if="!menuItem.meta?.hidden" :key="menuItem.redirect as string">
<template #icon>
<svg-icon
style="height: 16px; width: 16px"
:highlight="toggleActivatedIcon({ key: menuItem.redirect as string, icon: menuItem.meta?.icon || '' })"
:name="menuItem.meta?.icon || ''"
/>
</template>
<span>{{ t(menuItem.meta!.title!) }}</span>
</a-menu-item>
</template>
</template>
</a-menu>
<div v-if="showCreateClusterBtn">
<a-divider />
<div class="create-option">
<a-button type="primary" ghost @click="addCluster">
<div>
<label>{{ t('menu.create') }}</label>
</div>
</a-button>
</div>
</div>
</a-layout-sider>
</template>
<style scoped lang="scss">
.cluster-status {
height: 10px;
margin-inline: 7px;
display: flex;
justify-content: center;
align-items: flex-end;
}
@mixin reset-sider-menu {
width: 100%;
border-radius: 0;
padding: 0 0 0 14px !important;
margin: 4px 0 0 0 !important;
}
.sider {
width: $layout-header-height;
background: $layout-sider-bg-color;
overflow: auto;
:deep(.ant-menu-submenu-title) {
@include reset-sider-menu();
}
:deep(.ant-menu-item) {
@include reset-sider-menu();
}
:deep(.ant-menu-item-selected) {
border-right: 2px solid $color-primary;
}
.create-option {
width: 100%;
display: flex;
justify-content: center;
padding-bottom: $space-lg;
button {
width: 160px;
@include flexbox($align: center, $justify: center);
label {
cursor: pointer;
}
}
}
}
</style>