Skip to content

Commit b97839b

Browse files
committed
add md details
1 parent 62b4611 commit b97839b

File tree

5 files changed

+1031
-13
lines changed

5 files changed

+1031
-13
lines changed

dify-helm-watchdog/next.config.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
// next.config.js
2-
import type { NextConfig } from 'next';
3-
import { codeInspectorPlugin } from 'code-inspector-plugin';
2+
import type { NextConfig } from "next";
3+
import { codeInspectorPlugin } from "code-inspector-plugin";
4+
5+
const isDev = process.env.NODE_ENV === "development";
46

57
const nextConfig: NextConfig = {
6-
turbopack: {
7-
rules: codeInspectorPlugin({
8-
bundler: 'turbopack',
9-
}),
10-
},
8+
...(isDev
9+
? {
10+
turbopack: {
11+
rules: codeInspectorPlugin({
12+
bundler: "turbopack",
13+
}),
14+
},
15+
}
16+
: {}),
1117
};
1218

1319
export default nextConfig;

dify-helm-watchdog/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"react": "19.1.0",
2727
"react-diff-viewer": "^3.1.1",
2828
"react-dom": "19.1.0",
29+
"react-markdown": "^10.1.0",
30+
"remark-gfm": "^4.0.1",
2931
"semver": "7.7.3",
3032
"shadcn": "^3.5.0",
3133
"swagger-ui-react": "^5.30.2",
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
"use client";
2+
3+
import ReactMarkdown from "react-markdown";
4+
import remarkGfm from "remark-gfm";
5+
6+
interface MarkdownRendererProps {
7+
content: string;
8+
className?: string;
9+
}
10+
11+
const withClassName = (base: string, extra?: string) =>
12+
extra ? `${base} ${extra}` : base;
13+
14+
export function MarkdownRenderer({ content, className }: MarkdownRendererProps) {
15+
return (
16+
<div
17+
className={withClassName(
18+
"h-full overflow-auto custom-scrollbar",
19+
className,
20+
)}
21+
>
22+
<article className="flex w-full flex-col gap-4 px-[15px] py-6 text-sm leading-6 text-foreground">
23+
<ReactMarkdown
24+
remarkPlugins={[remarkGfm]}
25+
components={{
26+
h1: ({ className: headingClass, ...props }) => (
27+
<h1
28+
{...props}
29+
className={withClassName(
30+
"mt-2 text-2xl font-semibold tracking-tight text-foreground",
31+
headingClass,
32+
)}
33+
/>
34+
),
35+
h2: ({ className: headingClass, ...props }) => (
36+
<h2
37+
{...props}
38+
className={withClassName(
39+
"mt-6 text-xl font-semibold tracking-tight text-foreground",
40+
headingClass,
41+
)}
42+
/>
43+
),
44+
h3: ({ className: headingClass, ...props }) => (
45+
<h3
46+
{...props}
47+
className={withClassName(
48+
"mt-6 text-lg font-semibold tracking-tight text-foreground",
49+
headingClass,
50+
)}
51+
/>
52+
),
53+
p: ({ className: paragraphClass, ...props }) => (
54+
<p
55+
{...props}
56+
className={withClassName(
57+
"text-sm leading-6 text-foreground/90",
58+
paragraphClass,
59+
)}
60+
/>
61+
),
62+
a: ({ className: linkClass, ...props }) => (
63+
<a
64+
{...props}
65+
target="_blank"
66+
rel="noopener noreferrer"
67+
className={withClassName(
68+
"text-primary underline underline-offset-4 transition hover:text-primary/80",
69+
linkClass,
70+
)}
71+
/>
72+
),
73+
ul: ({ className: listClass, ...props }) => (
74+
<ul
75+
{...props}
76+
className={withClassName("ml-5 list-disc space-y-1", listClass)}
77+
/>
78+
),
79+
ol: ({ className: listClass, ...props }) => (
80+
<ol
81+
{...props}
82+
className={withClassName(
83+
"ml-5 list-decimal space-y-1",
84+
listClass,
85+
)}
86+
/>
87+
),
88+
li: ({ className: listItemClass, ...props }) => (
89+
<li
90+
{...props}
91+
className={withClassName(
92+
"text-sm leading-6 text-foreground/90",
93+
listItemClass,
94+
)}
95+
/>
96+
),
97+
blockquote: ({ className: quoteClass, ...props }) => (
98+
<blockquote
99+
{...props}
100+
className={withClassName(
101+
"border-l-2 border-border pl-4 text-sm italic text-muted-foreground",
102+
quoteClass,
103+
)}
104+
/>
105+
),
106+
hr: ({ className: hrClass, ...props }) => (
107+
<hr {...props} className={withClassName("my-6 border-border", hrClass)} />
108+
),
109+
table: ({ className: tableClass, ...props }) => (
110+
<div className="overflow-auto">
111+
<table
112+
{...props}
113+
className={withClassName(
114+
"w-full border-separate border-spacing-0 text-sm",
115+
tableClass,
116+
)}
117+
/>
118+
</div>
119+
),
120+
thead: ({ className: headClass, ...props }) => (
121+
<thead {...props} className={withClassName("bg-muted/40", headClass)} />
122+
),
123+
th: ({ className: thClass, ...props }) => (
124+
<th
125+
{...props}
126+
className={withClassName(
127+
"border border-border px-3 py-2 text-left text-xs font-semibold uppercase tracking-wide text-muted-foreground",
128+
thClass,
129+
)}
130+
/>
131+
),
132+
td: ({ className: tdClass, ...props }) => (
133+
<td
134+
{...props}
135+
className={withClassName(
136+
"border border-border px-3 py-2 align-top text-sm text-foreground/90",
137+
tdClass,
138+
)}
139+
/>
140+
),
141+
pre: ({ className: preClass, ...props }) => (
142+
<pre
143+
{...props}
144+
className={withClassName(
145+
"my-4 overflow-auto rounded-lg border border-border bg-card p-4 text-xs leading-5 text-foreground",
146+
preClass,
147+
)}
148+
/>
149+
),
150+
code: ({ inline, className: codeClass, ...props }) => (
151+
<code
152+
{...props}
153+
className={withClassName(
154+
inline
155+
? "rounded bg-muted px-1 py-0.5 font-mono text-xs text-foreground"
156+
: "font-mono text-xs text-foreground",
157+
codeClass,
158+
)}
159+
/>
160+
),
161+
img: ({ className: imgClass, ...props }) => (
162+
<img
163+
{...props}
164+
className={withClassName(
165+
"max-w-full rounded-lg border border-border",
166+
imgClass,
167+
)}
168+
/>
169+
),
170+
}}
171+
>
172+
{content}
173+
</ReactMarkdown>
174+
</article>
175+
</div>
176+
);
177+
}

dify-helm-watchdog/src/components/version-explorer.tsx

Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import type {
2929
StoredVersion,
3030
} from "@/lib/types";
3131
import { CodeBlock } from "@/components/ui/code-block";
32+
import { MarkdownRenderer } from "@/components/ui/markdown-renderer";
3233
import { ImageValidationTable } from "@/components/image-validation-table";
3334
import { ThemeToggle } from "@/components/theme-toggle";
3435
import 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

Comments
 (0)