Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add file tree to file view page #32721

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions routers/web/repo/blame.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ func RefBlame(ctx *context.Context) {
return
}

// ctx.Data["RepoPreferences"] = ctx.Session.Get("repoPreferences")
ctx.Data["RepoPreferences"] = &preferencesForm{
ShowFileViewTreeSidebar: true,
}

branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
treeLink := branchLink
rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL()
Expand Down
45 changes: 45 additions & 0 deletions routers/web/repo/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2018 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package repo

import (
"net/http"

"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/services/context"
files_service "code.gitea.io/gitea/services/repository/files"
)

// canReadFiles returns true if repository is readable and user has proper access level.
func canReadFiles(r *context.Repository) bool {
return r.Permission.CanRead(unit.TypeCode)
}

// GetContents Get the metadata and contents (if a file) of an entry in a repository, or a list of entries if a dir
func GetContents(ctx *context.Context) {
if !canReadFiles(ctx.Repo) {
ctx.NotFound("Invalid FilePath", nil)
return
}

treePath := ctx.PathParam("*")
ref := ctx.FormTrim("ref")

if fileList, err := files_service.GetContentsOrList(ctx, ctx.Repo.Repository, treePath, ref); err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound("GetContentsOrList", err)
return
}
ctx.ServerError("Repo.GitRepo.GetCommit", err)
} else {
ctx.JSON(http.StatusOK, fileList)
}
}

// GetContentsList Get the metadata of all the entries of the root dir
func GetContentsList(ctx *context.Context) {
GetContents(ctx)
}
18 changes: 18 additions & 0 deletions routers/web/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
repo_module "code.gitea.io/gitea/modules/repository"
Expand Down Expand Up @@ -758,3 +759,20 @@ func PrepareBranchList(ctx *context.Context) {
}
ctx.Data["Branches"] = brs
}

type preferencesForm struct {
ShowFileViewTreeSidebar bool `json:"show_file_view_tree_sidebar"`
}

func UpdatePreferences(ctx *context.Context) {
form := &preferencesForm{}
if err := json.NewDecoder(ctx.Req.Body).Decode(&form); err != nil {
ctx.ServerError("DecodePreferencesForm", err)
return
}
// if err := ctx.Session.Set("repoPreferences", form); err != nil {
// ctx.ServerError("Session.Set", err)
// return
// }
ctx.JSONOK()
}
5 changes: 5 additions & 0 deletions routers/web/repo/view_home.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,11 @@ func Home(ctx *context.Context) {
return
}

// ctx.Data["RepoPreferences"] = ctx.Session.Get("repoPreferences")
ctx.Data["RepoPreferences"] = &preferencesForm{
ShowFileViewTreeSidebar: true,
}

title := ctx.Repo.Repository.Owner.Name + "/" + ctx.Repo.Repository.Name
if len(ctx.Repo.Repository.Description) > 0 {
title += ": " + ctx.Repo.Repository.Description
Expand Down
5 changes: 5 additions & 0 deletions routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,7 @@ func registerRoutes(m *web.Router) {
m.Get("/migrate", repo.Migrate)
m.Post("/migrate", web.Bind(forms.MigrateRepoForm{}), repo.MigratePost)
m.Get("/search", repo.SearchRepo)
m.Put("/preferences", repo.UpdatePreferences)
}, reqSignIn)
// end "/repo": create, migrate, search

Expand Down Expand Up @@ -1161,6 +1162,10 @@ func registerRoutes(m *web.Router) {
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.TreeList)
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.TreeList)
})
m.Group("/contents", func() {
m.Get("", repo.GetContentsList)
m.Get("/*", repo.GetContents)
})
m.Get("/compare", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff)
m.Combo("/compare/*", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists).
Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
Expand Down
26 changes: 20 additions & 6 deletions templates/repo/home.tmpl
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
{{template "base/head" .}}
{{$treeNamesLen := len .TreeNames}}
{{$isTreePathRoot := eq $treeNamesLen 0}}
{{$showSidebar := $isTreePathRoot}}
{{$hasTreeSidebar := not $isTreePathRoot}}
{{$showTreeSidebar := .RepoPreferences.ShowFileViewTreeSidebar}}
{{$hideTreeSidebar := not $showTreeSidebar}}
{{$hasAndShowTreeSidebar := and $hasTreeSidebar $showTreeSidebar}}
<div role="main" aria-label="{{.Title}}" class="page-content repository file list {{if .IsBlame}}blame{{end}}">
{{template "repo/header" .}}
<div class="ui container {{if .IsBlame}}fluid padded{{end}}">
Expand All @@ -16,14 +23,20 @@

