From cf1b2f5a3d82969a09c05a1a7fe6ec3b8ef00f4f Mon Sep 17 00:00:00 2001 From: ma-silva Date: Tue, 20 Jun 2023 17:35:30 +0800 Subject: [PATCH 01/68] FIX: search function --- src/components/SearchNav.vue | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/SearchNav.vue b/src/components/SearchNav.vue index 39ac6bc..3dc9755 100644 --- a/src/components/SearchNav.vue +++ b/src/components/SearchNav.vue @@ -103,20 +103,23 @@ const setActive = (event) => { } } +const iskeyFound = (keys, item) => keys.every((k) => item.toLowerCase().includes(k)) + const filterKeys = (keys, key) => { + const splitKey = key.split(' ').map((k) => k.toLowerCase()) return keys.filter((title) => { - const isGroupFound = title.toLowerCase().includes(key.toLowerCase()) - const items = docs.value[title].filter((item) => - item.summary.toLowerCase().includes(key.toLowerCase()) + const isGroupFound = iskeyFound(splitKey, title) + const items = docs.value[title].filter( + (item) => isGroupFound || iskeyFound(splitKey, item.summary) ) groups.value[title] = items return isGroupFound || items.length > 0 }) } -const searchEvent = (event) => { - if (event) { - sortedKeys.value = filterKeys(activeKeys.value, event) +const searchEvent = (value) => { + if (value) { + sortedKeys.value = filterKeys(activeKeys.value, value) } else { groups.value = JSON.parse(JSON.stringify(docs.value)) sortedKeys.value = Object.keys(groups.value).sort() From 166ee307abdeb4658d92972f4b725735209b4b5a Mon Sep 17 00:00:00 2001 From: ma-silva Date: Thu, 22 Jun 2023 22:38:01 +0800 Subject: [PATCH 02/68] FEATURE: product styling --- .env.example | 6 ++ components.d.ts | 1 + src/components/Content.vue | 17 ++-- src/components/HeaderNav.vue | 40 +++++++-- src/components/MessageDocsSearchNav.vue | 111 ++++++++++++++++++++++++ src/components/Preview.vue | 3 +- src/components/SearchNav.vue | 6 +- src/main.ts | 18 ++-- src/obp/index.ts | 3 +- src/obp/resource-docs.ts | 8 +- src/obp/style-setting.ts | 15 ++++ src/router/index.ts | 6 ++ src/views/MessageDocsView.vue | 63 ++++++++++++++ 13 files changed, 266 insertions(+), 31 deletions(-) create mode 100644 src/components/MessageDocsSearchNav.vue create mode 100644 src/obp/style-setting.ts create mode 100644 src/views/MessageDocsView.vue diff --git a/.env.example b/.env.example index f547258..1396ae5 100644 --- a/.env.example +++ b/.env.example @@ -5,3 +5,9 @@ VITE_OBP_EXPLORER_HOST=http://localhost:5173 VITE_OBP_CONSUMER_KEY=your_consumer_key VITE_OBP_CONSUMER_SECRET=your_consumer_secret VITE_OBP_REDIRECT_URL=http://localhost:5173/api/callback +# Product styling setting +#VITE_OBP_PRODUCT_LINKS_COLOR="#3665c7" +#VITE_OBP_PRODUCT_HEADER_LINKS_COLOR="#ffffff" +#VITE_OBP_PRODUCT_HEADER_LINKS_HOVER_COLOR="#ffffff" +#VITE_OBP_PRODUCT_HEADER_LINKS_BACKGROUND_COLOR="#f8b81e" +#VITE_OBP_PRODUCT_LOGO_SOURCE=https://static.openbankproject.com/xsquare/img/xsquare.jpg diff --git a/components.d.ts b/components.d.ts index fa3f81c..5f1754b 100644 --- a/components.d.ts +++ b/components.d.ts @@ -33,6 +33,7 @@ declare module '@vue/runtime-core' { GlossarySearchNav: typeof import('./src/components/GlossarySearchNav.vue')['default'] HeaderNav: typeof import('./src/components/HeaderNav.vue')['default'] Menu: typeof import('./src/components/Menu.vue')['default'] + MessageDocsSearchNav: typeof import('./src/components/MessageDocsSearchNav.vue')['default'] Preview: typeof import('./src/components/Preview.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] diff --git a/src/components/Content.vue b/src/components/Content.vue index a1846b2..9eec8ff 100644 --- a/src/components/Content.vue +++ b/src/components/Content.vue @@ -11,6 +11,7 @@ import { getCurrentUser } from '../obp' import { setTabActive, initializeAPICollections } from './SearchNav.vue' +import { summaryPagerLinksColor as summaryPagerLinksColorSetting } from '../obp/style-setting' const route = useRoute() const description = ref('') @@ -21,6 +22,7 @@ const displayNext = ref(true) const prev = ref({ id: 'prev' }) const next = ref({ id: 'next' }) const favoriteButtonStyle = ref('favorite favoriteButton') +const summaryPagerLinksColor = ref(summaryPagerLinksColorSetting) let routeId = '' let isFavorite = false let apiCollectionsEndpoint = inject('OBP-MyCollectionsEndpoint')! @@ -78,15 +80,19 @@ const createDeleteFavorite = async (): void => { apiCollectionsEndpoint = [] } if (isFavorite) { - await deleteMyAPICollectionEndpoint(routeId) + const response = await deleteMyAPICollectionEndpoint(routeId) favoriteButtonStyle.value = 'favorite favoriteButton' - showNotification('Removed from favourites.', 'success') + if (response) { + showNotification(response, 'success') + } else { + showNotification('Removed from favourites.', 'success') + } isFavorite = false apiCollectionsEndpoint = apiCollectionsEndpoint.filter((api) => api != routeId) } else { - await createMyAPICollectionEndpoint(routeId) + const response = await createMyAPICollectionEndpoint(routeId) favoriteButtonStyle.value = 'favorite activeFavoriteButton' - showNotification('Added to favourites.', 'success') + showNotification(response, 'success') isFavorite = true apiCollectionsEndpoint.push(routeId) } @@ -98,7 +104,6 @@ const createDeleteFavorite = async (): void => { const showNotification = (message: string, type: string): void => { ElNotification({ duration: 5500, - position: 'bottom-right', message, type }) @@ -214,7 +219,7 @@ div { .pager-router-link:hover, .pager-left:hover, .pager-right:hover { - color: #52b165; + color: v-bind(summaryPagerLinksColor); } .favorite { cursor: pointer; diff --git a/src/components/HeaderNav.vue b/src/components/HeaderNav.vue index 02aedcd..f1bfb1a 100644 --- a/src/components/HeaderNav.vue +++ b/src/components/HeaderNav.vue @@ -1,31 +1,49 @@ @@ -329,6 +349,10 @@ li { display: flex; flex-direction: row; } +.footnote { + color: #656665; + font-size: 12px; +} #search-input { -webkit-border-top-right-radius: 0; -moz-border-top-right-radius: 0; From 9f630c4973fb1a2e1760a00d9f2aa8aeb8cbf402 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 16 Aug 2023 21:36:31 +0800 Subject: [PATCH 15/68] REFACTOR: divider color and footnote color --- src/components/Preview.vue | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/Preview.vue b/src/components/Preview.vue index ed9cd4a..991c834 100644 --- a/src/components/Preview.vue +++ b/src/components/Preview.vue @@ -238,7 +238,7 @@ onBeforeRouteUpdate((to) => { - +

{{ $t('preview.validations') }}:

@@ -249,7 +249,7 @@ onBeforeRouteUpdate((to) => {
- +

{{ $t('preview.possible_errors') }}:

    @@ -258,7 +258,7 @@ onBeforeRouteUpdate((to) => {
- +

{{ $t('preview.connector_methods') }}:

    @@ -267,7 +267,7 @@ onBeforeRouteUpdate((to) => {
- +

Version: {{ footNote.version }}, function_name: by {{ footNote.functionName }}, @@ -350,9 +350,14 @@ li { flex-direction: row; } .footnote { - color: #656665; + color: var(--el-color-info); font-size: 12px; } +.divider { + border-top: 1px #253047 solid; + margin-left: -25px; + padding-right: 50px; +} #search-input { -webkit-border-top-right-radius: 0; -moz-border-top-right-radius: 0; From 1cec8c7a3f48623f21507d0f9cc29f7fe9a29427 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Sat, 26 Aug 2023 16:42:20 +0800 Subject: [PATCH 16/68] WIP: api version standards --- .env.example | 1 + server/app.ts | 2 +- src/components/Content.vue | 16 ++++++++---- src/components/HeaderNav.vue | 15 ++++++++--- src/components/Preview.vue | 17 ++++++++----- src/components/SearchNav.vue | 32 +++++++++++++++++++----- src/main.ts | 6 ++--- src/obp/message-docs.ts | 16 +++--------- src/obp/resource-docs.ts | 48 +++++++++++++++++++++--------------- 9 files changed, 97 insertions(+), 56 deletions(-) diff --git a/.env.example b/.env.example index 66d8443..7c3f101 100644 --- a/.env.example +++ b/.env.example @@ -5,6 +5,7 @@ VITE_OBP_EXPLORER_HOST=http://localhost:5173 VITE_OBP_CONSUMER_KEY=your_consumer_key VITE_OBP_CONSUMER_SECRET=your_consumer_secret VITE_OBP_REDIRECT_URL=http://localhost:5173/api/callback +VITE_OPB_SERVER_SESSION_PASSWORD=very secret # Product styling setting #VITE_OBP_LINKS_COLOR="#52b165" #VITE_OBP_HEADER_LINKS_COLOR="#39455f" diff --git a/server/app.ts b/server/app.ts index 8cc36be..ffb8ac0 100644 --- a/server/app.ts +++ b/server/app.ts @@ -11,7 +11,7 @@ const app: Application = express() app.use(express.json()) app.use( session({ - secret: 'very secret', + secret: process.env.VITE_OPB_SERVER_SESSION_PASSWORD, resave: false, saveUninitialized: true }) diff --git a/src/components/Content.vue b/src/components/Content.vue index 9eec8ff..4abe829 100644 --- a/src/components/Content.vue +++ b/src/components/Content.vue @@ -12,11 +12,15 @@ import { } from '../obp' import { setTabActive, initializeAPICollections } from './SearchNav.vue' import { summaryPagerLinksColor as summaryPagerLinksColorSetting } from '../obp/style-setting' +import { version } from '../obp' +import { getGroupedResourceDocs } from '../obp/resource-docs' const route = useRoute() +const configVersion = 'OBP' + version const description = ref('') const summary = ref('') -const docs = inject('OBP-ResourceDocs') +const resourceDocs = inject('OBP-ResourceDocs') +const docs = getGroupedResourceDocs(configVersion, resourceDocs) const displayPrev = ref(true) const displayNext = ref(true) const prev = ref({ id: 'prev' }) @@ -27,8 +31,8 @@ let routeId = '' let isFavorite = false let apiCollectionsEndpoint = inject('OBP-MyCollectionsEndpoint')! -const setOperationDetails = (id: string): void => { - const operation = getOperationDetails(docs, id) +const setOperationDetails = (id: string, version: string): void => { + const operation = getOperationDetails(version, id, resourceDocs) description.value = operation.description summary.value = operation.summary } @@ -111,13 +115,15 @@ const showNotification = (message: string, type: string): void => { onMounted(async () => { routeId = route.params.id - setOperationDetails(routeId) + const version = route.query.version ? route.query.version : configVersion + setOperationDetails(routeId, version) setPager(routeId) await tagFavoriteButton(routeId) }) onBeforeRouteUpdate(async (to) => { routeId = to.params.id - setOperationDetails(routeId) + const version = route.query.version ? route.query.version : configVersion + setOperationDetails(routeId, version) setPager(routeId) await tagFavoriteButton(routeId) }) diff --git a/src/components/HeaderNav.vue b/src/components/HeaderNav.vue index fa114c5..d466262 100644 --- a/src/components/HeaderNav.vue +++ b/src/components/HeaderNav.vue @@ -1,8 +1,9 @@ -

+
Loading...
diff --git a/package.json b/package.json index 2e963d6..11a4358 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "api-explorer", - "version": "0.0.0", + "version": "1.0.1", "private": true, "scripts": { "dev": "vite & ts-node server/app.ts", diff --git a/server/controllers/StatusController.ts b/server/controllers/StatusController.ts new file mode 100644 index 0000000..d29ce19 --- /dev/null +++ b/server/controllers/StatusController.ts @@ -0,0 +1,87 @@ +import { Controller, Session, Req, Res, Get } from 'routing-controllers' +import { Request, Response } from 'express' +import OBPClientService from '../services/OBPClientService' +import OauthInjectedService from '../services/OauthInjectedService' +import { Service } from 'typedi' +import { OAuthConfig } from 'obp-typescript' + +@Service() +@Controller('/status') +export class StatusController { + private obpExplorerHome = process.env.VITE_OBP_EXPLORER_HOST + private connectors = [ + 'kafka_vSept2018', + 'akka_vDec2018', + 'rest_vMar2019', + 'stored_procedure_vDec2019' + ] + constructor( + private obpClientService: OBPClientService, + private oauthInjectedService: OauthInjectedService + ) {} + @Get('/') + async index( + @Session() session: any, + @Req() request: Request, + @Res() response: Response + ): Response { + const oauthConfig = session['clientConfig'] + const version = this.obpClientService.getOBPVersion() + const apiVersions = await this.checkApiVersions(oauthConfig, version) + const messageDocs = await this.checkMessagDocs(oauthConfig, version) + const resourceDocs = await this.checkResourceDocs(oauthConfig, version) + return response.json({ + status: apiVersions && messageDocs && resourceDocs, + apiVersions, + messageDocs, + resourceDocs + }) + } + + isCodeError(response: any): boolean { + if (!response || Object.keys(response).length == 0) return true + if (Object.keys(response).includes('code')) { + const code = response['code'] + if (code >= 400) return true + } + return false + } + + async checkResourceDocs(oauthConfig: OAuthConfig, version: string): Promise { + try { + const resourceDocs = await this.obpClientService.get( + `/obp/${version}/resource-docs/${version}/obp`, + oauthConfig + ) + return !this.isCodeError(resourceDocs) + } catch (error) { + return false + } + } + async checkMessagDocs(oauthConfig: OAuthConfig, version: string): Promise { + try { + const messageDocsCodeResult = await Promise.all( + this.connectors.map(async (connector) => { + return !this.isCodeError( + await this.obpClientService.get( + `/obp/${version}/message-docs/${connector}`, + oauthConfig + ) + ) + }) + ) + return messageDocsCodeResult.every((isCodeError: boolean) => isCodeError) + } catch (error) { + return false + } + } + + async checkApiVersions(oauthConfig: OAuthConfig, version: string): Promise { + try { + const versions = await this.obpClientService.get(`/obp/${version}/api/versions`, oauthConfig) + return !this.isCodeError(versions) + } catch (error) { + return false + } + } +} diff --git a/src/components/Content.vue b/src/components/Content.vue index 4abe829..95d1f54 100644 --- a/src/components/Content.vue +++ b/src/components/Content.vue @@ -1,5 +1,5 @@ + + + + diff --git a/src/views/InternalServerErrorView.vue b/src/views/InternalServerErrorView.vue new file mode 100644 index 0000000..5781747 --- /dev/null +++ b/src/views/InternalServerErrorView.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/vite.config.ts b/vite.config.ts index d7f56b8..d8ff8b9 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -34,6 +34,7 @@ export default defineConfig({ __VUE_I18N_FULL_INSTALL__: true, __VUE_I18N_LEGACY_API__: false, __INTLIFY_PROD_DEVTOOLS__: false, + __APP_VERSION__: JSON.stringify(process.env.npm_package_version) }, server:{ proxy: { From 65978c8f764082e2b527852baf1ec98a567161ae Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Mon, 18 Sep 2023 14:29:05 +0800 Subject: [PATCH 24/68] REVISIONS: caching data FIX: favourites --- src/components/SearchNav.vue | 2 +- src/main.ts | 100 ++++++++++++++++++----------------- src/obp/index.ts | 6 ++- src/obp/message-docs.ts | 4 +- src/obp/resource-docs.ts | 4 +- 5 files changed, 64 insertions(+), 52 deletions(-) diff --git a/src/components/SearchNav.vue b/src/components/SearchNav.vue index 94b55f9..6651003 100644 --- a/src/components/SearchNav.vue +++ b/src/components/SearchNav.vue @@ -177,7 +177,7 @@ const searchEvent = (value) => { @click="setActive" > { const app = createApp(App) const router = await appRouter() - app.provide('OBP-APIActiveVersions', [version]) try { - const isServerActive = await isServerUp() - if (isServerActive) await setupData(app) + const isDataSetup = await setupData(app) const messages = Object.assign(languages) const i18n = createI18n({ @@ -40,7 +38,7 @@ import '@fontsource/roboto/700.css' app.mount('#app') - if (!isServerActive) router.replace({ path: 'api-server-error' }) + if (!isDataSetup) router.replace({ path: 'api-server-error' }) app.config.errorHandler = (error) => { console.log(error) router.replace({ path: 'error' }) @@ -52,51 +50,57 @@ import '@fontsource/roboto/700.css' })() async function setupData(app: App) { - const worker = new Worker('/js/worker/web-worker.js') - const resourceDocsCache = await caches.open('obp-resource-docs-cache') - const resourceDocsCacheResponse = await resourceDocsCache.match('/') - const messageDocsCache = await caches.open('obp-message-docs-cache') - const messageDocsCacheResponse = await messageDocsCache.match('/') - const { resourceDocs, groupedDocs } = await cacheResourceDocs( - resourceDocsCache, - resourceDocsCacheResponse, - worker - ) - const messageDocs = await cacheMessageDocs(messageDocsCache, messageDocsCacheResponse, worker) + try { + const worker = new Worker('/js/worker/web-worker.js') + const resourceDocsCache = await caches.open('obp-resource-docs-cache') + const resourceDocsCacheResponse = await resourceDocsCache.match('/') + const messageDocsCache = await caches.open('obp-message-docs-cache') + const messageDocsCacheResponse = await messageDocsCache.match('/') + const { resourceDocs, groupedDocs } = await cacheResourceDocs( + resourceDocsCache, + resourceDocsCacheResponse, + worker + ) + const messageDocs = await cacheMessageDocs(messageDocsCache, messageDocsCacheResponse, worker) - //Listen to Web worker - worker.onmessage = async (event) => { - //Update cache docs data in the background - if (event.data === 'update-resource-docs') { - await cacheResourceDocsDoc(resourceDocsCache) + //Listen to Web worker + worker.onmessage = async (event) => { + //Update cache docs data in the background + if (event.data === 'update-resource-docs') { + await cacheResourceDocsDoc(resourceDocsCache) + } + if (event.data === 'update-message-docs') { + await cacheMessageDocsDoc(messageDocsCache) + } } - if (event.data === 'update-message-docs') { - await cacheMessageDocsDoc(messageDocsCache) + + app.provide('OBP-ResourceDocs', resourceDocs) + app.provide('OBP-APIActiveVersions', Object.keys(resourceDocs).sort()) + app.provide('OBP-GroupedResourceDocs', groupedDocs) + app.provide('OBP-GroupedMessageDocs', messageDocs) + app.provide('OBP-API-Host', import.meta.env.VITE_OBP_API_HOST) + const glossary = await getOBPGlossary() + app.provide('OBP-Glossary', glossary) + + const apiCollections = (await getMyAPICollections()).api_collections + if (apiCollections && apiCollections.length > 0) { + //Uncomment this when other collection will be supported. + //for (const { api_collection_name } of apiCollections) { + // const apiCollectionsEndpoint = ( + // await getMyAPICollectionsEndpoint(api_collection_name) + // ).api_collection_endpoints.map((api) => api.operation_id) + // app.provide('OBP-MyCollectionsEndpoint', apiCollectionsEndpoint) + //} + const apiCollectionsEndpoint = ( + await getMyAPICollectionsEndpoint('Favourites') + ).api_collection_endpoints.map((api) => api.operation_id) + app.provide('OBP-MyCollectionsEndpoint', apiCollectionsEndpoint) + } else { + app.provide('OBP-MyCollectionsEndpoint', undefined) } - } - - app.provide('OBP-ResourceDocs', resourceDocs) - app.provide('OBP-APIActiveVersions', Object.keys(resourceDocs).sort()) - app.provide('OBP-GroupedResourceDocs', groupedDocs) - app.provide('OBP-GroupedMessageDocs', messageDocs) - app.provide('OBP-API-Host', import.meta.env.VITE_OBP_API_HOST) - const glossary = await getOBPGlossary() - app.provide('OBP-Glossary', glossary) - - const apiCollections = (await getMyAPICollections()).api_collections - if (apiCollections && apiCollections.length > 0) { - //Uncomment this when other collection will be supported. - //for (const { api_collection_name } of apiCollections) { - // const apiCollectionsEndpoint = ( - // await getMyAPICollectionsEndpoint(api_collection_name) - // ).api_collection_endpoints.map((api) => api.operation_id) - // app.provide('OBP-MyCollectionsEndpoint', apiCollectionsEndpoint) - //} - const apiCollectionsEndpoint = ( - await getMyAPICollectionsEndpoint('Favourites') - ).api_collection_endpoints.map((api) => api.operation_id) - app.provide('OBP-MyCollectionsEndpoint', apiCollectionsEndpoint) - } else { - app.provide('OBP-MyCollectionsEndpoint', undefined) + return true + } catch (error) { + app.provide('OBP-APIActiveVersions', [version]) + return false } } diff --git a/src/obp/index.ts b/src/obp/index.ts index 81a17f5..a934ce6 100644 --- a/src/obp/index.ts +++ b/src/obp/index.ts @@ -3,8 +3,12 @@ import superagent from 'superagent' export const version = import.meta.env.VITE_OBP_API_VERSION const default_collection_name = 'Favourites' +export async function serverStatus(): Promise { + return (await superagent.get(`/api/status`)).body +} + export async function isServerUp(): Promise { - return (await superagent.get(`/api/status`)).body['status'] + return (await serverStatus())['status'] } export async function get(path: string): Promise { diff --git a/src/obp/message-docs.ts b/src/obp/message-docs.ts index e2c56ef..fa2a7a6 100644 --- a/src/obp/message-docs.ts +++ b/src/obp/message-docs.ts @@ -1,4 +1,4 @@ -import { version, get } from '../obp' +import { version, get, isServerUp } from '../obp' export const connectors = [ 'kafka_vSept2018', @@ -47,6 +47,8 @@ export async function cache( } catch (error) { console.warn('No message docs cache or malformed cache.') console.log('Caching message docs...') + const isServerActive = await isServerUp() + if (!isServerActive) throw new Error('API Server is not responding.') return await getCacheDoc(messageDocsCache, worker) } } diff --git a/src/obp/resource-docs.ts b/src/obp/resource-docs.ts index ab4a37e..b468245 100644 --- a/src/obp/resource-docs.ts +++ b/src/obp/resource-docs.ts @@ -1,4 +1,4 @@ -import { get, version as configVersion } from '../obp' +import { get, isServerUp, version as configVersion } from '../obp' import { getOBPAPIVersions } from '../obp/api-version' // Get Resource Docs @@ -60,6 +60,8 @@ export async function cache( } catch (error) { console.warn('No resource docs cache or malformed cache.') console.log('Caching resource docs...') + const isServerActive = await isServerUp() + if (!isServerActive) throw new Error('API Server is not responding.') const resourceDocs = await getCacheDoc(resourceDocsCache, worker) const groupedDocs = getGroupedResourceDocs('OBP' + configVersion, resourceDocs) return { resourceDocs, groupedDocs } From 953b56a552ebb1772bf4d1d7760bf142ecba157f Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 26 Sep 2023 22:24:05 +0800 Subject: [PATCH 25/68] FEAT: styled status page --- src/router/index.ts | 6 +++ src/views/APIServerStatusView.vue | 81 +++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/views/APIServerStatusView.vue diff --git a/src/router/index.ts b/src/router/index.ts index 0335047..bb46f14 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -7,6 +7,7 @@ import Preview from '../components/Preview.vue' import NotFoundView from '../views/NotFoundView.vue' import InternalServerErrorView from '../views/InternalServerErrorView.vue' import APIServerErrorView from '../views/APIServerErrorView.vue' +import APIServerStatusView from '../views/APIServerStatusView.vue' import { isServerUp } from '../obp' export default async function router(): Promise { @@ -19,6 +20,11 @@ export default async function router(): Promise { path: '/', redirect: isServerActive ? '/operationid' : '/api-server-error' }, + { + path: '/status', + name: 'status', + component: APIServerStatusView + }, { path: '/glossary', name: 'glossary', diff --git a/src/views/APIServerStatusView.vue b/src/views/APIServerStatusView.vue new file mode 100644 index 0000000..09f0445 --- /dev/null +++ b/src/views/APIServerStatusView.vue @@ -0,0 +1,81 @@ + + + + + From 39df942d8c9393e59c1b006982a0f5c66efdd466 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 27 Sep 2023 18:20:18 +0800 Subject: [PATCH 26/68] FIX: missing Berlin Group --- package.json | 2 +- src/obp/resource-docs.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 11a4358..fcaf095 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "api-explorer", - "version": "1.0.1", + "version": "1.0.2", "private": true, "scripts": { "dev": "vite & ts-node server/app.ts", diff --git a/src/obp/resource-docs.ts b/src/obp/resource-docs.ts index b468245..fa25aff 100644 --- a/src/obp/resource-docs.ts +++ b/src/obp/resource-docs.ts @@ -25,9 +25,9 @@ export async function cacheDoc(resourceDocsCache: any): Promise { if (apiVersions) { const scannedAPIVersions = apiVersions.scanned_api_versions const resourceDocsMapping: any = {} - for (const { urlPrefix, API_VERSION } of scannedAPIVersions) { - if (urlPrefix) { - const version = `${urlPrefix.toUpperCase()}${API_VERSION}` + for (const { apiStandard, API_VERSION } of scannedAPIVersions) { + if (apiStandard) { + const version = `${apiStandard.toUpperCase()}${API_VERSION}` const resourceDocs = await getOBPResourceDocs(version) if (version && Object.keys(resourceDocs).includes('resource_docs')) resourceDocsMapping[version] = resourceDocs From 360737d52acd80eccdfe327bfcd6d1c227ab0c76 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 27 Sep 2023 20:02:32 +0800 Subject: [PATCH 27/68] FIX: background worker --- src/main.ts | 19 ++++++++++--------- src/obp/message-docs.ts | 9 ++++----- src/obp/resource-docs.ts | 9 ++++----- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/main.ts b/src/main.ts index 8d2acba..fd7f489 100644 --- a/src/main.ts +++ b/src/main.ts @@ -21,7 +21,8 @@ import '@fontsource/roboto/700.css' const app = createApp(App) const router = await appRouter() try { - const isDataSetup = await setupData(app) + const worker = new Worker('/js/worker/web-worker.js') + const isDataSetup = await setupData(app, worker) const messages = Object.assign(languages) const i18n = createI18n({ @@ -49,19 +50,12 @@ import '@fontsource/roboto/700.css' } })() -async function setupData(app: App) { +async function setupData(app: App, worker: Worker) { try { - const worker = new Worker('/js/worker/web-worker.js') const resourceDocsCache = await caches.open('obp-resource-docs-cache') const resourceDocsCacheResponse = await resourceDocsCache.match('/') const messageDocsCache = await caches.open('obp-message-docs-cache') const messageDocsCacheResponse = await messageDocsCache.match('/') - const { resourceDocs, groupedDocs } = await cacheResourceDocs( - resourceDocsCache, - resourceDocsCacheResponse, - worker - ) - const messageDocs = await cacheMessageDocs(messageDocsCache, messageDocsCacheResponse, worker) //Listen to Web worker worker.onmessage = async (event) => { @@ -74,6 +68,13 @@ async function setupData(app: App) { } } + const { resourceDocs, groupedDocs } = await cacheResourceDocs( + resourceDocsCache, + resourceDocsCacheResponse, + worker + ) + const messageDocs = await cacheMessageDocs(messageDocsCache, messageDocsCacheResponse, worker) + app.provide('OBP-ResourceDocs', resourceDocs) app.provide('OBP-APIActiveVersions', Object.keys(resourceDocs).sort()) app.provide('OBP-GroupedResourceDocs', groupedDocs) diff --git a/src/obp/message-docs.ts b/src/obp/message-docs.ts index fa2a7a6..c6207fd 100644 --- a/src/obp/message-docs.ts +++ b/src/obp/message-docs.ts @@ -31,10 +31,8 @@ export async function cacheDoc(messageDocsCache: any): Promise { return messageDocs } -async function getCacheDoc(messageDocsCache: any, worker: any): Promise { - const docs = await cacheDoc(messageDocsCache) - worker.postMessage('update-message-docs') - return docs +async function getCacheDoc(messageDocsCache: any): Promise { + return await cacheDoc(messageDocsCache) } export async function cache( @@ -43,12 +41,13 @@ export async function cache( worker: any ): Promise { try { + worker.postMessage('update-message-docs') return await messageDocsCacheResponse.json() } catch (error) { console.warn('No message docs cache or malformed cache.') console.log('Caching message docs...') const isServerActive = await isServerUp() if (!isServerActive) throw new Error('API Server is not responding.') - return await getCacheDoc(messageDocsCache, worker) + return await getCacheDoc(messageDocsCache) } } diff --git a/src/obp/resource-docs.ts b/src/obp/resource-docs.ts index fa25aff..69bb916 100644 --- a/src/obp/resource-docs.ts +++ b/src/obp/resource-docs.ts @@ -42,10 +42,8 @@ export async function cacheDoc(resourceDocsCache: any): Promise { } } -async function getCacheDoc(resourceDocsCache: any, worker: any): Promise { - const docs = await cacheDoc(resourceDocsCache) - worker.postMessage('update-resource-docs') - return docs +async function getCacheDoc(resourceDocsCache: any): Promise { + return await cacheDoc(resourceDocsCache) } export async function cache( @@ -54,6 +52,7 @@ export async function cache( worker: any ): Promise { try { + worker.postMessage('update-resource-docs') const resourceDocs = await resourceDocsCacheResponse.json() const groupedDocs = getGroupedResourceDocs('OBP' + configVersion, resourceDocs) return { resourceDocs, groupedDocs } @@ -62,7 +61,7 @@ export async function cache( console.log('Caching resource docs...') const isServerActive = await isServerUp() if (!isServerActive) throw new Error('API Server is not responding.') - const resourceDocs = await getCacheDoc(resourceDocsCache, worker) + const resourceDocs = await getCacheDoc(resourceDocsCache) const groupedDocs = getGroupedResourceDocs('OBP' + configVersion, resourceDocs) return { resourceDocs, groupedDocs } } From 8f705dc315654bf748298dacc7cf471d6f975142 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Thu, 28 Sep 2023 00:43:53 +0800 Subject: [PATCH 28/68] REFACTOR: API server status validation --- src/components/HeaderNav.vue | 14 +++----------- src/main.ts | 2 ++ src/obp/index.ts | 3 ++- src/obp/message-docs.ts | 4 +++- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/components/HeaderNav.vue b/src/components/HeaderNav.vue index e2d9fa7..9dacbe7 100644 --- a/src/components/HeaderNav.vue +++ b/src/components/HeaderNav.vue @@ -18,6 +18,7 @@ const obpApiManagerHost = ref(import.meta.env.VITE_OBP_API_MANAGER_HOST) const loginUsername = ref('') const logoffurl = ref('') const obpApiVersions = ref(inject('OBP-APIActiveVersions')!) +const obpMessageDocs = ref(Object.keys(inject('OBP-GroupedMessageDocs')!)) const isShowLoginButton = ref(true) const isShowLogOffButton = ref(false) const logo = ref(logoSource) @@ -110,17 +111,8 @@ watchEffect(() => { {{ value }} - Message Docs for: Akka - Message Docs for: Kafka - Message Docs for: Rest - Message Docs for: Stored Procedue + Message Docs for: {{ value }} diff --git a/src/main.ts b/src/main.ts index fd7f489..7808902 100644 --- a/src/main.ts +++ b/src/main.ts @@ -62,9 +62,11 @@ async function setupData(app: App, worker: Worker) { //Update cache docs data in the background if (event.data === 'update-resource-docs') { await cacheResourceDocsDoc(resourceDocsCache) + console.log('Resource Docs cache was updated.') } if (event.data === 'update-message-docs') { await cacheMessageDocsDoc(messageDocsCache) + console.log('Message Docs cache was updated.') } } diff --git a/src/obp/index.ts b/src/obp/index.ts index a934ce6..c5d8191 100644 --- a/src/obp/index.ts +++ b/src/obp/index.ts @@ -8,7 +8,8 @@ export async function serverStatus(): Promise { } export async function isServerUp(): Promise { - return (await serverStatus())['status'] + //Set the status to offline/down only if all the resource data is not availalbe. + return !Object.values(await serverStatus()).every((isTrue) => !isTrue) } export async function get(path: string): Promise { diff --git a/src/obp/message-docs.ts b/src/obp/message-docs.ts index c6207fd..06a6bab 100644 --- a/src/obp/message-docs.ts +++ b/src/obp/message-docs.ts @@ -24,7 +24,9 @@ export async function cacheDoc(messageDocsCache: any): Promise { const messageDocs = await connectors.reduce(async (agroup: any, connector: any) => { const group = await agroup const docs = await getOBPMessageDocs(connector) - group[connector] = getGroupedMessageDocs(docs) + if (!Object.keys(docs).includes('code')) { + group[connector] = getGroupedMessageDocs(docs) + } return group }, Promise.resolve({})) await messageDocsCache.put('/', new Response(JSON.stringify(messageDocs))) From 8af4a4d7e4a35d70835af02069ba87af3b23ee75 Mon Sep 17 00:00:00 2001 From: nemo Date: Wed, 15 Nov 2023 18:00:53 +0000 Subject: [PATCH 29/68] Add loading page and WIP: session cookies --- index.html | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++- server/app.ts | 7 ++++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index cd06207..e22162e 100644 --- a/index.html +++ b/index.html @@ -6,12 +6,63 @@ API Explorer + + -
Loading...
+ + +
+
+ +
+

Loading...

+
+
+ diff --git a/server/app.ts b/server/app.ts index ffb8ac0..b5d6535 100644 --- a/server/app.ts +++ b/server/app.ts @@ -13,7 +13,12 @@ app.use( session({ secret: process.env.VITE_OPB_SERVER_SESSION_PASSWORD, resave: false, - saveUninitialized: true + saveUninitialized: true, + cookie: { + httpOnly: true, + secure: true, + maxAge: 300*1000, // 5 minutes in milliseconds + } }) ) useContainer(Container) From fd5234c16db5eae7e98d9df193c7f877caee7ffe Mon Sep 17 00:00:00 2001 From: nemo Date: Fri, 17 Nov 2023 11:08:06 +0000 Subject: [PATCH 30/68] Add Collections Menu and add fancy loading screen. As proof of concept, the collection url-text pairs are hard-coded into into the Collections.vue file. This is to be better configured later on. --- index.html | 4 +-- src/components/Collections.vue | 59 ++++++++++++++++++++++++++++++++++ src/views/BodyView.vue | 10 ++++++ 3 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 src/components/Collections.vue diff --git a/index.html b/index.html index e22162e..f033dd8 100644 --- a/index.html +++ b/index.html @@ -30,6 +30,7 @@ position: relative; width: 80px; height: 80px; + margin-top: 15px; } .lds-dual-ring:after { content: " "; @@ -57,9 +58,8 @@
- +
-

Loading...

diff --git a/src/components/Collections.vue b/src/components/Collections.vue new file mode 100644 index 0000000..6160add --- /dev/null +++ b/src/components/Collections.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/src/views/BodyView.vue b/src/views/BodyView.vue index 6a6fa5e..8ca0cf0 100644 --- a/src/views/BodyView.vue +++ b/src/views/BodyView.vue @@ -1,6 +1,7 @@