Feature: Adding Help page (gets data from glossary Item)

This commit is contained in:
simonredfern 2025-11-10 18:41:36 +01:00
parent 7905adb252
commit 2cbc48135f
7 changed files with 325 additions and 22 deletions

View File

@ -134,12 +134,15 @@ const getCurrentPath = () => {
<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>
<el-dropdown
class="menu-right router-link"
id="header-nav-more"
<el-dropdown
class="menu-right router-link"
id="header-nav-more"
@command="handleMore"
trigger="hover"
placement="bottom-end"

View File

@ -4,6 +4,7 @@
"api_explorer": "API Explorer",
"api_manager": "API Manager",
"glossary": "Glossary",
"help": "Help",
"more": "More",
"spaces": "Spaces",
"login": "Log on",

View File

@ -4,6 +4,7 @@
"api_explorer": "Explorador de API",
"api_manager": "Administrador de API",
"glossary": "Glosario",
"help": "Ayuda",
"more": "Mas",
"spaces": "Espacio",
"login": "Iniciar sesión",

View File

@ -1,19 +1,19 @@
{
"header": {
"portal_home": "Portal Acasă",
"api_explorer": "Explorator API",
"api_manager": "Administrator API",
"glossary": "Glosar",
"more": "Mai mult",
"spaces": "Spații",
"login": "Autentificare",
"logoff": "Deconectare"
},
"preview": {
"required_roles": "ROLURI NECESARE",
"validations": "VALIDĂRI",
"possible_errors": "POSIBILE ERORI",
"connector_methods": "METODE DE CONECTOR"
}
"header": {
"portal_home": "Portal Acasă",
"api_explorer": "Explorator API",
"api_manager": "Administrator API",
"glossary": "Glosar",
"help": "Ajutor",
"more": "Mai mult",
"spaces": "Spații",
"login": "Autentificare",
"logoff": "Deconectare"
},
"preview": {
"required_roles": "ROLURI NECESARE",
"validations": "VALIDĂRI",
"possible_errors": "POSIBILE ERORI",
"connector_methods": "METODE DE CONECTOR"
}
}

View File

@ -33,5 +33,47 @@ export async function getOBPGlossary(): Promise<any> {
const logMessage = `Loading glossary { version: ${OBP_API_VERSION} }`
console.log(logMessage)
updateLoadingInfoMessage(logMessage)
return await get(`obp/${OBP_API_VERSION}/api/glossary`)
const glossary = await get(`obp/${OBP_API_VERSION}/api/glossary`)
// Check if the API call failed
if (glossary && glossary.error) {
console.error('Failed to load glossary:', glossary.error)
return glossary
}
if (glossary && glossary.glossary_items) {
const itemCount = glossary.glossary_items.length
console.log(`✓ Loaded ${itemCount} glossary items`)
// Log specific items of interest
const helpItem = glossary.glossary_items.find(
(item: any) => item.title === 'API-Explorer-II-Help'
)
if (helpItem) {
console.log('✓ Found glossary item: API-Explorer-II-Help')
} else {
console.warn(
'⚠ Glossary item not found: API-Explorer-II-Help (Help page will show error message)'
)
}
} else {
console.warn('⚠ Glossary response does not contain glossary_items array')
}
return glossary
}
// Get a specific glossary item by title
export function getGlossaryItemByTitle(glossary: any, title: string): any | null {
if (!glossary || !glossary.glossary_items) {
console.warn(`Cannot retrieve glossary item "${title}": glossary data is not available`)
return null
}
const item = glossary.glossary_items.find((item: any) => item.title === title)
if (item) {
console.log(`Retrieved glossary item: ${title}`)
} else {
console.warn(`Glossary item not found: ${title}`)
}
return item || null
}

View File

@ -27,6 +27,7 @@
import { createRouter, createWebHistory } from 'vue-router'
import GlossaryView from '../views/GlossaryView.vue'
import HelpView from '../views/HelpView.vue'
import MessageDocsView from '../views/MessageDocsView.vue'
import BodyView from '../views/BodyView.vue'
import Content from '../components/Content.vue'
@ -58,10 +59,15 @@ export default async function router(): Promise<any> {
name: 'glossary',
component: isServerActive ? GlossaryView : InternalServerErrorView
},
{
path: '/help',
name: 'help',
component: isServerActive ? HelpView : InternalServerErrorView
},
{
path: '/message-docs/:id',
name: 'message-docs',
component: isServerActive ? MessageDocsView : InternalServerErrorView,
component: isServerActive ? MessageDocsView : InternalServerErrorView
},
{
path: '/operationid',

250
src/views/HelpView.vue Normal file
View File

@ -0,0 +1,250 @@
<!--
- 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, onBeforeMount, inject, computed } from 'vue'
import { obpGlossaryKey } from '@/obp/keys'
import { getGlossaryItemByTitle } from '@/obp/glossary'
const glossary = ref(inject(obpGlossaryKey)!)
const helpContent = ref<any>(null)
const notFound = ref(false)
onBeforeMount(() => {
const helpItem = getGlossaryItemByTitle(glossary.value, 'API-Explorer-II-Help')
if (helpItem) {
helpContent.value = helpItem
} else {
notFound.value = true
}
})
const hasContent = computed(() => helpContent.value !== null)
</script>
<template>
<el-container class="help-container">
<el-main class="help-content">
<el-scrollbar>
<el-backtop :right="100" :bottom="100" />
<div v-if="hasContent">
<h1 class="help-title">{{ helpContent.title }}</h1>
<div v-html="helpContent.description.html" class="content"></div>
</div>
<div v-else-if="notFound" class="not-found">
<h1>Help Content Not Available</h1>
<p>
The help content for API Explorer II could not be found. Please ensure that a glossary
item with the title "API-Explorer-II-Help" exists in the system.
</p>
</div>
</el-scrollbar>
</el-main>
</el-container>
</template>
<style scoped>
.help-container {
height: calc(100vh - 60px);
}
.help-content {
color: #39455f;
font-family: 'Roboto';
padding: 0;
}
.help-content :deep(.el-scrollbar__wrap) {
overflow-x: hidden;
}
.help-content :deep(.el-scrollbar__view) {
padding: 40px 60px;
word-wrap: break-word;
overflow-wrap: break-word;
max-width: 100%;
box-sizing: border-box;
}
.help-title {
font-size: 32px;
font-weight: 700;
margin-bottom: 20px;
color: #39455f;
word-wrap: break-word;
overflow-wrap: break-word;
}
.content {
font-size: 14px;
line-height: 1.6;
word-wrap: break-word;
overflow-wrap: break-word;
max-width: 100%;
}
.content :deep(*) {
max-width: 100%;
word-wrap: break-word;
overflow-wrap: break-word;
}
.content :deep(h1),
.content :deep(h2),
.content :deep(h3),
.content :deep(h4),
.content :deep(h5),
.content :deep(h6) {
font-family: 'Roboto';
font-weight: 700;
margin-top: 24px;
margin-bottom: 16px;
color: #39455f;
}
.content :deep(h1) {
font-size: 28px;
}
.content :deep(h2) {
font-size: 24px;
}
.content :deep(h3) {
font-size: 20px;
}
.content :deep(p) {
margin-bottom: 16px;
}
.content :deep(ul),
.content :deep(ol) {
margin-bottom: 16px;
padding-left: 24px;
}
.content :deep(li) {
margin-bottom: 8px;
}
.content :deep(img) {
max-width: 100%;
height: auto;
display: block;
margin: 16px 0;
}
.content :deep(table) {
max-width: 100%;
table-layout: auto;
word-wrap: break-word;
border-collapse: collapse;
margin: 16px 0;
}
.content :deep(table th),
.content :deep(table td) {
border: 1px solid #dcdfe6;
padding: 8px 12px;
}
.content :deep(table th) {
background-color: #f5f7fa;
font-weight: 700;
}
.content :deep(pre) {
max-width: 100%;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
background-color: #f5f7fa;
padding: 16px;
border-radius: 4px;
margin: 16px 0;
}
.content :deep(code) {
word-wrap: break-word;
overflow-wrap: break-word;
background-color: #f5f7fa;
padding: 2px 6px;
border-radius: 3px;
font-family: 'Courier New', monospace;
font-size: 13px;
}
.content :deep(pre code) {
background-color: transparent;
padding: 0;
}
.content :deep(strong) {
font-family: 'Roboto';
font-weight: 700;
}
.content :deep(a) {
text-decoration: underline;
font-family: 'Roboto';
font-size: 14px;
color: #409eff;
border-radius: 3px;
padding: 1px;
}
.content :deep(a):hover {
background-color: #ecf5ff;
color: #66b1ff;
}
.content :deep(blockquote) {
border-left: 4px solid #dcdfe6;
padding-left: 16px;
margin: 16px 0;
color: #606266;
font-style: italic;
}
.not-found {
text-align: center;
padding: 40px 20px;
}
.not-found h1 {
font-size: 24px;
color: #f56c6c;
margin-bottom: 16px;
}
.not-found p {
font-size: 14px;
color: #909399;
line-height: 1.6;
}
</style>