mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Keep file tree view icons consistent with icon theme (#33921)
Fix #33914 before:  after:  --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -6,12 +6,14 @@ package files
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/url"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/fileicon"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@@ -140,8 +142,13 @@ func entryModeString(entryMode git.EntryMode) string {
|
||||
}
|
||||
|
||||
type TreeViewNode struct {
|
||||
EntryName string `json:"entryName"`
|
||||
EntryMode string `json:"entryMode"`
|
||||
EntryName string `json:"entryName"`
|
||||
EntryMode string `json:"entryMode"`
|
||||
EntryIcon template.HTML `json:"entryIcon"`
|
||||
EntryIconOpen template.HTML `json:"entryIconOpen,omitempty"`
|
||||
|
||||
SymLinkedToMode string `json:"symLinkedToMode,omitempty"` // TODO: for the EntryMode="symlink"
|
||||
|
||||
FullPath string `json:"fullPath"`
|
||||
SubmoduleURL string `json:"submoduleUrl,omitempty"`
|
||||
Children []*TreeViewNode `json:"children,omitempty"`
|
||||
@@ -151,13 +158,28 @@ func (node *TreeViewNode) sortLevel() int {
|
||||
return util.Iif(node.EntryMode == "tree" || node.EntryMode == "commit", 0, 1)
|
||||
}
|
||||
|
||||
func newTreeViewNodeFromEntry(ctx context.Context, commit *git.Commit, parentDir string, entry *git.TreeEntry) *TreeViewNode {
|
||||
func newTreeViewNodeFromEntry(ctx context.Context, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, parentDir string, entry *git.TreeEntry) *TreeViewNode {
|
||||
node := &TreeViewNode{
|
||||
EntryName: entry.Name(),
|
||||
EntryMode: entryModeString(entry.Mode()),
|
||||
FullPath: path.Join(parentDir, entry.Name()),
|
||||
}
|
||||
|
||||
if entry.IsLink() {
|
||||
// TODO: symlink to a folder or a file, the icon differs
|
||||
target, err := entry.FollowLink()
|
||||
if err == nil {
|
||||
_ = target.IsDir()
|
||||
// if target.IsDir() { } else { }
|
||||
}
|
||||
}
|
||||
|
||||
if node.EntryIcon == "" {
|
||||
node.EntryIcon = fileicon.RenderEntryIcon(renderedIconPool, entry)
|
||||
// TODO: no open icon support yet
|
||||
// node.EntryIconOpen = fileicon.RenderEntryIconOpen(renderedIconPool, entry)
|
||||
}
|
||||
|
||||
if node.EntryMode == "commit" {
|
||||
if subModule, err := commit.GetSubModule(node.FullPath); err != nil {
|
||||
log.Error("GetSubModule: %v", err)
|
||||
@@ -182,7 +204,7 @@ func sortTreeViewNodes(nodes []*TreeViewNode) {
|
||||
})
|
||||
}
|
||||
|
||||
func listTreeNodes(ctx context.Context, commit *git.Commit, tree *git.Tree, treePath, subPath string) ([]*TreeViewNode, error) {
|
||||
func listTreeNodes(ctx context.Context, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, tree *git.Tree, treePath, subPath string) ([]*TreeViewNode, error) {
|
||||
entries, err := tree.ListEntries()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -191,14 +213,14 @@ func listTreeNodes(ctx context.Context, commit *git.Commit, tree *git.Tree, tree
|
||||
subPathDirName, subPathRemaining, _ := strings.Cut(subPath, "/")
|
||||
nodes := make([]*TreeViewNode, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
node := newTreeViewNodeFromEntry(ctx, commit, treePath, entry)
|
||||
node := newTreeViewNodeFromEntry(ctx, renderedIconPool, commit, treePath, entry)
|
||||
nodes = append(nodes, node)
|
||||
if entry.IsDir() && subPathDirName == entry.Name() {
|
||||
subTreePath := treePath + "/" + node.EntryName
|
||||
if subTreePath[0] == '/' {
|
||||
subTreePath = subTreePath[1:]
|
||||
}
|
||||
subNodes, err := listTreeNodes(ctx, commit, entry.Tree(), subTreePath, subPathRemaining)
|
||||
subNodes, err := listTreeNodes(ctx, renderedIconPool, commit, entry.Tree(), subTreePath, subPathRemaining)
|
||||
if err != nil {
|
||||
log.Error("listTreeNodes: %v", err)
|
||||
} else {
|
||||
@@ -210,10 +232,10 @@ func listTreeNodes(ctx context.Context, commit *git.Commit, tree *git.Tree, tree
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func GetTreeViewNodes(ctx context.Context, commit *git.Commit, treePath, subPath string) ([]*TreeViewNode, error) {
|
||||
func GetTreeViewNodes(ctx context.Context, renderedIconPool *fileicon.RenderedIconPool, commit *git.Commit, treePath, subPath string) ([]*TreeViewNode, error) {
|
||||
entry, err := commit.GetTreeEntryByPath(treePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listTreeNodes(ctx, commit, entry.Tree(), treePath, subPath)
|
||||
return listTreeNodes(ctx, renderedIconPool, commit, entry.Tree(), treePath, subPath)
|
||||
}
|
||||
|
@@ -4,9 +4,11 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/fileicon"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/services/contexttest"
|
||||
@@ -62,40 +64,51 @@ func TestGetTreeViewNodes(t *testing.T) {
|
||||
contexttest.LoadGitRepo(t, ctx)
|
||||
defer ctx.Repo.GitRepo.Close()
|
||||
|
||||
treeNodes, err := GetTreeViewNodes(ctx, ctx.Repo.Commit, "", "")
|
||||
renderedIconPool := fileicon.NewRenderedIconPool()
|
||||
mockIconForFile := func(id string) template.HTML {
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file" width="16" height="16" aria-hidden="true"><use xlink:href="#` + id + `"></use></svg>`)
|
||||
}
|
||||
mockIconForFolder := func(id string) template.HTML {
|
||||
return template.HTML(`<svg class="svg git-entry-icon octicon-file-directory-fill" width="16" height="16" aria-hidden="true"><use xlink:href="#` + id + `"></use></svg>`)
|
||||
}
|
||||
treeNodes, err := GetTreeViewNodes(ctx, renderedIconPool, ctx.Repo.Commit, "", "")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []*TreeViewNode{
|
||||
{
|
||||
EntryName: "docs",
|
||||
EntryMode: "tree",
|
||||
FullPath: "docs",
|
||||
EntryIcon: mockIconForFolder(`svg-mfi-folder-docs`),
|
||||
},
|
||||
}, treeNodes)
|
||||
|
||||
treeNodes, err = GetTreeViewNodes(ctx, ctx.Repo.Commit, "", "docs/README.md")
|
||||
treeNodes, err = GetTreeViewNodes(ctx, renderedIconPool, ctx.Repo.Commit, "", "docs/README.md")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []*TreeViewNode{
|
||||
{
|
||||
EntryName: "docs",
|
||||
EntryMode: "tree",
|
||||
FullPath: "docs",
|
||||
EntryIcon: mockIconForFolder(`svg-mfi-folder-docs`),
|
||||
Children: []*TreeViewNode{
|
||||
{
|
||||
EntryName: "README.md",
|
||||
EntryMode: "blob",
|
||||
FullPath: "docs/README.md",
|
||||
EntryIcon: mockIconForFile(`svg-mfi-readme`),
|
||||
},
|
||||
},
|
||||
},
|
||||
}, treeNodes)
|
||||
|
||||
treeNodes, err = GetTreeViewNodes(ctx, ctx.Repo.Commit, "docs", "README.md")
|
||||
treeNodes, err = GetTreeViewNodes(ctx, renderedIconPool, ctx.Repo.Commit, "docs", "README.md")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []*TreeViewNode{
|
||||
{
|
||||
EntryName: "README.md",
|
||||
EntryMode: "blob",
|
||||
FullPath: "docs/README.md",
|
||||
EntryIcon: mockIconForFile(`svg-mfi-readme`),
|
||||
},
|
||||
}, treeNodes)
|
||||
}
|
||||
|
Reference in New Issue
Block a user