用户问题: 有 list_clusters MCP tool 但没简易 admin HTML。 A + B 方案: - A: OpenAPI 文档 + Scalar UI(让人看 + 试 admin API) - B: Cluster CRUD HTML 页面(让人填表创建/改 cluster) 实现: - internal/admin/openapi.yaml: 手写 6 admin 端点 + Cluster/AuditEntry/Error schema。auth_password 不在 spec(因 json:"-" tag) - internal/admin/openapi.go: //go:embed openapi.yaml + Scalar HTML GET /admin/docs 返 Scalar UI (CDN), GET /admin/docs/spec 返 YAML - internal/admin/web/cluster.html: 单文件 401 行暗色 monospace 风格 cluster CRUD 页面, 14 字段表单, vanilla JS + localStorage token + 内嵌 CSS, 无前端框架, 无 bundler - internal/admin/web.go: //go:embed web/cluster.html - internal/admin/router.go: Mount 里追加 4 路由 (GET /admin, /admin/, /admin/docs, /admin/docs/spec), 全部在 AdminAuth 组内 Linus 视角决策: 整个 /admin 子树 (含 HTML) 统一用 AdminAuth — 用户进页面前输 token, JS 存 localStorage, 后续 fetch 自动加 header。 简单且一致, 不搞"白名单 + 不带 token 也能看页"这种特殊 case。 Constraint: - 不引第三方 Go 库 (不用 gofiber/swagger/scalar-go) - 不引前端框架 (no React/Vue) - 不开 JS bundler (no webpack/vite) - HTML/CSS/JS 全内嵌在 cluster.html 一个文件 - Scalar 走 CDN (@scalar/api-reference latest) Co-Authored-By: Claude <noreply@anthropic.com>
53 lines
1.2 KiB
Go
53 lines
1.2 KiB
Go
package admin
|
|
|
|
import (
|
|
"embed"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
//go:embed openapi.yaml
|
|
var openAPIFS embed.FS
|
|
|
|
// OpenAPIYAML returns the embedded OpenAPI spec bytes.
|
|
func OpenAPIYAML() ([]byte, error) {
|
|
return openAPIFS.ReadFile("openapi.yaml")
|
|
}
|
|
|
|
// DocsHandler serves the Scalar API reference HTML.
|
|
func DocsHandler(c *gin.Context) {
|
|
_, err := OpenAPIYAML()
|
|
if err != nil {
|
|
c.String(http.StatusInternalServerError, "openapi.yaml not embedded: %v", err)
|
|
return
|
|
}
|
|
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(scalarHTML))
|
|
}
|
|
|
|
// OpenAPISpecHandler serves the raw OpenAPI YAML spec.
|
|
func OpenAPISpecHandler(c *gin.Context) {
|
|
spec, err := OpenAPIYAML()
|
|
if err != nil {
|
|
c.String(http.StatusInternalServerError, "openapi.yaml: %v", err)
|
|
return
|
|
}
|
|
c.Data(http.StatusOK, "application/yaml", spec)
|
|
}
|
|
|
|
const scalarHTML = `<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>spark-mcp-go Admin API</title>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<style>
|
|
body { margin: 0; padding: 0; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<script id="api-reference" data-url="/admin/docs/spec"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
</body>
|
|
</html>`
|