| | import { getPathWithoutLanguage, getPathWithoutVersion } from '@/frame/lib/path-utils' |
| | import { renderContent } from '@/content-render/index' |
| | import { executeWithFallback } from '@/languages/lib/render-with-fallback' |
| | import getApplicableVersions from '@/versions/lib/get-applicable-versions' |
| | import Permalink from '@/frame/lib/permalink' |
| | import getLinkData from './get-link-data' |
| |
|
| | export interface JourneyContext { |
| | trackId: string |
| | trackName: string |
| | trackTitle: string |
| | journeyTitle: string |
| | journeyPath: string |
| | currentGuideIndex: number |
| | numberOfGuides: number |
| | nextGuide?: { |
| | href: string |
| | title: string |
| | } |
| | prevGuide?: { |
| | href: string |
| | title: string |
| | } |
| | } |
| |
|
| | export interface JourneyTrack { |
| | id: string |
| | title: string |
| | description?: string |
| | guides: Array<{ |
| | href: string |
| | title: string |
| | }> |
| | } |
| |
|
| | type JourneyPage = { |
| | layout?: string |
| | title?: string |
| | permalink?: string |
| | relativePath?: string |
| | versions?: any |
| | journeyTracks?: Array<{ |
| | id: string |
| | title: string |
| | description?: string |
| | guides: string[] |
| | }> |
| | } |
| |
|
| | type Pages = Record<string, any> |
| | type ContentContext = { |
| | currentProduct?: string |
| | currentLanguage?: string |
| | currentVersion?: string |
| | pages?: Pages |
| | redirects?: any |
| | [key: string]: any |
| | } |
| |
|
| | |
| | let cachedJourneyPages: JourneyPage[] | null = null |
| |
|
| | function getJourneyPages(pages: Pages): JourneyPage[] { |
| | if (!cachedJourneyPages) { |
| | cachedJourneyPages = Object.values(pages).filter( |
| | (page: any) => page.journeyTracks && page.journeyTracks.length > 0, |
| | ) as JourneyPage[] |
| | } |
| | return cachedJourneyPages |
| | } |
| |
|
| | function normalizeGuidePath(path: string): string { |
| | |
| | const pathWithSlash = path.startsWith('/') ? path : `/${path}` |
| |
|
| | |
| | const withoutVersion = getPathWithoutVersion(pathWithSlash) |
| | const withoutLanguage = getPathWithoutLanguage(withoutVersion) |
| |
|
| | |
| | return withoutLanguage && withoutLanguage.startsWith('/') |
| | ? withoutLanguage |
| | : `/${withoutLanguage || path}` |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | export async function resolveJourneyContext( |
| | articlePath: string, |
| | pages: Pages, |
| | context: ContentContext, |
| | currentJourneyPage?: JourneyPage, |
| | ): Promise<JourneyContext | null> { |
| | const normalizedPath = normalizeGuidePath(articlePath) |
| |
|
| | |
| | const journeyPages = currentJourneyPage ? [currentJourneyPage] : getJourneyPages(pages) |
| |
|
| | let result: JourneyContext | null = null |
| |
|
| | |
| | for (const journeyPage of journeyPages) { |
| | if (!journeyPage.journeyTracks) continue |
| |
|
| | |
| | |
| | |
| | if (journeyPage.versions) { |
| | const journeyVersions = getApplicableVersions(journeyPage.versions) |
| | if (!journeyVersions.includes(context.currentVersion || '')) { |
| | continue |
| | } |
| | } |
| |
|
| | for (const track of journeyPage.journeyTracks) { |
| | if (!track.guides || !Array.isArray(track.guides)) continue |
| |
|
| | |
| | let guideIndex = -1 |
| |
|
| | for (let i = 0; i < track.guides.length; i++) { |
| | const guidePath = track.guides[i] |
| | let renderedGuidePath = guidePath |
| |
|
| | |
| | try { |
| | renderedGuidePath = await executeWithFallback( |
| | context, |
| | () => renderContent(guidePath, context, { textOnly: true }), |
| | () => guidePath, |
| | ) |
| | } catch { |
| | |
| | renderedGuidePath = guidePath |
| | } |
| |
|
| | const normalizedGuidePath = normalizeGuidePath(renderedGuidePath) |
| |
|
| | if (normalizedGuidePath === normalizedPath) { |
| | guideIndex = i |
| | break |
| | } |
| | } |
| |
|
| | if (guideIndex >= 0) { |
| | result = { |
| | trackId: track.id, |
| | trackName: track.id, |
| | trackTitle: track.title, |
| | journeyTitle: journeyPage.title || '', |
| | journeyPath: |
| | journeyPage.permalink || Permalink.relativePathToSuffix(journeyPage.relativePath || ''), |
| | currentGuideIndex: guideIndex, |
| | numberOfGuides: track.guides.length, |
| | } |
| |
|
| | |
| | if (guideIndex > 0) { |
| | const prevGuidePath = track.guides[guideIndex - 1] |
| | try { |
| | const resultData = await getLinkData(prevGuidePath, context, { |
| | title: true, |
| | intro: false, |
| | fullTitle: false, |
| | }) |
| | if (resultData && resultData.length > 0) { |
| | const linkResult = resultData[0] |
| | result.prevGuide = { |
| | href: linkResult.href, |
| | title: linkResult.title || '', |
| | } |
| | } |
| | } catch (error) { |
| | console.warn('Could not get link data for previous guide:', prevGuidePath, error) |
| | } |
| | } |
| |
|
| | |
| | if (guideIndex < track.guides.length - 1) { |
| | const nextGuidePath = track.guides[guideIndex + 1] |
| | try { |
| | const resultData = await getLinkData(nextGuidePath, context, { |
| | title: true, |
| | intro: false, |
| | fullTitle: false, |
| | }) |
| | if (resultData && resultData.length > 0) { |
| | const linkResult = resultData[0] |
| | result.nextGuide = { |
| | href: linkResult.href, |
| | title: linkResult.title || '', |
| | } |
| | } |
| | } catch (error) { |
| | console.warn('Could not get link data for next guide:', nextGuidePath, error) |
| | } |
| | } |
| |
|
| | break |
| | } |
| | } |
| |
|
| | if (result) break |
| | } |
| |
|
| | return result |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | export async function resolveJourneyTracks( |
| | journeyTracks: any[], |
| | context: ContentContext, |
| | ): Promise<JourneyTrack[]> { |
| | const result = await Promise.all( |
| | journeyTracks.map(async (track: any) => { |
| | |
| | const renderedTitle = await renderContent(track.title, context, { textOnly: true }) |
| | const renderedDescription = track.description |
| | ? await renderContent(track.description, context, { textOnly: true }) |
| | : undefined |
| |
|
| | const guides = await Promise.all( |
| | track.guides.map(async (guidePath: string) => { |
| | const linkData = await getLinkData(guidePath, context, { title: true }) |
| | const baseHref = linkData?.[0]?.href || guidePath |
| | return { |
| | href: baseHref, |
| | title: linkData?.[0]?.title || 'Untitled Guide', |
| | } |
| | }), |
| | ) |
| |
|
| | return { |
| | id: track.id, |
| | title: renderedTitle, |
| | description: renderedDescription, |
| | guides, |
| | } |
| | }), |
| | ) |
| |
|
| | return result |
| | } |
| |
|