@@ -29,6 +29,7 @@ import type {
2929 StoredVersion ,
3030} from "@/lib/types" ;
3131import { CodeBlock } from "@/components/ui/code-block" ;
32+ import { MarkdownRenderer } from "@/components/ui/markdown-renderer" ;
3233import { ImageValidationTable } from "@/components/image-validation-table" ;
3334import { ThemeToggle } from "@/components/theme-toggle" ;
3435import ValuesWizardModal from "@/components/modals/values-wizard-modal" ;
@@ -252,14 +253,20 @@ export function VersionExplorer({ data }: VersionExplorerProps) {
252253 versions [ 0 ] ?. version ?? null ,
253254 ) ;
254255 const [ activeArtifact , setActiveArtifact ] = useState <
255- "values" | "images" | "validation"
256+ "values" | "images" | "validation" | "details"
256257 > ( "values" ) ;
257258 const [ valuesContent , setValuesContent ] = useState < string > ( "" ) ;
258259 const [ imagesContent , setImagesContent ] = useState < string > ( "" ) ;
259260 const [ validationData , setValidationData ] =
260261 useState < ImageValidationPayload | null > ( null ) ;
261262 const [ validationError , setValidationError ] = useState < string | null > ( null ) ;
262263 const [ hasValidationAsset , setHasValidationAsset ] = useState ( false ) ;
264+ const [ detailsContent , setDetailsContent ] = useState < string > ( "" ) ;
265+ const [ detailsStatus , setDetailsStatus ] = useState <
266+ "idle" | "loading" | "success" | "error"
267+ > ( "idle" ) ;
268+ const [ detailsError , setDetailsError ] = useState < string | null > ( null ) ;
269+ const [ detailsReloadKey , setDetailsReloadKey ] = useState ( 0 ) ;
263270 const [ loading , setLoading ] = useState ( false ) ;
264271 const [ error , setError ] = useState < string | null > ( null ) ;
265272 const [ reloadFlag , setReloadFlag ] = useState ( 0 ) ;
@@ -281,6 +288,7 @@ export function VersionExplorer({ data }: VersionExplorerProps) {
281288 const [ diffLoading , setDiffLoading ] = useState ( false ) ;
282289 const [ diffError , setDiffError ] = useState < string | null > ( null ) ;
283290 const diffRequestRef = useRef ( 0 ) ;
291+ const detailsRequestRef = useRef ( 0 ) ;
284292
285293 // Wizard state
286294 const [ wizardOpen , setWizardOpen ] = useState ( false ) ;
@@ -335,6 +343,51 @@ export function VersionExplorer({ data }: VersionExplorerProps) {
335343 return ( ) => controller . abort ( ) ;
336344 } , [ ] ) ;
337345
346+ useEffect ( ( ) => {
347+ if ( ! selectedVersion ) {
348+ setDetailsContent ( "" ) ;
349+ setDetailsStatus ( "idle" ) ;
350+ setDetailsError ( null ) ;
351+ return ;
352+ }
353+
354+ const controller = new AbortController ( ) ;
355+ const requestId = detailsRequestRef . current + 1 ;
356+ detailsRequestRef . current = requestId ;
357+
358+ setDetailsStatus ( "loading" ) ;
359+ setDetailsError ( null ) ;
360+ setDetailsContent ( "" ) ;
361+
362+ const docsVersion = selectedVersion . replace ( / \. / g, "_" ) ;
363+
364+ fetch ( `https://langgenius.github.io/dify-helm/pages/${ docsVersion } .md` , {
365+ signal : controller . signal ,
366+ } )
367+ . then ( ( res ) =>
368+ res . ok ? res . text ( ) : Promise . reject ( new Error ( `HTTP ${ res . status } ` ) ) ,
369+ )
370+ . then ( ( text ) => {
371+ if ( detailsRequestRef . current !== requestId ) {
372+ return ;
373+ }
374+ setDetailsContent ( text ) ;
375+ setDetailsStatus ( "success" ) ;
376+ } )
377+ . catch ( ( thrown ) => {
378+ if ( detailsRequestRef . current !== requestId ) {
379+ return ;
380+ }
381+ if ( thrown instanceof Error && thrown . name === "AbortError" ) {
382+ return ;
383+ }
384+ setDetailsStatus ( "error" ) ;
385+ setDetailsError ( `Failed to load details for v${ selectedVersion } .` ) ;
386+ } ) ;
387+
388+ return ( ) => controller . abort ( ) ;
389+ } , [ selectedVersion , detailsReloadKey ] ) ;
390+
338391 // Wizard handlers
339392 const handleOpenWizard = useCallback ( ( ) => {
340393 setWizardOpen ( true ) ;
@@ -526,6 +579,10 @@ export function VersionExplorer({ data }: VersionExplorerProps) {
526579 setReloadFlag ( ( value ) => value + 1 ) ;
527580 } ;
528581
582+ const handleDetailsRetry = useCallback ( ( ) => {
583+ setDetailsReloadKey ( ( value ) => value + 1 ) ;
584+ } , [ ] ) ;
585+
529586 const codeTabs = useMemo (
530587 ( ) => [
531588 {
@@ -556,6 +613,11 @@ export function VersionExplorer({ data }: VersionExplorerProps) {
556613 label : "image availability" ,
557614 type : "validation" as const ,
558615 } ,
616+ {
617+ id : "details" as const ,
618+ label : "Details" ,
619+ type : "markdown" as const ,
620+ } ,
559621 ] ,
560622 [ codeTabs ] ,
561623 ) ;
@@ -1025,7 +1087,7 @@ export function VersionExplorer({ data }: VersionExplorerProps) {
10251087
10261088 < div className = "flex flex-1 flex-col gap-4 overflow-hidden" >
10271089 < div className = "relative z-30 flex items-center justify-center gap-4 py-2" >
1028- < div className = "relative flex w-full justify-center rounded-full bg-black/10 p-1 dark:bg-muted/50" >
1090+ < div className = "relative flex w-full justify-center rounded-full bg-black/10 p-1 shadow-[6px_6px_18px_rgba(0,0,0,0.12)] dark:bg-muted/50" >
10291091 { artifactTabs . map ( ( tab ) => {
10301092 const isActive = tab . id === activeTab . id ;
10311093 return (
@@ -1128,6 +1190,40 @@ export function VersionExplorer({ data }: VersionExplorerProps) {
11281190 version = { selectedVersion ?? undefined }
11291191 className = "h-full w-full"
11301192 />
1193+ ) : activeTab . type === "markdown" ? (
1194+ detailsStatus === "success" ? (
1195+ < MarkdownRenderer
1196+ content = { detailsContent }
1197+ className = "h-full w-full"
1198+ />
1199+ ) : detailsStatus === "loading" || detailsStatus === "idle" ? (
1200+ < div className = "flex h-full items-center justify-center rounded-2xl border border-border bg-card/30" >
1201+ < div className = "flex items-center gap-2 text-sm text-muted-foreground" >
1202+ < Loader2 className = "h-4 w-4 animate-spin text-primary" />
1203+ < span > Loading details...</ span >
1204+ </ div >
1205+ </ div >
1206+ ) : (
1207+ < div className = "flex h-full items-center justify-center rounded-2xl border border-border bg-card/30 p-6" >
1208+ < div className = "flex flex-col items-center gap-3 text-center text-sm text-muted-foreground" >
1209+ < div className = "flex items-center gap-2 text-foreground/90" >
1210+ < AlertTriangle className = "h-4 w-4 text-destructive" />
1211+ < span >
1212+ { detailsError ??
1213+ `Failed to load details for v${ selectedVersion ?? "" } .` }
1214+ </ span >
1215+ </ div >
1216+ < button
1217+ type = "button"
1218+ onClick = { handleDetailsRetry }
1219+ className = "inline-flex items-center gap-2 rounded-full border border-primary/40 bg-transparent px-4 py-1 text-xs uppercase tracking-[0.3em] text-foreground transition hover:border-primary/70 hover:bg-primary/10"
1220+ >
1221+ < RefreshCw className = "h-3 w-3" />
1222+ Refresh
1223+ </ button >
1224+ </ div >
1225+ </ div >
1226+ )
11311227 ) : (
11321228 < ImageValidationTable
11331229 version = { selectedVersion ?? undefined }
0 commit comments