API-Explorer-II/src/components/HeaderNav.vue
2025-12-08 19:39:19 +01:00

295 lines
9.1 KiB
Vue

<!--
- Open Bank Project - API Explorer II
- Copyright (C) 2023-2024, TESOBE GmbH
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
- Email: contact@tesobe.com
- TESOBE GmbH
- Osloerstrasse 16/17
- Berlin 13359, Germany
-
- This product includes software developed at
- TESOBE (http://www.tesobe.com/)
-
-->
<script setup lang="ts">
import { ref, inject, watchEffect, onMounted, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { OBP_API_DEFAULT_RESOURCE_DOC_VERSION, getCurrentUser } from '../obp'
import { getOBPAPIVersions } from '../obp/api-version'
import {
LOGO_URL as logoSource,
HEADER_LINKS_COLOR,
HEADER_LINKS_HOVER_COLOR as headerLinksHoverColorSetting,
HEADER_LINKS_BACKGROUND_COLOR as headerLinksBackgroundColorSetting
} from '../obp/style-setting'
import { obpApiActiveVersionsKey, obpGroupedMessageDocsKey, obpMyCollectionsEndpointKey } from '@/obp/keys'
import SvelteDropdown from './SvelteDropdown.vue'
const route = useRoute()
const router = useRouter()
const obpApiHost = ref(import.meta.env.VITE_OBP_API_HOST)
const obpApiPortalHost = ref(import.meta.env.VITE_OBP_API_PORTAL_HOST)
const obpApiHybridPost = computed(() => obpApiPortalHost.value ? obpApiPortalHost.value : obpApiHost.value)
const obpApiManagerHost = ref(import.meta.env.VITE_OBP_API_MANAGER_HOST)
const hasObpApiManagerHost = computed(() => obpApiManagerHost.value ? true : false)
const showObpApiManagerButton = computed(() => import.meta.env.VITE_SHOW_API_MANAGER_BUTTON === 'true')
const loginUsername = ref('')
const logoffurl = ref('')
const obpApiVersions = ref(inject(obpApiActiveVersionsKey)!)
const obpMessageDocs = ref(Object.keys(inject(obpGroupedMessageDocsKey)!))
// Split versions into main and other
const mainVersions = ['BGv1.3', 'OBPv5.1.0', 'OBPv6.0.0', 'UKv3.1', 'dynamic-endpoints', 'dynamic-entities', 'OBPdynamic-endpoint', 'OBPdynamic-entity']
const sortedVersions = computed(() => {
const all = obpApiVersions.value || []
console.log('All available versions:', all)
const main = mainVersions.filter(v => all.includes(v))
console.log('Main versions found:', main)
const others = all.filter(v => !mainVersions.includes(v)).sort()
console.log('Other versions:', others)
// Only add divider if we have both main and other versions
if (main.length > 0 && others.length > 0) {
return [...main, '---', ...others]
} else if (main.length > 0) {
return main
} else {
return others
}
})
const isShowLoginButton = ref(true)
const isShowLogOffButton = ref(false)
const logo = ref(logoSource)
const headerLinksHoverColor = ref(headerLinksHoverColorSetting)
const headerLinksBackgroundColor = ref(headerLinksBackgroundColorSetting)
const clearActiveTab = () => {
const activeLinks = document.querySelectorAll<HTMLElement>('.router-link')
for (const active of activeLinks) {
// Skip login and logoff buttons
if (active.id && active.id !== 'login' && active.id !== 'logoff') {
active.style.backgroundColor = 'transparent'
active.style.color = '#39455f'
}
}
}
const setActive = (target: HTMLElement | null) => {
if (target) {
clearActiveTab()
target.style.backgroundColor = headerLinksBackgroundColor.value
target.style.color = HEADER_LINKS_COLOR
}
}
const handleMore = (command: string) => {
console.log('handleMore called with command:', command)
// Ignore divider
if (command === '---') {
return
}
let element = document.getElementById("selected-api-version")
if (element !== null) {
element.textContent = command;
}
if (command === '/message-docs') {
// Navigate to message docs list
console.log('Navigating to message docs list')
router.push({ name: 'message-docs-list' })
} else if (command.includes('_')) {
console.log('Navigating to message docs:', command)
router.push({ name: 'message-docs', params: { id: command } })
} else {
console.log('Navigating to resource docs:', `/resource-docs/${command}`)
console.log('Current route:', route.path)
// Clear operationid query param when changing versions to avoid showing non-existent operation
router.push(`/resource-docs/${command}`)
}
}
onMounted(async () => {
const currentUser = await getCurrentUser()
const currentResponseKeys = Object.keys(currentUser)
if (currentResponseKeys.includes('username')) {
isShowLoginButton.value = false
isShowLogOffButton.value = !isShowLoginButton.value
loginUsername.value = currentUser.username
} else {
isShowLoginButton.value = true
isShowLogOffButton.value = !isShowLoginButton.value
}
})
watchEffect(() => {
const routeName = typeof route.name === 'string' ? route.name : null
if (routeName && route.params && !route.params.id) {
setActive(document.getElementById(`header-nav-${routeName}`))
} else {
if (routeName === 'message-docs') {
clearActiveTab()
} else {
setActive(document.getElementById('header-nav-tags'))
}
}
})
const getCurrentPath = () => {
const currentPath = route.path
return currentPath
}
</script>
<template>
<img alt="OBP logo" class="logo" v-show="logo" :src="logo" />
<img alt="OBP logo" class="logo" v-show="!logo" src="@/assets/logo2x-1.png" />
<nav id="nav">
<RouterView name="header">
<a v-bind:href="obpApiHybridPost" class="router-link" id="header-nav-home">
{{ $t('header.portal_home') }}
</a>
<RouterLink class="router-link" id="header-nav-tags" :to="'/resource-docs/' + OBP_API_DEFAULT_RESOURCE_DOC_VERSION">{{
$t('header.api_explorer') }}</RouterLink>
<RouterLink class="router-link" id="header-nav-glossary" to="/glossary">{{
$t('header.glossary')
}}</RouterLink>
<RouterLink class="router-link" id="header-nav-help" to="/help">{{
$t('header.help')
}}</RouterLink>
<a v-if="showObpApiManagerButton && hasObpApiManagerHost" v-bind:href="obpApiManagerHost" class="router-link" id="header-nav-api-manager">
{{ $t('header.api_manager') }}
</a>
<SvelteDropdown
class="menu-right"
id="header-nav-versions"
label="Versions"
:items="sortedVersions"
:hover-color="headerLinksHoverColor"
:background-color="headerLinksBackgroundColor"
@select="handleMore"
/>
<SvelteDropdown
class="menu-right"
id="header-nav-message-docs"
label="Message Docs"
:items="obpMessageDocs"
:hover-color="headerLinksHoverColor"
:background-color="headerLinksBackgroundColor"
@select="handleMore"
/>
<!--<span class="el-dropdown-link">
<RouterLink class="router-link" id="header-nav-spaces" to="/spaces">{{
$t('header.spaces')
}}</RouterLink>
<el-icon class="el-icon--right">
<arrow-down />
</el-icon>
</span>-->
<a v-bind:href="'/api/oauth2/connect?redirect='+ encodeURIComponent(getCurrentPath())" v-show="isShowLoginButton" class="login-button router-link" id="login">
{{ $t('header.login') }}
</a>
<span v-show="isShowLogOffButton" class="login-user">{{ loginUsername }}</span>
<a v-bind:href="'/api/user/logoff?redirect=' + encodeURIComponent(getCurrentPath())" v-show="isShowLogOffButton" class="logoff-button router-link" id="logoff">
{{ $t('header.logoff') }}
</a>
</RouterView>
</nav>
</template>
<style>
nav {
text-align: right;
display: table-cell;
vertical-align: middle;
}
.logo {
display: table-cell;
vertical-align: middle;
transform: translateY(-50%);
top: 50%;
}
.header {
position: relative;
display: table;
}
.header::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 1px;
background-color: var(--el-border-color-light);
z-index: var(--el-index-normal);
}
.login-user {
font-family: 'Roboto';
padding: 9px;
color: #39455f;
font-size: 14px;
border-radius: 8px;
}
.router-link {
padding: 9px;
margin: 3px;
color: #39455f;
font-family: 'Roboto';
font-size: 14px;
text-decoration: none;
border-radius: 8px;
}
.router-link:hover {
background-color: v-bind(headerLinksBackgroundColor) !important;
color: v-bind(headerLinksHoverColor) !important;
}
.logo {
height: 40px;
position: absolute;
cursor: pointer;
}
a.login-button,
a.logoff-button {
margin: 5px;
color: #ffffff;
background-color: #32b9ce;
cursor: pointer;
}
.login-button:hover,
.logoff-button:hover {
color: #39455f;
}
/* Custom dropdown containers */
#header-nav-versions,
#header-nav-message-docs {
display: inline-block;
vertical-align: middle;
}
</style>