{{template "repo/code/recently_pushed_new_branches" .}}

{{$treeNamesLen := len .TreeNames}}
{{$isTreePathRoot := eq $treeNamesLen 0}}
{{$showSidebar := $isTreePathRoot}}
<div class="{{Iif $showSidebar "repo-grid-filelist-sidebar" "repo-grid-filelist-only"}}">
<div class="{{Iif $showSidebar "repo-grid-filelist-sidebar" (Iif $showTreeSidebar "repo-grid-tree-sidebar" "repo-grid-filelist-only")}}">
{{if $hasTreeSidebar}}
<div class="repo-view-file-tree-sidebar not-mobile {{if $hideTreeSidebar}}tw-hidden{{end}}">{{template "repo/view_file_tree_sidebar" .}}</div>
{{end}}

<div class="repo-home-filelist">
{{template "repo/sub_menu" .}}
<div class="repo-button-row">
<div class="repo-button-row-left">
{{if $hasTreeSidebar}}
<button class="show-tree-sidebar-button ui compact basic button icon not-mobile {{if $showTreeSidebar}}tw-hidden{{end}}" title="{{ctx.Locale.Tr "repo.diff.show_file_tree"}}">
{{svg "octicon-sidebar-collapse" 20 "icon"}}
</button>
{{end}}
{{$branchDropdownCurrentRefType := "branch"}}
{{$branchDropdownCurrentRefShortName := .BranchName}}
{{if .IsViewTag}}
Expand All @@ -40,6 +53,7 @@
"RefLinkTemplate" "{RepoLink}/src/{RefType}/{RefShortName}/{TreePath}"
"AllowCreateNewRef" .CanCreateBranch
"ShowViewAllRefsEntry" true
"ContainerClasses" (Iif $hasAndShowTreeSidebar "tw-hidden" "")
}}
{{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}}
{{$cmpBranch := ""}}
Expand All @@ -48,7 +62,7 @@
{{end}}
{{$cmpBranch = print $cmpBranch (.BranchName|PathEscapeSegments)}}
{{$compareLink := printf "%s/compare/%s...%s" .BaseRepo.Link (.BaseRepo.DefaultBranch|PathEscapeSegments) $cmpBranch}}
<a id="new-pull-request" role="button" class="ui compact basic button" href="{{$compareLink}}"
<a id="new-pull-request" role="button" class="ui compact basic button {{if $hasAndShowTreeSidebar}}tw-hidden{{end}}" href="{{$compareLink}}"
data-tooltip-content="{{if .PullRequestCtx.Allowed}}{{ctx.Locale.Tr "repo.pulls.compare_changes"}}{{else}}{{ctx.Locale.Tr "action.compare_branch"}}{{end}}">
{{svg "octicon-git-pull-request"}}
</a>
Expand All @@ -60,7 +74,7 @@
{{end}}

