mirror of
https://github.com/MeshEnvy/mesh-forge.git
synced 2026-03-28 17:42:55 +01:00
feat: integrate Giscus comments into build pages for enhanced discussion and support
This commit is contained in:
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Minor
|
||||
|
||||
- Integrated Giscus comments into build pages for discussion threads per build configuration
|
||||
|
||||
### Patch
|
||||
|
||||
- Made build hash label clickable in BuildProgress component to navigate to build detail page
|
||||
|
||||
@@ -7,7 +7,7 @@ import { getArtifactFilenameBase } from "@/convex/lib/filename"
|
||||
import modulesData from "@/convex/modules.json"
|
||||
import { getImplicitDependencies, humanizeStatus } from "@/lib/utils"
|
||||
import registryData from "@/public/registry.json"
|
||||
import { AlertCircle, CheckCircle, Copy, Loader2, Share2, X, XCircle } from "lucide-react"
|
||||
import { CheckCircle, Copy, Loader2, Share2, X, XCircle } from "lucide-react"
|
||||
import { useState } from "react"
|
||||
import { toast } from "sonner"
|
||||
import { navigate } from "vike/client/router"
|
||||
@@ -139,60 +139,6 @@ export function BuildProgress({ build, isAdmin = false, onRetry, showActions = t
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
// Generate GitHub discussion URL with prefilled body
|
||||
const generateDiscussionUrl = (): string => {
|
||||
const flags = computeFlagsFromConfig(build.config)
|
||||
const plugins = build.config.pluginsEnabled?.join(", ") || "(none)"
|
||||
const timestamp = new Date(build.startedAt).toISOString()
|
||||
const githubRunLink = githubActionUrl ? `[View run](${githubActionUrl})` : "(not available)"
|
||||
const buildPageUrl = `${window.location.origin}/builds/${build.buildHash}`
|
||||
|
||||
// Format plugins as +plugin@version
|
||||
const formattedPlugins =
|
||||
build.config.pluginsEnabled
|
||||
?.map(plugin => {
|
||||
// Plugin might be "slug@version" or just "slug"
|
||||
return plugin.includes("@") ? `+${plugin}` : `+${plugin}`
|
||||
})
|
||||
.join(" ") || ""
|
||||
|
||||
const bracketContent = [
|
||||
build.config.target,
|
||||
`v${build.config.version}`,
|
||||
...(formattedPlugins ? [formattedPlugins] : []),
|
||||
].join(" ")
|
||||
|
||||
const discussionTitle = `Build ${build.status === "failure" ? "Failed" : "Issue"}: ${targetLabel} [${bracketContent}]`
|
||||
|
||||
const discussionBody = `## Build ${build.status === "failure" ? "Failed" : "Information"}
|
||||
|
||||
**Build Hash**: \`${build.buildHash}\`
|
||||
**Target Board**: ${build.config.target}
|
||||
**Firmware Version**: ${build.config.version}
|
||||
**Build Flags**: ${flags || "(none)"}
|
||||
**Plugins**: ${plugins}
|
||||
**Build Timestamp**: ${timestamp}
|
||||
|
||||
**Build Page**: [View build page](${buildPageUrl})
|
||||
**GitHub Run**: ${githubRunLink}
|
||||
|
||||
## Additional Information
|
||||
(Please add any additional details about the issue here)`
|
||||
|
||||
const baseUrl = "https://github.com/MeshEnvy/mesh-forge/discussions/new"
|
||||
const params = new URLSearchParams({
|
||||
category: "q-a",
|
||||
title: discussionTitle,
|
||||
body: discussionBody,
|
||||
})
|
||||
|
||||
return `${baseUrl}?${params.toString()}`
|
||||
}
|
||||
|
||||
const handleReportIssue = () => {
|
||||
window.open(generateDiscussionUrl(), "_blank", "noopener,noreferrer")
|
||||
}
|
||||
|
||||
const handleRetry = async () => {
|
||||
if (!build?._id || !onRetry) return
|
||||
try {
|
||||
@@ -311,10 +257,6 @@ export function BuildProgress({ build, isAdmin = false, onRetry, showActions = t
|
||||
</div>
|
||||
{showActions && (
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={handleReportIssue} variant="outline" className="border-slate-600 hover:bg-slate-800">
|
||||
<AlertCircle className="w-4 h-4 mr-2" />
|
||||
Support
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => navigate(`/builds/new/${build.buildHash}`)}
|
||||
variant="outline"
|
||||
|
||||
55
components/GiscusComments.tsx
Normal file
55
components/GiscusComments.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import type { Doc } from "@/convex/_generated/dataModel"
|
||||
import { getBuildIdentifier } from "@/convex/lib/filename"
|
||||
import { useEffect, useRef } from "react"
|
||||
|
||||
interface GiscusCommentsProps {
|
||||
build: Doc<"builds">
|
||||
}
|
||||
|
||||
export function GiscusComments({ build }: GiscusCommentsProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return
|
||||
|
||||
// Compute the data-term using build identifier
|
||||
const term = getBuildIdentifier(
|
||||
build.config.version,
|
||||
build.config.target,
|
||||
build.buildHash,
|
||||
build.config.pluginsEnabled
|
||||
)
|
||||
|
||||
// Clear any existing script
|
||||
containerRef.current.innerHTML = ""
|
||||
|
||||
// Create script element
|
||||
const script = document.createElement("script")
|
||||
script.src = "https://giscus.app/client.js"
|
||||
script.setAttribute("data-repo", "MeshEnvy/mesh-forge")
|
||||
script.setAttribute("data-repo-id", "R_kgDOQa32VQ")
|
||||
script.setAttribute("data-category", "Builds")
|
||||
script.setAttribute("data-category-id", "DIC_kwDOQa32Vc4CznuV")
|
||||
script.setAttribute("data-mapping", "specific")
|
||||
script.setAttribute("data-term", term)
|
||||
script.setAttribute("data-strict", "1")
|
||||
script.setAttribute("data-reactions-enabled", "1")
|
||||
script.setAttribute("data-emit-metadata", "0")
|
||||
script.setAttribute("data-input-position", "bottom")
|
||||
script.setAttribute("data-theme", "dark_tritanopia")
|
||||
script.setAttribute("data-lang", "en")
|
||||
script.crossOrigin = "anonymous"
|
||||
script.async = true
|
||||
|
||||
containerRef.current.appendChild(script)
|
||||
|
||||
// Cleanup function
|
||||
return () => {
|
||||
if (containerRef.current && containerRef.current.contains(script)) {
|
||||
containerRef.current.removeChild(script)
|
||||
}
|
||||
}
|
||||
}, [build])
|
||||
|
||||
return <div ref={containerRef} className="mt-6" />
|
||||
}
|
||||
@@ -27,3 +27,32 @@ export function getArtifactFilenameBase(
|
||||
|
||||
return `${os}-${version}-${target}-${last4Hash}-${githubRunId}-${artifactType}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a build identifier for use in external systems (e.g., Giscus discussions).
|
||||
* Format: {target}-{version}-{last4hash} or {target}-{version}-{last4hash}-{plugins}
|
||||
* This is a simpler identifier without OS prefix, job ID, or artifact type.
|
||||
*
|
||||
* @param version - The firmware version
|
||||
* @param target - The target board name
|
||||
* @param buildHash - The build hash (used to get last 4 characters)
|
||||
* @param pluginsEnabled - Optional array of enabled plugin slugs
|
||||
* @returns The build identifier (e.g., "tbeam-v2.7.16-a1b2" or "tbeam-v2.7.16-a1b2-plugin1+plugin2")
|
||||
*/
|
||||
export function getBuildIdentifier(
|
||||
version: string,
|
||||
target: string,
|
||||
buildHash: string,
|
||||
pluginsEnabled?: string[]
|
||||
): string {
|
||||
const last4Hash = buildHash.slice(-4)
|
||||
let identifier = `${target}-${version}-${last4Hash}`
|
||||
|
||||
if (pluginsEnabled && pluginsEnabled.length > 0) {
|
||||
const sortedPlugins = [...pluginsEnabled].sort()
|
||||
const pluginsStr = sortedPlugins.join("+")
|
||||
identifier = `${identifier}-${pluginsStr}`
|
||||
}
|
||||
|
||||
return identifier
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BuildProgress } from "@/components/BuildProgress"
|
||||
import { GiscusComments } from "@/components/GiscusComments"
|
||||
import { api } from "@/convex/_generated/api"
|
||||
import { useMutation, useQuery } from "convex/react"
|
||||
import { Loader2 } from "lucide-react"
|
||||
@@ -68,6 +69,7 @@ export default function BuildProgressPage() {
|
||||
<div className="min-h-screen bg-slate-950 text-white p-8">
|
||||
<div className="max-w-4xl mx-auto space-y-6">
|
||||
<BuildProgress build={build} isAdmin={isAdmin === true} onRetry={handleRetry} />
|
||||
<GiscusComments build={build} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user