mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
console: display missing images in documentation
And don't embed SVG. This is wasteful.
This commit is contained in:
@@ -14,13 +14,21 @@ import (
|
|||||||
var embeddedAssets embed.FS
|
var embeddedAssets embed.FS
|
||||||
|
|
||||||
func (c *Component) assetsHandlerFunc(w http.ResponseWriter, req *http.Request) {
|
func (c *Component) assetsHandlerFunc(w http.ResponseWriter, req *http.Request) {
|
||||||
assets := c.embedOrLiveFS(embeddedAssets, "data/frontend")
|
|
||||||
upath := req.URL.Path
|
upath := req.URL.Path
|
||||||
if !strings.HasPrefix(upath, "/") {
|
if !strings.HasPrefix(upath, "/") {
|
||||||
upath = "/" + upath
|
upath = "/" + upath
|
||||||
req.URL.Path = upath
|
req.URL.Path = upath
|
||||||
}
|
}
|
||||||
// Serve assets using a file server
|
|
||||||
|
// Serve /doc/images
|
||||||
|
if strings.HasPrefix(upath, "/docs/images/") {
|
||||||
|
docs := c.embedOrLiveFS(embeddedDocs, "data/docs")
|
||||||
|
http.ServeFileFS(w, req, docs, req.URL.Path[len("/docs/images/"):])
|
||||||
|
http.FileServer(http.FS(docs)).ServeHTTP(w, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve /assets
|
||||||
|
assets := c.embedOrLiveFS(embeddedAssets, "data/frontend")
|
||||||
if strings.HasPrefix(upath, "/assets/") {
|
if strings.HasPrefix(upath, "/assets/") {
|
||||||
http.FileServer(http.FS(assets)).ServeHTTP(w, req)
|
http.FileServer(http.FS(assets)).ServeHTTP(w, req)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ identified with a specific icon:
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- 🩹 *console*: display missing images in documentation
|
||||||
- 🌱 *build*: accept building with a not up-to-date toolchain
|
- 🌱 *build*: accept building with a not up-to-date toolchain
|
||||||
- 🌱 *docker*: update ClickHouse to 25.8 (not mandatory)
|
- 🌱 *docker*: update ClickHouse to 25.8 (not mandatory)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package console
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"embed"
|
"embed"
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
@@ -116,7 +115,7 @@ func (c *Component) docsHandlerFunc(gc *gin.Context) {
|
|||||||
parser.WithAutoHeadingID(),
|
parser.WithAutoHeadingID(),
|
||||||
parser.WithASTTransformers(
|
parser.WithASTTransformers(
|
||||||
util.Prioritized(&internalLinkTransformer{}, 500),
|
util.Prioritized(&internalLinkTransformer{}, 500),
|
||||||
util.Prioritized(&imageEmbedder{docs}, 500),
|
util.Prioritized(&imageLinkTransformer{docs}, 500),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -152,11 +151,11 @@ func (r *internalLinkTransformer) Transform(node *ast.Document, _ text.Reader, _
|
|||||||
ast.Walk(node, replaceLinks)
|
ast.Walk(node, replaceLinks)
|
||||||
}
|
}
|
||||||
|
|
||||||
type imageEmbedder struct {
|
type imageLinkTransformer struct {
|
||||||
root fs.FS
|
root fs.FS
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *imageEmbedder) Transform(node *ast.Document, _ text.Reader, _ parser.Context) {
|
func (r *imageLinkTransformer) Transform(node *ast.Document, _ text.Reader, _ parser.Context) {
|
||||||
replaceLinks := func(n ast.Node, entering bool) (ast.WalkStatus, error) {
|
replaceLinks := func(n ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
if !entering {
|
if !entering {
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
@@ -164,19 +163,9 @@ func (r *imageEmbedder) Transform(node *ast.Document, _ text.Reader, _ parser.Co
|
|||||||
switch node := n.(type) {
|
switch node := n.(type) {
|
||||||
case *ast.Image:
|
case *ast.Image:
|
||||||
path := string(node.Destination)
|
path := string(node.Destination)
|
||||||
if strings.Contains(path, "/") || !strings.HasSuffix(path, ".svg") {
|
if !strings.Contains(path, "/") {
|
||||||
break
|
node.Destination = []byte(fmt.Sprintf("images/%s", path))
|
||||||
}
|
}
|
||||||
f, err := r.root.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
content, err := io.ReadAll(f)
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
encoded := fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(content))
|
|
||||||
node.Destination = []byte(encoded)
|
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"akvorado/common/helpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServeDocs(t *testing.T) {
|
func TestServeDocs(t *testing.T) {
|
||||||
@@ -22,7 +24,7 @@ func TestServeDocs(t *testing.T) {
|
|||||||
Expect string
|
Expect string
|
||||||
}{
|
}{
|
||||||
{"usage", `<a href=\"configuration\">configuration section</a>`},
|
{"usage", `<a href=\"configuration\">configuration section</a>`},
|
||||||
{"intro", `data:image/svg`},
|
{"intro", `images/design.svg`},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(fmt.Sprintf("%s-%s", name, tc.Path), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%s-%s", name, tc.Path), func(t *testing.T) {
|
||||||
@@ -50,3 +52,38 @@ func TestServeDocs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServeImages(t *testing.T) {
|
||||||
|
for _, live := range []bool{false, true} {
|
||||||
|
name := "livefs"
|
||||||
|
if !live {
|
||||||
|
name = "embeddedfs"
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
conf := DefaultConfiguration()
|
||||||
|
conf.ServeLiveFS = live
|
||||||
|
_, h, _, _ := NewMock(t, conf)
|
||||||
|
|
||||||
|
resp, err := http.Get(fmt.Sprintf("http://%s/docs/images/design.svg",
|
||||||
|
h.LocalAddr()))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GET /docs/images/design.svg:\n%+v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
t.Errorf("GET /docs/images/design.svg: got status code %d, not 200",
|
||||||
|
resp.StatusCode)
|
||||||
|
}
|
||||||
|
expected := `<?xml version="1.0" encoding="UTF-8"?>`
|
||||||
|
got := make([]byte, len(expected))
|
||||||
|
if _, err := io.ReadFull(resp.Body, got); err != nil {
|
||||||
|
t.Fatalf("GET /docs/images/design.svg ReadFull() error:\n%+v", err)
|
||||||
|
}
|
||||||
|
if diff := helpers.Diff(string(got), expected); diff != "" {
|
||||||
|
t.Errorf("GET /docs/images/design.svg:\n%s",
|
||||||
|
diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user