{{if and .CanWriteCode .IsViewBranch (not .Repository.IsMirror) (not .Repository.IsArchived) (not .IsViewFile)}}
<button class="ui dropdown basic compact jump button"{{if not .Repository.CanEnableEditor}} disabled{{end}}>
<button class="add-file-dropdown ui dropdown basic compact jump button {{if $hasAndShowTreeSidebar}}tw-hidden{{end}}"{{if not .Repository.CanEnableEditor}} disabled{{end}}>
{{ctx.Locale.Tr "repo.editor.add_file"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
Expand Down
65 changes: 65 additions & 0 deletions templates/repo/view_file_tree_sidebar.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<div class="view-file-tree-sidebar-top">
<div class="sidebar-header">
<button class="hide-tree-sidebar-button ui compact basic button icon" title="{{ctx.Locale.Tr "repo.diff.hide_file_tree"}}">
{{svg "octicon-sidebar-expand" 20 "icon"}}
</button>
<b> Files</b>
</div>
<div class="sidebar-ref">
{{$branchDropdownCurrentRefType := "branch"}}
{{$branchDropdownCurrentRefShortName := .BranchName}}
{{if .IsViewTag}}
{{$branchDropdownCurrentRefType = "tag"}}
{{$branchDropdownCurrentRefShortName = .TagName}}
{{end}}
{{template "repo/branch_dropdown" dict
"Repository" .Repository
"ShowTabBranches" true
"ShowTabTags" true
"CurrentRefType" $branchDropdownCurrentRefType
"CurrentRefShortName" $branchDropdownCurrentRefShortName
"CurrentTreePath" .TreePath
"RefLinkTemplate" "{RepoLink}/src/{RefType}/{RefShortName}/{TreePath}"
"AllowCreateNewRef" .CanCreateBranch
"ShowViewAllRefsEntry" true
}}

{{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}}
{{$cmpBranch := ""}}
{{if ne .Repository.ID .BaseRepo.ID}}
{{$cmpBranch = printf "%s/%s:" (.Repository.OwnerName|PathEscape) (.Repository.Name|PathEscape)}}
{{end}}
{{$cmpBranch = print $cmpBranch (.BranchName|PathEscapeSegments)}}
{{$compareLink := printf "%s/compare/%s...%s" .BaseRepo.Link (.BaseRepo.DefaultBranch|PathEscapeSegments) $cmpBranch}}
<a role="button" class="ui compact basic button" href="{{$compareLink}}"
data-tooltip-content="{{if .PullRequestCtx.Allowed}}{{ctx.Locale.Tr "repo.pulls.compare_changes"}}{{else}}{{ctx.Locale.Tr "action.compare_branch"}}{{end}}">
{{svg "octicon-git-pull-request"}}
</a>
{{end}}

{{if and .CanWriteCode .IsViewBranch (not .Repository.IsMirror) (not .Repository.IsArchived) (not .IsViewFile)}}
<button class="ui dropdown basic compact jump button"{{if not .Repository.CanEnableEditor}} disabled{{end}}>
{{ctx.Locale.Tr "repo.editor.add_file"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<a class="item" href="{{.RepoLink}}/_new/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
{{ctx.Locale.Tr "repo.editor.new_file"}}
</a>
{{if .RepositoryUploadEnabled}}
<a class="item" href="{{.RepoLink}}/_upload/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
{{ctx.Locale.Tr "repo.editor.upload_file"}}
</a>
{{end}}
<a class="item" href="{{.RepoLink}}/_diffpatch/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}">
{{ctx.Locale.Tr "repo.editor.patch"}}
</a>
</div>
</button>
{{end}}
</div>
</div>
<div class="view-file-tree-sidebar-bottom">
<div id="view-file-tree" class="center" data-api-base-url="{{.RepoLink}}" data-tree-path="{{$.TreePath}}">
{{svg "octicon-sync" 16 "job-status-rotate"}}
</div>
</div>
43 changes: 43 additions & 0 deletions web_src/css/repo/home.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,49 @@
}
}

.repo-grid-tree-sidebar {
display: grid;
grid-template-columns: 300px auto;
grid-template-rows: auto auto 1fr;
}

.repo-grid-tree-sidebar .repo-home-filelist {
min-width: 0;
grid-column: 2;
grid-row: 1 / 4;
}

.repo-grid-tree-sidebar .repo-view-file-tree-sidebar {
display: flex;
flex-direction: column;
gap: 0.25em;
}

.repo-grid-tree-sidebar .view-file-tree-sidebar-top {
display: flex;
flex-direction: column;
gap: 0.25em;
}

.repo-grid-tree-sidebar .view-file-tree-sidebar-top .button {
padding: 6px 10px !important;
height: 30px;
flex-shrink: 0;
margin: 0;
}

.repo-grid-tree-sidebar .view-file-tree-sidebar-top .sidebar-ref {
display: flex;
gap: 0.25em;
}

@media (max-width: 767.98px) {
.repo-grid-tree-sidebar {
grid-template-columns: auto;
grid-template-rows: auto auto auto;
}
}

.language-stats {
display: flex;
gap: 2px;
Expand Down
26 changes: 26 additions & 0 deletions web_src/js/components/ViewFileTree.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script lang="ts" setup>
import ViewFileTreeItem from './ViewFileTreeItem.vue';

defineProps<{
files: any,
selectedItem: any,
loadChildren: any,
loadContent: any;
}>();
</script>

<template>
<div class="view-file-tree-items">
<!-- only render the tree if we're visible. in many cases this is something that doesn't change very often -->
<ViewFileTreeItem v-for="item in files" :key="item.name" :item="item" :selected-item="selectedItem" :load-content="loadContent" :load-children="loadChildren"/>
</div>
</template>

<style scoped>
.view-file-tree-items {
display: flex;
flex-direction: column;
gap: 1px;
margin-right: .5rem;
}
</style>
Loading
Loading