From 181645f4edac217522e2aaa730a98e472ac60c90 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Thu, 12 Dec 2024 15:20:28 +0000 Subject: [PATCH 01/77] add tree sidebar to file view --- routers/web/repo/blame.go | 5 + routers/web/repo/file.go | 45 +++++++ routers/web/repo/repo.go | 18 +++ routers/web/repo/view_home.go | 5 + routers/web/web.go | 5 + templates/repo/home.tmpl | 20 ++- templates/repo/view_file_tree_sidebar.tmpl | 65 ++++++++++ web_src/css/repo/home.css | 43 +++++++ web_src/js/components/ViewFileTree.vue | 25 ++++ web_src/js/components/ViewFileTreeItem.vue | 119 ++++++++++++++++++ .../features/repo-view-file-tree-sidebar.ts | 87 +++++++++++++ web_src/js/index.ts | 2 + 12 files changed, 436 insertions(+), 3 deletions(-) create mode 100644 routers/web/repo/file.go create mode 100644 templates/repo/view_file_tree_sidebar.tmpl create mode 100644 web_src/js/components/ViewFileTree.vue create mode 100644 web_src/js/components/ViewFileTreeItem.vue create mode 100644 web_src/js/features/repo-view-file-tree-sidebar.ts diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index ad790875136c3..2bdaeefb88c61 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -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() diff --git a/routers/web/repo/file.go b/routers/web/repo/file.go new file mode 100644 index 0000000000000..60e7cb24b74da --- /dev/null +++ b/routers/web/repo/file.go @@ -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) +} diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index f5e59b0357b02..fbd3c835518c9 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -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" @@ -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() +} diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go index b318c4a621a60..707387f8e5cc4 100644 --- a/routers/web/repo/view_home.go +++ b/routers/web/repo/view_home.go @@ -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 diff --git a/routers/web/web.go b/routers/web/web.go index 72ee47bb4c962..bf8c4306bf314 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -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 @@ -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). diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 4e6d375b51710..89d2442afafc4 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -19,11 +19,24 @@ {{$treeNamesLen := len .TreeNames}} {{$isTreePathRoot := eq $treeNamesLen 0}} {{$showSidebar := $isTreePathRoot}} -
+ {{$hasTreeSidebar := not $isTreePathRoot}} + {{$showTreeSidebar := .RepoPreferences.ShowFileViewTreeSidebar}} + {{$hideTreeSidebar := not $showTreeSidebar}} + {{$hasAndShowTreeSidebar := and $hasTreeSidebar $showTreeSidebar}} +
+ {{if $hasTreeSidebar}} +
{{template "repo/view_file_tree_sidebar" .}}
+ {{end}} +
{{template "repo/sub_menu" .}}
+ {{if $hasTreeSidebar}} + + {{end}} {{$branchDropdownCurrentRefType := "branch"}} {{$branchDropdownCurrentRefShortName := .BranchName}} {{if .IsViewTag}} @@ -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 := ""}} @@ -48,7 +62,7 @@ {{end}} {{$cmpBranch = print $cmpBranch (.BranchName|PathEscapeSegments)}} {{$compareLink := printf "%s/compare/%s...%s" .BaseRepo.Link (.BaseRepo.DefaultBranch|PathEscapeSegments) $cmpBranch}} - {{svg "octicon-git-pull-request"}} @@ -60,7 +74,7 @@ {{end}} {{if and .CanWriteCode .IsViewBranch (not .Repository.IsMirror) (not .Repository.IsArchived) (not .IsViewFile)}} - + Files +
+ +
+
+
+ {{svg "octicon-sync" 16 "job-status-rotate"}} +
+
diff --git a/web_src/css/repo/home.css b/web_src/css/repo/home.css index ca5b432804fe4..71ccbaf8f227f 100644 --- a/web_src/css/repo/home.css +++ b/web_src/css/repo/home.css @@ -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; diff --git a/web_src/js/components/ViewFileTree.vue b/web_src/js/components/ViewFileTree.vue new file mode 100644 index 0000000000000..605314027ce83 --- /dev/null +++ b/web_src/js/components/ViewFileTree.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue new file mode 100644 index 0000000000000..0df09613bc0f1 --- /dev/null +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -0,0 +1,119 @@ + + + + diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts new file mode 100644 index 0000000000000..26a9d0111b118 --- /dev/null +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -0,0 +1,87 @@ +import {createApp} from 'vue'; +import {toggleElem} from '../utils/dom.ts'; +import {GET, PUT} from '../modules/fetch.ts'; +import ViewFileTree from '../components/ViewFileTree.vue'; + +async function toggleSidebar(visibility) { + const sidebarEl = document.querySelector('.repo-view-file-tree-sidebar'); + const showBtnEl = document.querySelector('.show-tree-sidebar-button'); + const refSelectorEl = document.querySelector('.repo-home-filelist .js-branch-tag-selector'); + const newPrBtnEl = document.querySelector('.repo-home-filelist #new-pull-request'); + const addFileEl = document.querySelector('.repo-home-filelist .add-file-dropdown'); + const containerClassList = sidebarEl.parentElement.classList; + containerClassList.toggle('repo-grid-tree-sidebar', visibility); + containerClassList.toggle('repo-grid-filelist-only', !visibility); + toggleElem(sidebarEl, visibility); + toggleElem(showBtnEl, !visibility); + toggleElem(refSelectorEl, !visibility); + toggleElem(newPrBtnEl, !visibility); + if (addFileEl) { + toggleElem(addFileEl, !visibility); + } + + // save to session + await PUT('/repo/preferences', { + data: { + show_file_view_tree_sidebar: visibility, + }, + }); +} + +async function loadChildren(item?) { + const el = document.querySelector('#view-file-tree'); + const apiBaseUrl = el.getAttribute('data-api-base-url'); + const response = await GET(`${apiBaseUrl}/contents/${item ? item.path : ''}`); + const json = await response.json(); + if (json instanceof Array) { + return json.map((i) => ({ + name: i.name, + isFile: i.type === 'file', + htmlUrl: i.html_url, + path: i.path, + })); + } + return null; +} + +async function loadRecursive(treePath) { + let root = null; + let parent = null; + let parentPath = ''; + for (const i of (`/${treePath}`).split('/')) { + const path = `${parentPath}${parentPath ? '/' : ''}${i}`; + const result = await loadChildren({path}); + if (root === null) { + root = result; + parent = root; + } else { + parent = parent.find((item) => item.path === path); + parent.children = result; + parent = result; + } + parentPath = path; + } + return root; +} + +export async function initViewFileTreeSidebar() { + const sidebarElement = document.querySelector('.repo-view-file-tree-sidebar'); + if (!sidebarElement) return; + + document.querySelector('.show-tree-sidebar-button').addEventListener('click', () => { + toggleSidebar(true); + }); + + document.querySelector('.hide-tree-sidebar-button').addEventListener('click', () => { + toggleSidebar(false); + }); + + const fileTree = document.querySelector('#view-file-tree'); + const treePath = fileTree.getAttribute('data-tree-path'); + + const files = await loadRecursive(treePath); + + fileTree.classList.remove('center'); + const fileTreeView = createApp(ViewFileTree, {files, selectedItem: treePath, loadChildren}); + fileTreeView.mount(fileTree); +} diff --git a/web_src/js/index.ts b/web_src/js/index.ts index 51d8c96fbdfbf..4602e22ffa5e9 100644 --- a/web_src/js/index.ts +++ b/web_src/js/index.ts @@ -33,6 +33,7 @@ import { } from './features/repo-issue.ts'; import {initRepoEllipsisButton, initCommitStatuses} from './features/repo-commit.ts'; import {initRepoTopicBar} from './features/repo-home.ts'; +import {initViewFileTreeSidebar} from './features/repo-view-file-tree-sidebar.ts'; import {initAdminCommon} from './features/admin/common.ts'; import {initRepoTemplateSearch} from './features/repo-template.ts'; import {initRepoCodeView} from './features/repo-code.ts'; @@ -195,6 +196,7 @@ onDomReady(() => { initRepoReleaseNew, initRepoTemplateSearch, initRepoTopicBar, + initViewFileTreeSidebar, initRepoWikiForm, initRepository, initRepositoryActionView, From c4e7f0c11929c5c0581792cedbee3dec66437b7b Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Fri, 13 Dec 2024 08:08:41 +0000 Subject: [PATCH 02/77] add tree sidebar to file view --- templates/repo/home.tmpl | 14 +++++++------- web_src/js/components/ViewFileTree.vue | 5 +++-- web_src/js/components/ViewFileTreeItem.vue | 15 ++++++++------- .../js/features/repo-view-file-tree-sidebar.ts | 13 +++++++++++-- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 89d2442afafc4..f5c76a026bc6f 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -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}}
{{template "repo/header" .}}
@@ -16,13 +23,6 @@ {{template "repo/code/recently_pushed_new_branches" .}} - {{$treeNamesLen := len .TreeNames}} - {{$isTreePathRoot := eq $treeNamesLen 0}} - {{$showSidebar := $isTreePathRoot}} - {{$hasTreeSidebar := not $isTreePathRoot}} - {{$showTreeSidebar := .RepoPreferences.ShowFileViewTreeSidebar}} - {{$hideTreeSidebar := not $showTreeSidebar}} - {{$hasAndShowTreeSidebar := and $hasTreeSidebar $showTreeSidebar}}
{{if $hasTreeSidebar}}
{{template "repo/view_file_tree_sidebar" .}}
diff --git a/web_src/js/components/ViewFileTree.vue b/web_src/js/components/ViewFileTree.vue index 605314027ce83..3337f6e9e553e 100644 --- a/web_src/js/components/ViewFileTree.vue +++ b/web_src/js/components/ViewFileTree.vue @@ -3,15 +3,16 @@ import ViewFileTreeItem from './ViewFileTreeItem.vue'; defineProps<{ files: any, - selectedItem: string, + selectedItem: any, loadChildren: any, + loadContent: any; }>(); diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index 0df09613bc0f1..db2e888fddfdf 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -12,13 +12,14 @@ type Item = { const props = defineProps<{ item: Item, + loadContent: any; loadChildren: any; - selectedItem?: string; + selectedItem?: any; }>(); const isLoading = ref(false); -const collapsed = ref(!props.item.children); const children = ref(props.item.children); +const collapsed = ref(!props.item.children); const doLoadChildren = async () => { collapsed.value = !collapsed.value; @@ -32,11 +33,11 @@ const doLoadChildren = async () => { const doLoadDirContent = () => { doLoadChildren(); - window.location.href = props.item.htmlUrl; + props.loadContent(props.item); }; const doLoadFileContent = () => { - window.location.href = props.item.htmlUrl; + props.loadContent(props.item); }; @@ -44,7 +45,7 @@ const doLoadFileContent = () => {
@@ -54,7 +55,7 @@ const doLoadFileContent = () => {
@@ -66,7 +67,7 @@ const doLoadFileContent = () => {
- +
From 2d644fb4cea501063294afe9451229ea1795185d Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 14 Jan 2025 21:47:59 -0800 Subject: [PATCH 57/77] make template simpler --- templates/repo/home.tmpl | 15 +++++---------- templates/repo/home_content.tmpl | 11 ++++------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 07141256c7beb..290e80064c574 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -1,13 +1,8 @@ {{template "base/head" .}} -{{$treeNamesLen := len .TreeNames}} -{{$isTreePathRoot := eq $treeNamesLen 0}} -{{$showSidebar := and $isTreePathRoot (not .HideRepoInfo) (not .IsBlame)}} -{{$hasTreeSidebar := not $isTreePathRoot}} -{{$showTreeSidebar := .RepoPreferences.ShowFileViewTreeSidebar}} -{{$hideTreeSidebar := not $showTreeSidebar}} +{{$showSidebar := and (not .TreeNames) (not .HideRepoInfo) (not .IsBlame)}}
{{template "repo/header" .}} -
+
{{template "base/alert" .}} {{if .Repository.IsArchived}} @@ -22,9 +17,9 @@ {{template "repo/code/recently_pushed_new_branches" .}} -
- {{if $hasTreeSidebar}} -
{{template "repo/view_file_tree_sidebar" .}}
+
+ {{if .TreeNames}} +
{{template "repo/view_file_tree_sidebar" .}}
{{end}}
diff --git a/templates/repo/home_content.tmpl b/templates/repo/home_content.tmpl index 881a9de1a4d66..291ceb50cdca7 100644 --- a/templates/repo/home_content.tmpl +++ b/templates/repo/home_content.tmpl @@ -1,14 +1,11 @@ -{{$treeNamesLen := len .TreeNames}} -{{$isTreePathRoot := eq $treeNamesLen 0}} +{{$isTreePathRoot := not .TreeNames}} {{$showSidebar := and $isTreePathRoot (not .HideRepoInfo) (not .IsBlame)}} -{{$hasTreeSidebar := not $isTreePathRoot}} -{{$showTreeSidebar := .RepoPreferences.ShowFileViewTreeSidebar}} {{template "repo/sub_menu" .}}
- {{if $hasTreeSidebar}} - {{end}} @@ -58,7 +55,7 @@ {{end}} {{if not $isTreePathRoot}} - {{$treeNameIdxLast := Eval $treeNamesLen "-" 1}} + {{$treeNameIdxLast := Eval (len .TreeNames) "-" 1}} {{StringUtils.EllipsisString .Repository.Name 30}} {{- range $i, $v := .TreeNames -}} From bb8297919178719c4085e0e9285727c41e4a2576 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 14 Jan 2025 21:57:42 -0800 Subject: [PATCH 58/77] remove duplicated code --- routers/web/repo/blame.go | 13 +------------ routers/web/repo/view_home.go | 28 ++++++++++++++++------------ 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index 31a6a577728a7..808d2cb052c6b 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -46,18 +46,7 @@ func RefBlame(ctx *context.Context) { return } - showFileViewTreeSidebar := true - if ctx.Doer != nil { - v, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyShowFileViewTreeSidebar, "true") - if err != nil { - log.Error("GetUserSetting: %v", err) - } else { - showFileViewTreeSidebar, _ = strconv.ParseBool(v) - } - } - ctx.Data["RepoPreferences"] = &preferencesForm{ - ShowFileViewTreeSidebar: showFileViewTreeSidebar, - } + prepareHomeTreeSideBarSwitch(ctx) branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.RefTypeNameSubURL() treeLink := branchLink diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go index 0c5a20eff7d42..39da84b1e9dfc 100644 --- a/routers/web/repo/view_home.go +++ b/routers/web/repo/view_home.go @@ -312,6 +312,21 @@ func handleRepoHomeFeed(ctx *context.Context) bool { return false } +func prepareHomeTreeSideBarSwitch(ctx *context.Context) { + showFileViewTreeSidebar := true + if ctx.Doer != nil { + v, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyShowFileViewTreeSidebar, "true") + if err != nil { + log.Error("GetUserSetting: %v", err) + } else { + showFileViewTreeSidebar, _ = strconv.ParseBool(v) + } + } + ctx.Data["RepoPreferences"] = &preferencesForm{ + ShowFileViewTreeSidebar: showFileViewTreeSidebar, + } +} + // Home render repository home page func Home(ctx *context.Context) { if handleRepoHomeFeed(ctx) { @@ -325,18 +340,7 @@ func Home(ctx *context.Context) { return } - showFileViewTreeSidebar := true - if ctx.Doer != nil { - v, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyShowFileViewTreeSidebar, "true") - if err != nil { - log.Error("GetUserSetting: %v", err) - } else { - showFileViewTreeSidebar, _ = strconv.ParseBool(v) - } - } - ctx.Data["RepoPreferences"] = &preferencesForm{ - ShowFileViewTreeSidebar: showFileViewTreeSidebar, - } + prepareHomeTreeSideBarSwitch(ctx) title := ctx.Repo.Repository.Owner.Name + "/" + ctx.Repo.Repository.Name if len(ctx.Repo.Repository.Description) > 0 { From 717991640291fd9ea151eb7f14e35ad252f1fd7c Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Thu, 16 Jan 2025 01:22:25 +0000 Subject: [PATCH 59/77] fix --- web_src/css/repo/home.css | 3 +++ web_src/js/features/repo-view-file-tree-sidebar.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/web_src/css/repo/home.css b/web_src/css/repo/home.css index db171e7974b29..d8ca1339f98c7 100644 --- a/web_src/css/repo/home.css +++ b/web_src/css/repo/home.css @@ -73,6 +73,9 @@ gap: 8px; max-height: 100vh; overflow: hidden; + position: sticky; + top: 14px; + z-index: 8; } .repo-grid-tree-sidebar .view-file-tree-sidebar-top { diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index 8bec3d06ae255..22f7978f3053d 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -2,6 +2,7 @@ import {createApp, ref} from 'vue'; import {toggleElem} from '../utils/dom.ts'; import {GET, PUT} from '../modules/fetch.ts'; import ViewFileTree from '../components/ViewFileTree.vue'; +import {initMarkupContent} from '../markup/content.ts'; import {initTargetRepoBranchTagSelector} from './repo-legacy.ts'; import {initTargetDropdown} from './common-page.ts'; import {initTargetRepoEllipsisButton} from './repo-commit.ts'; @@ -58,6 +59,7 @@ function reloadContentScript(contentEl: Element) { contentEl.querySelector('.show-tree-sidebar-button').addEventListener('click', () => { toggleSidebar(true, document.querySelector('.repo-view-file-tree-sidebar').hasAttribute('data-is-signed')); }); + initMarkupContent(); initTargetButtons(contentEl); initTargetDropdown(contentEl); initTargetPdfViewer(contentEl); From a0f69ec1a1f7bf0c2e1ccaad1dd556d6ede04717 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Thu, 20 Feb 2025 06:13:11 +0000 Subject: [PATCH 60/77] fix --- routers/web/repo/tree.go | 3 ++- web_src/js/components/ViewFileTreeItem.vue | 6 +++--- .../js/features/repo-view-file-tree-sidebar.ts | 16 ++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/routers/web/repo/tree.go b/routers/web/repo/tree.go index 78aa5537f61db..b4d214e4d050b 100644 --- a/routers/web/repo/tree.go +++ b/routers/web/repo/tree.go @@ -4,6 +4,7 @@ package repo import ( + "errors" "net/http" "code.gitea.io/gitea/modules/base" @@ -58,7 +59,7 @@ func Tree(ctx *context.Context) { recursive := ctx.FormBool("recursive") if ctx.Repo.RefFullName == "" { - ctx.Error(http.StatusBadRequest, "RefFullName", "ref_name is invalid") + ctx.ServerError("RefFullName", errors.New("ref_name is invalid")) return } diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index cbfe68ac8e573..9240ba45f5def 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -25,7 +25,7 @@ const doLoadChildren = async () => { collapsed.value = !collapsed.value; if (!collapsed.value && props.loadChildren) { isLoading.value = true; - const _children = await props.loadChildren(props.item); + const _children = await props.loadChildren(props.item.path); children.value = _children; isLoading.value = false; } @@ -33,11 +33,11 @@ const doLoadChildren = async () => { const doLoadDirContent = () => { doLoadChildren(); - props.loadContent(props.item); + props.loadContent(props.item.path); }; const doLoadFileContent = () => { - props.loadContent(props.item); + props.loadContent(props.item.path); }; const doGotoSubModule = () => { diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index 22f7978f3053d..d7fdb3f2d2a57 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -10,7 +10,7 @@ import {initTargetPdfViewer} from '../render/pdf.ts'; import {initTargetButtons} from './common-button.ts'; import {initTargetCopyContent} from './copycontent.ts'; -async function toggleSidebar(visibility, isSigned) { +async function toggleSidebar(visibility: boolean, isSigned: boolean) { const sidebarEl = document.querySelector('.repo-view-file-tree-sidebar'); const showBtnEl = document.querySelector('.show-tree-sidebar-button'); const containerClassList = sidebarEl.parentElement.classList; @@ -29,11 +29,11 @@ async function toggleSidebar(visibility, isSigned) { }); } -async function loadChildren(item, recursive?: boolean) { +async function loadChildren(path: string, recursive?: boolean) { const fileTree = document.querySelector('#view-file-tree'); const apiBaseUrl = fileTree.getAttribute('data-api-base-url'); const refTypeNameSubURL = fileTree.getAttribute('data-current-ref-type-name-sub-url'); - const response = await GET(`${apiBaseUrl}/tree/${refTypeNameSubURL}/${item ? item.path : ''}?recursive=${recursive ?? false}`); + const response = await GET(`${apiBaseUrl}/tree/${refTypeNameSubURL}/${path ?? ''}?recursive=${recursive ?? false}`); const json = await response.json(); if (json instanceof Array) { return json.map((i) => ({ @@ -90,12 +90,12 @@ export async function initViewFileTreeSidebar() { const selectedItem = ref(treePath); - const files = await loadChildren({path: treePath}, true); + const files = await loadChildren(treePath, true); fileTree.classList.remove('is-loading'); - const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren, loadContent: (item) => { - window.history.pushState(null, null, `${baseUrl}/src${refString}/${item.path}`); - selectedItem.value = item.path; + const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren, loadContent: (path: string) => { + window.history.pushState(null, null, `${baseUrl}/src${refString}/${path}`); + selectedItem.value = path; loadContent(); }}); fileTreeView.mount(fileTree); @@ -106,7 +106,7 @@ export async function initViewFileTreeSidebar() { }); } -function extractPath(url) { +function extractPath(url: string) { // Create a URL object const urlObj = new URL(url); From bf83b2a1e51d825fbbf5b251f486303a0f0c8f66 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 3 Mar 2025 06:04:34 +0000 Subject: [PATCH 61/77] Revert some changes, and plan to complete the adaptation of the function in a new way of global-*. --- web_src/js/features/common-button.ts | 10 +++----- web_src/js/features/copycontent.ts | 6 +---- web_src/js/features/repo-commit.ts | 6 +---- web_src/js/features/repo-legacy.ts | 14 +++++------ .../features/repo-view-file-tree-sidebar.ts | 24 +++++++++---------- web_src/js/render/pdf.ts | 6 +---- 6 files changed, 25 insertions(+), 41 deletions(-) diff --git a/web_src/js/features/common-button.ts b/web_src/js/features/common-button.ts index 284c590fca62d..7aebdd8dd5be5 100644 --- a/web_src/js/features/common-button.ts +++ b/web_src/js/features/common-button.ts @@ -160,11 +160,7 @@ export function initGlobalButtons(): void { // There are a few cancel buttons in non-modal forms, and there are some dynamically created forms (eg: the "Edit Issue Content") addDelegatedEventListener(document, 'click', 'form button.ui.cancel.button', (_ /* el */, e) => e.preventDefault()); - initTargetButtons(document); -} - -export function initTargetButtons(target: ParentNode): void { - queryElems(target, '.show-panel', (el) => el.addEventListener('click', onShowPanelClick)); - queryElems(target, '.hide-panel', (el) => el.addEventListener('click', onHidePanelClick)); - queryElems(target, '.show-modal', (el) => el.addEventListener('click', onShowModalClick)); + queryElems(document, '.show-panel', (el) => el.addEventListener('click', onShowPanelClick)); + queryElems(document, '.hide-panel', (el) => el.addEventListener('click', onHidePanelClick)); + queryElems(document, '.show-modal', (el) => el.addEventListener('click', onShowModalClick)); } diff --git a/web_src/js/features/copycontent.ts b/web_src/js/features/copycontent.ts index 0bc14c3bff5af..4bc9281a35e4f 100644 --- a/web_src/js/features/copycontent.ts +++ b/web_src/js/features/copycontent.ts @@ -6,11 +6,7 @@ import {GET} from '../modules/fetch.ts'; const {i18n} = window.config; export function initCopyContent() { - initTargetCopyContent(document); -} - -export function initTargetCopyContent(target: ParentNode) { - const btn = target.querySelector('#copy-content'); + const btn = document.querySelector('#copy-content'); if (!btn || btn.classList.contains('disabled')) return; btn.addEventListener('click', async () => { diff --git a/web_src/js/features/repo-commit.ts b/web_src/js/features/repo-commit.ts index f0a2f878d84f6..8994a57f4a8af 100644 --- a/web_src/js/features/repo-commit.ts +++ b/web_src/js/features/repo-commit.ts @@ -2,11 +2,7 @@ import {createTippy} from '../modules/tippy.ts'; import {toggleElem} from '../utils/dom.ts'; export function initRepoEllipsisButton() { - initTargetRepoEllipsisButton(document); -} - -export function initTargetRepoEllipsisButton(target: ParentNode) { - for (const button of target.querySelectorAll('.js-toggle-commit-body')) { + for (const button of document.querySelectorAll('.js-toggle-commit-body')) { button.addEventListener('click', function (e) { e.preventDefault(); const expanded = this.getAttribute('aria-expanded') === 'true'; diff --git a/web_src/js/features/repo-legacy.ts b/web_src/js/features/repo-legacy.ts index 90568edca83e9..a1b53c1f41327 100644 --- a/web_src/js/features/repo-legacy.ts +++ b/web_src/js/features/repo-legacy.ts @@ -20,6 +20,12 @@ import {initRepoNew} from './repo-new.ts'; import {createApp} from 'vue'; import RepoBranchTagSelector from '../components/RepoBranchTagSelector.vue'; +function initRepoBranchTagSelector(selector: string) { + for (const elRoot of document.querySelectorAll(selector)) { + createApp(RepoBranchTagSelector, {elRoot}).mount(elRoot); + } +} + export function initBranchSelectorTabs() { const elSelectBranches = document.querySelectorAll('.ui.dropdown.select-branch'); for (const elSelectBranch of elSelectBranches) { @@ -32,17 +38,11 @@ export function initBranchSelectorTabs() { } } -export function initTargetRepoBranchTagSelector(target: ParentNode, selector: string = '.js-branch-tag-selector') { - for (const elRoot of target.querySelectorAll(selector)) { - createApp(RepoBranchTagSelector, {elRoot}).mount(elRoot); - } -} - export function initRepository() { const pageContent = document.querySelector('.page-content.repository'); if (!pageContent) return; - initTargetRepoBranchTagSelector(document); + initRepoBranchTagSelector('.js-branch-tag-selector'); initRepoCommentFormAndSidebar(); // Labels diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index 3f82882390f07..33933563c9246 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -2,12 +2,12 @@ import {createApp, ref} from 'vue'; import {toggleElem} from '../utils/dom.ts'; import {GET, PUT} from '../modules/fetch.ts'; import ViewFileTree from '../components/ViewFileTree.vue'; -import {initMarkupContent} from '../markup/content.ts'; -import {initTargetRepoBranchTagSelector} from './repo-legacy.ts'; -import {initTargetRepoEllipsisButton} from './repo-commit.ts'; -import {initTargetPdfViewer} from '../render/pdf.ts'; -import {initTargetButtons} from './common-button.ts'; -import {initTargetCopyContent} from './copycontent.ts'; +// import {initMarkupContent} from '../markup/content.ts'; +// import {initTargetRepoBranchTagSelector} from './repo-legacy.ts'; +// import {initTargetRepoEllipsisButton} from './repo-commit.ts'; +// import {initTargetPdfViewer} from '../render/pdf.ts'; +// import {initTargetButtons} from './common-button.ts'; +// import {initTargetCopyContent} from './copycontent.ts'; async function toggleSidebar(visibility: boolean, isSigned: boolean) { const sidebarEl = document.querySelector('.repo-view-file-tree-sidebar'); @@ -58,13 +58,13 @@ function reloadContentScript(contentEl: Element) { contentEl.querySelector('.show-tree-sidebar-button').addEventListener('click', () => { toggleSidebar(true, document.querySelector('.repo-view-file-tree-sidebar').hasAttribute('data-is-signed')); }); - initMarkupContent(); - initTargetButtons(contentEl); + // initMarkupContent(); + // initTargetButtons(contentEl); // initTargetDropdown(contentEl); - initTargetPdfViewer(contentEl); - initTargetRepoBranchTagSelector(contentEl); - initTargetRepoEllipsisButton(contentEl); - initTargetCopyContent(contentEl); + // initTargetPdfViewer(contentEl); + // initTargetRepoBranchTagSelector(contentEl); + // initTargetRepoEllipsisButton(contentEl); + // initTargetCopyContent(contentEl); } export async function initViewFileTreeSidebar() { diff --git a/web_src/js/render/pdf.ts b/web_src/js/render/pdf.ts index 5bed6f7bab842..f31f161e6e8e2 100644 --- a/web_src/js/render/pdf.ts +++ b/web_src/js/render/pdf.ts @@ -1,11 +1,7 @@ import {htmlEscape} from 'escape-goat'; export async function initPdfViewer() { - initTargetPdfViewer(document); -} - -export async function initTargetPdfViewer(target: ParentNode) { - const els = target.querySelectorAll('.pdf-content'); + const els = document.querySelectorAll('.pdf-content'); if (!els.length) return; const pdfobject = await import(/* webpackChunkName: "pdfobject" */'pdfobject'); From 2d5a570faa58e8160513954f3098ef793e3c6212 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Tue, 4 Mar 2025 00:29:38 +0000 Subject: [PATCH 62/77] fix --- web_src/js/features/repo-view-file-tree-sidebar.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index 33933563c9246..858f640f198b9 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -2,12 +2,6 @@ import {createApp, ref} from 'vue'; import {toggleElem} from '../utils/dom.ts'; import {GET, PUT} from '../modules/fetch.ts'; import ViewFileTree from '../components/ViewFileTree.vue'; -// import {initMarkupContent} from '../markup/content.ts'; -// import {initTargetRepoBranchTagSelector} from './repo-legacy.ts'; -// import {initTargetRepoEllipsisButton} from './repo-commit.ts'; -// import {initTargetPdfViewer} from '../render/pdf.ts'; -// import {initTargetButtons} from './common-button.ts'; -// import {initTargetCopyContent} from './copycontent.ts'; async function toggleSidebar(visibility: boolean, isSigned: boolean) { const sidebarEl = document.querySelector('.repo-view-file-tree-sidebar'); @@ -58,13 +52,6 @@ function reloadContentScript(contentEl: Element) { contentEl.querySelector('.show-tree-sidebar-button').addEventListener('click', () => { toggleSidebar(true, document.querySelector('.repo-view-file-tree-sidebar').hasAttribute('data-is-signed')); }); - // initMarkupContent(); - // initTargetButtons(contentEl); - // initTargetDropdown(contentEl); - // initTargetPdfViewer(contentEl); - // initTargetRepoBranchTagSelector(contentEl); - // initTargetRepoEllipsisButton(contentEl); - // initTargetCopyContent(contentEl); } export async function initViewFileTreeSidebar() { From 9fc2ba3705266ec4909897f77a0808340064efc8 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Tue, 4 Mar 2025 00:51:31 +0000 Subject: [PATCH 63/77] Refactor initViewFileTreeSidebar using the new registerGlobalInitFunc --- templates/repo/home.tmpl | 2 +- .../features/repo-view-file-tree-sidebar.ts | 81 +++++++++---------- 2 files changed, 40 insertions(+), 43 deletions(-) diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 290e80064c574..7e16dd6549246 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -19,7 +19,7 @@
{{if .TreeNames}} -
{{template "repo/view_file_tree_sidebar" .}}
+
{{template "repo/view_file_tree_sidebar" .}}
{{end}}
diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index 858f640f198b9..a730cae3e9c35 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -1,10 +1,10 @@ import {createApp, ref} from 'vue'; import {toggleElem} from '../utils/dom.ts'; import {GET, PUT} from '../modules/fetch.ts'; +import {registerGlobalInitFunc} from '../modules/observer.ts'; import ViewFileTree from '../components/ViewFileTree.vue'; -async function toggleSidebar(visibility: boolean, isSigned: boolean) { - const sidebarEl = document.querySelector('.repo-view-file-tree-sidebar'); +async function toggleSidebar(sidebarEl: HTMLElement, visibility: boolean) { const showBtnEl = document.querySelector('.show-tree-sidebar-button'); const containerClassList = sidebarEl.parentElement.classList; containerClassList.toggle('repo-grid-tree-sidebar', visibility); @@ -12,7 +12,7 @@ async function toggleSidebar(visibility: boolean, isSigned: boolean) { toggleElem(sidebarEl, visibility); toggleElem(showBtnEl, !visibility); - if (!isSigned) return; + if (!sidebarEl.hasAttribute('data-is-signed')) return; // save to session await PUT('/repo/preferences', { @@ -40,55 +40,52 @@ async function loadChildren(path: string, recursive?: boolean) { return null; } -async function loadContent() { +async function loadContent(sidebarEl: HTMLElement) { // load content by path (content based on home_content.tmpl) const response = await GET(`${window.location.href}?only_content=true`); const contentEl = document.querySelector('.repo-home-filelist'); contentEl.innerHTML = await response.text(); - reloadContentScript(contentEl); + reloadContentScript(sidebarEl, contentEl); } -function reloadContentScript(contentEl: Element) { +function reloadContentScript(sidebarEl: HTMLElement, contentEl: Element) { contentEl.querySelector('.show-tree-sidebar-button').addEventListener('click', () => { - toggleSidebar(true, document.querySelector('.repo-view-file-tree-sidebar').hasAttribute('data-is-signed')); + toggleSidebar(sidebarEl, true); }); } -export async function initViewFileTreeSidebar() { - const sidebarElement = document.querySelector('.repo-view-file-tree-sidebar'); - if (!sidebarElement) return; - - const isSigned = sidebarElement.hasAttribute('data-is-signed'); - - document.querySelector('.hide-tree-sidebar-button').addEventListener('click', () => { - toggleSidebar(false, isSigned); - }); - document.querySelector('.repo-home-filelist .show-tree-sidebar-button').addEventListener('click', () => { - toggleSidebar(true, isSigned); - }); - - const fileTree = document.querySelector('#view-file-tree'); - const baseUrl = fileTree.getAttribute('data-api-base-url'); - const treePath = fileTree.getAttribute('data-tree-path'); - const refType = fileTree.getAttribute('data-current-ref-type'); - const refName = fileTree.getAttribute('data-current-ref-short-name'); - const refString = (refType ? (`/${refType}`) : '') + (refName ? (`/${refName}`) : ''); - - const selectedItem = ref(treePath); - - const files = await loadChildren(treePath, true); - - fileTree.classList.remove('is-loading'); - const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren, loadContent: (path: string) => { - window.history.pushState(null, null, `${baseUrl}/src${refString}/${path}`); - selectedItem.value = path; - loadContent(); - }}); - fileTreeView.mount(fileTree); - - window.addEventListener('popstate', () => { - selectedItem.value = extractPath(window.location.href); - loadContent(); +export function initViewFileTreeSidebar() { + registerGlobalInitFunc('initViewFileTreeSidebar', async (el: HTMLElement) => { + document.querySelector('.hide-tree-sidebar-button').addEventListener('click', () => { + toggleSidebar(el, false); + }); + document.querySelector('.repo-home-filelist .show-tree-sidebar-button').addEventListener('click', () => { + toggleSidebar(el, true); + }); + + const fileTree = document.querySelector('#view-file-tree'); + const baseUrl = fileTree.getAttribute('data-api-base-url'); + const treePath = fileTree.getAttribute('data-tree-path'); + const refType = fileTree.getAttribute('data-current-ref-type'); + const refName = fileTree.getAttribute('data-current-ref-short-name'); + const refString = (refType ? (`/${refType}`) : '') + (refName ? (`/${refName}`) : ''); + + const selectedItem = ref(treePath); + + const files = await loadChildren(treePath, true); + + fileTree.classList.remove('is-loading'); + const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren, loadContent: (path: string) => { + window.history.pushState(null, null, `${baseUrl}/src${refString}/${path}`); + selectedItem.value = path; + loadContent(el); + }}); + fileTreeView.mount(fileTree); + + window.addEventListener('popstate', () => { + selectedItem.value = extractPath(window.location.href); + loadContent(el); + }); }); } From a212ff6bb01b9f4049a0e76a029f315c89c0b3af Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Tue, 4 Mar 2025 07:11:45 +0000 Subject: [PATCH 64/77] fix --- .../features/repo-view-file-tree-sidebar.ts | 33 +++++-------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index a730cae3e9c35..a31c835a43dba 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -26,7 +26,7 @@ async function loadChildren(path: string, recursive?: boolean) { const fileTree = document.querySelector('#view-file-tree'); const apiBaseUrl = fileTree.getAttribute('data-api-base-url'); const refTypeNameSubURL = fileTree.getAttribute('data-current-ref-type-name-sub-url'); - const response = await GET(`${apiBaseUrl}/tree/${refTypeNameSubURL}/${path ?? ''}?recursive=${recursive ?? false}`); + const response = await GET(`${apiBaseUrl}/tree/${refTypeNameSubURL}/${encodeURIComponent(path ?? '')}?recursive=${recursive ?? false}`); const json = await response.json(); if (json instanceof Array) { return json.map((i) => ({ @@ -49,7 +49,7 @@ async function loadContent(sidebarEl: HTMLElement) { } function reloadContentScript(sidebarEl: HTMLElement, contentEl: Element) { - contentEl.querySelector('.show-tree-sidebar-button').addEventListener('click', () => { + contentEl.querySelector('.show-tree-sidebar-button')?.addEventListener('click', () => { toggleSidebar(sidebarEl, true); }); } @@ -70,41 +70,26 @@ export function initViewFileTreeSidebar() { const refName = fileTree.getAttribute('data-current-ref-short-name'); const refString = (refType ? (`/${refType}`) : '') + (refName ? (`/${refName}`) : ''); - const selectedItem = ref(treePath); + const selectedItem = ref(getSelectedPath(refString)); const files = await loadChildren(treePath, true); fileTree.classList.remove('is-loading'); const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren, loadContent: (path: string) => { - window.history.pushState(null, null, `${baseUrl}/src${refString}/${path}`); - selectedItem.value = path; + selectedItem.value = getSelectedPath(refString, `${baseUrl}/src${refString}/${path}`); + window.history.pushState(null, null, `${baseUrl}/src${refString}/${encodeURIComponent(path)}`); loadContent(el); }}); fileTreeView.mount(fileTree); window.addEventListener('popstate', () => { - selectedItem.value = extractPath(window.location.href); + selectedItem.value = getSelectedPath(refString); loadContent(el); }); }); } -function extractPath(url: string) { - // Create a URL object - const urlObj = new URL(url); - - // Get the pathname part - const path = urlObj.pathname; - - // Define a regular expression to match "/{param1}/{param2}/src/{branch}/{main}/" - const regex = /^\/[^/]+\/[^/]+\/src\/[^/]+\/[^/]+\//; - - // Use RegExp#exec() method to match the path - const match = regex.exec(path); - if (match) { - return path.substring(match[0].length); - } - - // If the path does not match, return the original path - return path; +function getSelectedPath(ref: string, url?: string) { + const path = url ?? (new URL(window.location.href).pathname); + return path.substring(path.indexOf(ref) + ref.length + 1); } From 605c5d4a072840fdf8f1a78f9a476cd1ec7d5fa3 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Tue, 4 Mar 2025 07:25:43 +0000 Subject: [PATCH 65/77] fix --- web_src/js/components/ViewFileTreeItem.vue | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index 9240ba45f5def..ec2660c8acad1 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -25,9 +25,12 @@ const doLoadChildren = async () => { collapsed.value = !collapsed.value; if (!collapsed.value && props.loadChildren) { isLoading.value = true; - const _children = await props.loadChildren(props.item.path); - children.value = _children; - isLoading.value = false; + try { + const _children = await props.loadChildren(props.item.path); + children.value = _children; + } finally { + isLoading.value = false; + } } }; From 3cbcd95e6a5f6067287f7866ee5dbd760470b611 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Tue, 4 Mar 2025 08:59:50 +0000 Subject: [PATCH 66/77] fix --- .../features/repo-view-file-tree-sidebar.ts | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index a31c835a43dba..e57cd4d7a6141 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -5,7 +5,7 @@ import {registerGlobalInitFunc} from '../modules/observer.ts'; import ViewFileTree from '../components/ViewFileTree.vue'; async function toggleSidebar(sidebarEl: HTMLElement, visibility: boolean) { - const showBtnEl = document.querySelector('.show-tree-sidebar-button'); + const showBtnEl = sidebarEl.parentElement.querySelector('.show-tree-sidebar-button'); const containerClassList = sidebarEl.parentElement.classList; containerClassList.toggle('repo-grid-tree-sidebar', visibility); containerClassList.toggle('repo-grid-filelist-only', !visibility); @@ -22,28 +22,30 @@ async function toggleSidebar(sidebarEl: HTMLElement, visibility: boolean) { }); } -async function loadChildren(path: string, recursive?: boolean) { - const fileTree = document.querySelector('#view-file-tree'); - const apiBaseUrl = fileTree.getAttribute('data-api-base-url'); - const refTypeNameSubURL = fileTree.getAttribute('data-current-ref-type-name-sub-url'); - const response = await GET(`${apiBaseUrl}/tree/${refTypeNameSubURL}/${encodeURIComponent(path ?? '')}?recursive=${recursive ?? false}`); - const json = await response.json(); - if (json instanceof Array) { - return json.map((i) => ({ - name: i.name, - type: i.type, - path: i.path, - sub_module_url: i.sub_module_url, - children: i.children, - })); - } - return null; +function childrenLoader(sidebarEl: HTMLElement) { + return async (path: string, recursive?: boolean) => { + const fileTree = sidebarEl.querySelector('#view-file-tree'); + const apiBaseUrl = fileTree.getAttribute('data-api-base-url'); + const refTypeNameSubURL = fileTree.getAttribute('data-current-ref-type-name-sub-url'); + const response = await GET(`${apiBaseUrl}/tree/${refTypeNameSubURL}/${encodeURIComponent(path ?? '')}?recursive=${recursive ?? false}`); + const json = await response.json(); + if (json instanceof Array) { + return json.map((i) => ({ + name: i.name, + type: i.type, + path: i.path, + sub_module_url: i.sub_module_url, + children: i.children, + })); + } + return null; + }; } async function loadContent(sidebarEl: HTMLElement) { // load content by path (content based on home_content.tmpl) const response = await GET(`${window.location.href}?only_content=true`); - const contentEl = document.querySelector('.repo-home-filelist'); + const contentEl = sidebarEl.parentElement.querySelector('.repo-home-filelist'); contentEl.innerHTML = await response.text(); reloadContentScript(sidebarEl, contentEl); } @@ -56,14 +58,14 @@ function reloadContentScript(sidebarEl: HTMLElement, contentEl: Element) { export function initViewFileTreeSidebar() { registerGlobalInitFunc('initViewFileTreeSidebar', async (el: HTMLElement) => { - document.querySelector('.hide-tree-sidebar-button').addEventListener('click', () => { + el.querySelector('.hide-tree-sidebar-button').addEventListener('click', () => { toggleSidebar(el, false); }); - document.querySelector('.repo-home-filelist .show-tree-sidebar-button').addEventListener('click', () => { + el.parentElement.querySelector('.repo-home-filelist .show-tree-sidebar-button').addEventListener('click', () => { toggleSidebar(el, true); }); - const fileTree = document.querySelector('#view-file-tree'); + const fileTree = el.querySelector('#view-file-tree'); const baseUrl = fileTree.getAttribute('data-api-base-url'); const treePath = fileTree.getAttribute('data-tree-path'); const refType = fileTree.getAttribute('data-current-ref-type'); @@ -72,10 +74,10 @@ export function initViewFileTreeSidebar() { const selectedItem = ref(getSelectedPath(refString)); - const files = await loadChildren(treePath, true); + const files = await childrenLoader(el)(treePath, true); fileTree.classList.remove('is-loading'); - const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren, loadContent: (path: string) => { + const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren: childrenLoader(el), loadContent: (path: string) => { selectedItem.value = getSelectedPath(refString, `${baseUrl}/src${refString}/${path}`); window.history.pushState(null, null, `${baseUrl}/src${refString}/${encodeURIComponent(path)}`); loadContent(el); From 6f2de3ea5e30522a5a24ed3ac0e8b6ea7c6a01f6 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Tue, 4 Mar 2025 11:21:39 +0000 Subject: [PATCH 67/77] fix --- web_src/js/features/repo-view-file-tree-sidebar.ts | 11 +++++++---- web_src/js/globals.d.ts | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index e57cd4d7a6141..3069584db33cb 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -84,10 +84,13 @@ export function initViewFileTreeSidebar() { }}); fileTreeView.mount(fileTree); - window.addEventListener('popstate', () => { - selectedItem.value = getSelectedPath(refString); - loadContent(el); - }); + if (!window.popstateListenerForViewFilePageAdded) { + window.addEventListener('popstate', () => { + selectedItem.value = getSelectedPath(refString); + loadContent(el); + }); + window.popstateListenerForViewFilePageAdded = true; + } }); } diff --git a/web_src/js/globals.d.ts b/web_src/js/globals.d.ts index 0c540ac296fc7..e1ccde79380ed 100644 --- a/web_src/js/globals.d.ts +++ b/web_src/js/globals.d.ts @@ -74,5 +74,6 @@ interface Window { turnstile: any, hcaptcha: any, codeEditors: any[], + popstateListenerForViewFilePageAdded: boolean, updateCloneStates: () => void, } From 31835f463806236fca5253a9740fee7702062b49 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Wed, 5 Mar 2025 02:53:11 +0000 Subject: [PATCH 68/77] fix --- web_src/js/features/repo-view-file-tree-sidebar.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index 3069584db33cb..ea14355c60475 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -27,7 +27,7 @@ function childrenLoader(sidebarEl: HTMLElement) { const fileTree = sidebarEl.querySelector('#view-file-tree'); const apiBaseUrl = fileTree.getAttribute('data-api-base-url'); const refTypeNameSubURL = fileTree.getAttribute('data-current-ref-type-name-sub-url'); - const response = await GET(`${apiBaseUrl}/tree/${refTypeNameSubURL}/${encodeURIComponent(path ?? '')}?recursive=${recursive ?? false}`); + const response = await GET(encodeURI(`${apiBaseUrl}/tree/${refTypeNameSubURL}/${path ?? ''}?recursive=${recursive ?? false}`)); const json = await response.json(); if (json instanceof Array) { return json.map((i) => ({ @@ -78,8 +78,8 @@ export function initViewFileTreeSidebar() { fileTree.classList.remove('is-loading'); const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren: childrenLoader(el), loadContent: (path: string) => { - selectedItem.value = getSelectedPath(refString, `${baseUrl}/src${refString}/${path}`); - window.history.pushState(null, null, `${baseUrl}/src${refString}/${encodeURIComponent(path)}`); + window.history.pushState(null, null, encodeURI(`${baseUrl}/src${refString}/${path}`)); + selectedItem.value = path; loadContent(el); }}); fileTreeView.mount(fileTree); @@ -94,7 +94,7 @@ export function initViewFileTreeSidebar() { }); } -function getSelectedPath(ref: string, url?: string) { - const path = url ?? (new URL(window.location.href).pathname); +function getSelectedPath(ref: string) { + const path = decodeURI(new URL(window.location.href).pathname); return path.substring(path.indexOf(ref) + ref.length + 1); } From 3bc3cd8ab5d7769aaf74400861f73b90e8f62911 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 5 Mar 2025 17:04:28 +0800 Subject: [PATCH 69/77] no window var --- web_src/js/features/repo-view-file-tree-sidebar.ts | 5 +++-- web_src/js/globals.d.ts | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index ea14355c60475..98ebfee24f446 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -57,6 +57,7 @@ function reloadContentScript(sidebarEl: HTMLElement, contentEl: Element) { } export function initViewFileTreeSidebar() { + let popstateListenerForViewFilePageAdded = false; registerGlobalInitFunc('initViewFileTreeSidebar', async (el: HTMLElement) => { el.querySelector('.hide-tree-sidebar-button').addEventListener('click', () => { toggleSidebar(el, false); @@ -84,12 +85,12 @@ export function initViewFileTreeSidebar() { }}); fileTreeView.mount(fileTree); - if (!window.popstateListenerForViewFilePageAdded) { + if (!popstateListenerForViewFilePageAdded) { window.addEventListener('popstate', () => { selectedItem.value = getSelectedPath(refString); loadContent(el); }); - window.popstateListenerForViewFilePageAdded = true; + popstateListenerForViewFilePageAdded = true; } }); } diff --git a/web_src/js/globals.d.ts b/web_src/js/globals.d.ts index e1ccde79380ed..0c540ac296fc7 100644 --- a/web_src/js/globals.d.ts +++ b/web_src/js/globals.d.ts @@ -74,6 +74,5 @@ interface Window { turnstile: any, hcaptcha: any, codeEditors: any[], - popstateListenerForViewFilePageAdded: boolean, updateCloneStates: () => void, } From b9eef420e4a1d2e36e9279131706f3b0ef38e5e0 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Thu, 6 Mar 2025 17:41:41 +0800 Subject: [PATCH 70/77] fix --- templates/repo/home_content.tmpl | 2 +- templates/repo/view_file_tree_sidebar.tmpl | 17 +++++++------- web_src/css/repo/home.css | 23 ------------------- .../features/repo-view-file-tree-sidebar.ts | 2 ++ 4 files changed, 11 insertions(+), 33 deletions(-) diff --git a/templates/repo/home_content.tmpl b/templates/repo/home_content.tmpl index 291ceb50cdca7..e2d78274668cc 100644 --- a/templates/repo/home_content.tmpl +++ b/templates/repo/home_content.tmpl @@ -6,7 +6,7 @@
{{if not $isTreePathRoot}} {{end}} {{template "repo/home_branch_dropdown" (dict "ctxData" .)}} diff --git a/templates/repo/view_file_tree_sidebar.tmpl b/templates/repo/view_file_tree_sidebar.tmpl index 48b8edfaa5235..4a5f829e5a7c2 100644 --- a/templates/repo/view_file_tree_sidebar.tmpl +++ b/templates/repo/view_file_tree_sidebar.tmpl @@ -1,13 +1,12 @@ -
- - +
+ + Files
-
+ + +
Date: Thu, 6 Mar 2025 17:56:51 +0800 Subject: [PATCH 71/77] dead code --- templates/repo/home_content.tmpl | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/repo/home_content.tmpl b/templates/repo/home_content.tmpl index e2d78274668cc..5bf3d67d0c3ff 100644 --- a/templates/repo/home_content.tmpl +++ b/templates/repo/home_content.tmpl @@ -1,5 +1,4 @@ {{$isTreePathRoot := not .TreeNames}} -{{$showSidebar := and $isTreePathRoot (not .HideRepoInfo) (not .IsBlame)}} {{template "repo/sub_menu" .}}
From 46ab64ba497ec83bd2fc1d19012f596b87cc0058 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 10 Mar 2025 02:14:59 +0000 Subject: [PATCH 72/77] Revert: [Refactor initViewFileTreeSidebar using the new registerGlobalInitFunc] --- templates/repo/home.tmpl | 2 +- .../features/repo-view-file-tree-sidebar.ts | 60 +++++++++---------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 7e16dd6549246..290e80064c574 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -19,7 +19,7 @@
{{if .TreeNames}} -
{{template "repo/view_file_tree_sidebar" .}}
+
{{template "repo/view_file_tree_sidebar" .}}
{{end}}
diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index dd1e8d6b4ada7..246a8b40ca10f 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -1,7 +1,6 @@ import {createApp, ref} from 'vue'; import {toggleElem} from '../utils/dom.ts'; import {GET, PUT} from '../modules/fetch.ts'; -import {registerGlobalInitFunc} from '../modules/observer.ts'; import ViewFileTree from '../components/ViewFileTree.vue'; async function toggleSidebar(sidebarEl: HTMLElement, visibility: boolean) { @@ -58,42 +57,39 @@ function reloadContentScript(sidebarEl: HTMLElement, contentEl: Element) { }); } -export function initViewFileTreeSidebar() { - let popstateListenerForViewFilePageAdded = false; - registerGlobalInitFunc('initViewFileTreeSidebar', async (el: HTMLElement) => { - el.querySelector('.hide-tree-sidebar-button').addEventListener('click', () => { - toggleSidebar(el, false); - }); - el.parentElement.querySelector('.repo-home-filelist .show-tree-sidebar-button').addEventListener('click', () => { - toggleSidebar(el, true); - }); +export async function initViewFileTreeSidebar() { + const sidebarEl = document.querySelector('.repo-view-file-tree-sidebar'); + if (!sidebarEl || !(sidebarEl instanceof HTMLElement)) return; - const fileTree = el.querySelector('#view-file-tree'); - const baseUrl = fileTree.getAttribute('data-api-base-url'); - const treePath = fileTree.getAttribute('data-tree-path'); - const refType = fileTree.getAttribute('data-current-ref-type'); - const refName = fileTree.getAttribute('data-current-ref-short-name'); - const refString = (refType ? (`/${refType}`) : '') + (refName ? (`/${refName}`) : ''); + sidebarEl.querySelector('.hide-tree-sidebar-button').addEventListener('click', () => { + toggleSidebar(sidebarEl, false); + }); + sidebarEl.parentElement.querySelector('.repo-home-filelist .show-tree-sidebar-button').addEventListener('click', () => { + toggleSidebar(sidebarEl, true); + }); - const selectedItem = ref(getSelectedPath(refString)); + const fileTree = sidebarEl.querySelector('#view-file-tree'); + const baseUrl = fileTree.getAttribute('data-api-base-url'); + const treePath = fileTree.getAttribute('data-tree-path'); + const refType = fileTree.getAttribute('data-current-ref-type'); + const refName = fileTree.getAttribute('data-current-ref-short-name'); + const refString = (refType ? (`/${refType}`) : '') + (refName ? (`/${refName}`) : ''); - const files = await childrenLoader(el)(treePath, true); + const selectedItem = ref(getSelectedPath(refString)); - fileTree.classList.remove('is-loading'); - const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren: childrenLoader(el), loadContent: (path: string) => { - window.history.pushState(null, null, encodeURI(`${baseUrl}/src${refString}/${path}`)); - selectedItem.value = path; - loadContent(el); - }}); - fileTreeView.mount(fileTree); + const files = await childrenLoader(sidebarEl)(treePath, true); - if (!popstateListenerForViewFilePageAdded) { - window.addEventListener('popstate', () => { - selectedItem.value = getSelectedPath(refString); - loadContent(el); - }); - popstateListenerForViewFilePageAdded = true; - } + fileTree.classList.remove('is-loading'); + const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren: childrenLoader(sidebarEl), loadContent: (path: string) => { + window.history.pushState(null, null, encodeURI(`${baseUrl}/src${refString}/${path}`)); + selectedItem.value = path; + loadContent(sidebarEl); + }}); + fileTreeView.mount(fileTree); + + window.addEventListener('popstate', () => { + selectedItem.value = getSelectedPath(refString); + loadContent(sidebarEl); }); } From 1211fcf75d133f86556360c8aa4989e1c12b9373 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 10 Mar 2025 02:40:45 +0000 Subject: [PATCH 73/77] fix --- web_src/js/features/repo-view-file-tree-sidebar.ts | 7 ++++--- web_src/js/utils/url.ts | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index 246a8b40ca10f..f135b547a57b4 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -1,5 +1,6 @@ import {createApp, ref} from 'vue'; import {toggleElem} from '../utils/dom.ts'; +import {pathEscapeSegments, pathUnescapeSegments} from '../utils/url.ts'; import {GET, PUT} from '../modules/fetch.ts'; import ViewFileTree from '../components/ViewFileTree.vue'; @@ -28,7 +29,7 @@ function childrenLoader(sidebarEl: HTMLElement) { const fileTree = sidebarEl.querySelector('#view-file-tree'); const apiBaseUrl = fileTree.getAttribute('data-api-base-url'); const refTypeNameSubURL = fileTree.getAttribute('data-current-ref-type-name-sub-url'); - const response = await GET(encodeURI(`${apiBaseUrl}/tree/${refTypeNameSubURL}/${path ?? ''}?recursive=${recursive ?? false}`)); + const response = await GET(`${apiBaseUrl}/tree/${refTypeNameSubURL}/${pathEscapeSegments(path ?? '')}?recursive=${recursive ?? false}`); const json = await response.json(); if (json instanceof Array) { return json.map((i) => ({ @@ -81,7 +82,7 @@ export async function initViewFileTreeSidebar() { fileTree.classList.remove('is-loading'); const fileTreeView = createApp(ViewFileTree, {files, selectedItem, loadChildren: childrenLoader(sidebarEl), loadContent: (path: string) => { - window.history.pushState(null, null, encodeURI(`${baseUrl}/src${refString}/${path}`)); + window.history.pushState(null, null, `${baseUrl}/src${refString}/${pathEscapeSegments(path)}`); selectedItem.value = path; loadContent(sidebarEl); }}); @@ -94,6 +95,6 @@ export async function initViewFileTreeSidebar() { } function getSelectedPath(ref: string) { - const path = decodeURI(new URL(window.location.href).pathname); + const path = pathUnescapeSegments(new URL(window.location.href).pathname); return path.substring(path.indexOf(ref) + ref.length + 1); } diff --git a/web_src/js/utils/url.ts b/web_src/js/utils/url.ts index a7d61c5e837b7..98f51d6adc9da 100644 --- a/web_src/js/utils/url.ts +++ b/web_src/js/utils/url.ts @@ -2,6 +2,10 @@ export function pathEscapeSegments(s: string): string { return s.split('/').map(encodeURIComponent).join('/'); } +export function pathUnescapeSegments(s: string): string { + return s.split('/').map(decodeURIComponent).join('/'); +} + function stripSlash(url: string): string { return url.endsWith('/') ? url.slice(0, -1) : url; } From ce6afd3debe1ac52d8b810dd5329cb9967b57bd6 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 10 Mar 2025 02:43:40 +0000 Subject: [PATCH 74/77] fix --- web_src/js/features/repo-view-file-tree-sidebar.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index f135b547a57b4..7957266727591 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -4,13 +4,13 @@ import {pathEscapeSegments, pathUnescapeSegments} from '../utils/url.ts'; import {GET, PUT} from '../modules/fetch.ts'; import ViewFileTree from '../components/ViewFileTree.vue'; -async function toggleSidebar(sidebarEl: HTMLElement, visibility: boolean) { +async function toggleSidebar(sidebarEl: HTMLElement, shouldShow: boolean) { const showBtnEl = sidebarEl.parentElement.querySelector('.show-tree-sidebar-button'); const containerClassList = sidebarEl.parentElement.classList; - containerClassList.toggle('repo-grid-tree-sidebar', visibility); - containerClassList.toggle('repo-grid-filelist-only', !visibility); - toggleElem(sidebarEl, visibility); - toggleElem(showBtnEl, !visibility); + containerClassList.toggle('repo-grid-tree-sidebar', shouldShow); + containerClassList.toggle('repo-grid-filelist-only', !shouldShow); + toggleElem(sidebarEl, shouldShow); + toggleElem(showBtnEl, !shouldShow); // FIXME: need to remove "full height" style from parent element @@ -19,7 +19,7 @@ async function toggleSidebar(sidebarEl: HTMLElement, visibility: boolean) { // save to session await PUT('/repo/preferences', { data: { - show_file_view_tree_sidebar: visibility, + show_file_view_tree_sidebar: shouldShow, }, }); } From 94033723f1bef0668e51e5f4169acbdecb5e9ccf Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 10 Mar 2025 06:34:17 +0000 Subject: [PATCH 75/77] fix --- web_src/js/features/repo-view-file-tree-sidebar.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index 7957266727591..bfa4bfc326975 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -4,6 +4,8 @@ import {pathEscapeSegments, pathUnescapeSegments} from '../utils/url.ts'; import {GET, PUT} from '../modules/fetch.ts'; import ViewFileTree from '../components/ViewFileTree.vue'; +const {appSubUrl} = window.config; + async function toggleSidebar(sidebarEl: HTMLElement, shouldShow: boolean) { const showBtnEl = sidebarEl.parentElement.querySelector('.show-tree-sidebar-button'); const containerClassList = sidebarEl.parentElement.classList; @@ -17,7 +19,7 @@ async function toggleSidebar(sidebarEl: HTMLElement, shouldShow: boolean) { if (!sidebarEl.hasAttribute('data-is-signed')) return; // save to session - await PUT('/repo/preferences', { + await PUT(`${appSubUrl}/repo/preferences`, { data: { show_file_view_tree_sidebar: shouldShow, }, From 3b41bea9a29bb195f9fdb03ad55b317a6ee45e67 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 10 Mar 2025 07:11:12 +0000 Subject: [PATCH 76/77] Split the original repo/home.tmpl into two templates: home and view. --- routers/web/repo/blame.go | 4 +-- routers/web/repo/view.go | 3 ++- routers/web/repo/view_home.go | 4 ++- templates/repo/home.tmpl | 8 ++---- templates/repo/view.tmpl | 27 +++++++++++++++++++ .../{home_content.tmpl => view_content.tmpl} | 0 web_src/css/repo/home.css | 20 ++++++++++---- .../features/repo-view-file-tree-sidebar.ts | 8 +++--- 8 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 templates/repo/view.tmpl rename templates/repo/{home_content.tmpl => view_content.tmpl} (100%) diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index 1c67a4002067c..1d872ba7c6a1b 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -95,9 +95,9 @@ func RefBlame(ctx *context.Context) { var tplName templates.TplName if ctx.FormBool("only_content") { - tplName = tplRepoHomeContent + tplName = tplRepoViewContent } else { - tplName = tplRepoHome + tplName = tplRepoView } if fileSize >= setting.UI.MaxDisplayFileSize { diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 4d172c9c2046f..6ed5801d10fa7 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -49,7 +49,8 @@ import ( const ( tplRepoEMPTY templates.TplName = "repo/empty" tplRepoHome templates.TplName = "repo/home" - tplRepoHomeContent templates.TplName = "repo/home_content" + tplRepoView templates.TplName = "repo/view" + tplRepoViewContent templates.TplName = "repo/view_content" tplRepoViewList templates.TplName = "repo/view_list" tplWatchers templates.TplName = "repo/watchers" tplForks templates.TplName = "repo/forks" diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go index e8dba14a64761..ba52a871389d3 100644 --- a/routers/web/repo/view_home.go +++ b/routers/web/repo/view_home.go @@ -430,7 +430,9 @@ func Home(ctx *context.Context) { } if ctx.FormBool("only_content") { - ctx.HTML(http.StatusOK, tplRepoHomeContent) + ctx.HTML(http.StatusOK, tplRepoViewContent) + } else if len(treeNames) != 0 { + ctx.HTML(http.StatusOK, tplRepoView) } else { ctx.HTML(http.StatusOK, tplRepoHome) } diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 290e80064c574..f86b90502df28 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -17,13 +17,9 @@ {{template "repo/code/recently_pushed_new_branches" .}} -
- {{if .TreeNames}} -
{{template "repo/view_file_tree_sidebar" .}}
- {{end}} - +
- {{template "repo/home_content" .}} + {{template "repo/view_content" .}}
{{if $showSidebar}} diff --git a/templates/repo/view.tmpl b/templates/repo/view.tmpl new file mode 100644 index 0000000000000..f28dd30f54aaf --- /dev/null +++ b/templates/repo/view.tmpl @@ -0,0 +1,27 @@ +{{template "base/head" .}} +
+ {{template "repo/header" .}} +
+ {{template "base/alert" .}} + + {{if .Repository.IsArchived}} +
+ {{if .Repository.ArchivedUnix.IsZero}} + {{ctx.Locale.Tr "repo.archive.title"}} + {{else}} + {{ctx.Locale.Tr "repo.archive.title_date" (DateUtils.AbsoluteLong .Repository.ArchivedUnix)}} + {{end}} +
+ {{end}} + + {{template "repo/code/recently_pushed_new_branches" .}} + +
+
{{template "repo/view_file_tree_sidebar" .}}
+
+ {{template "repo/view_content" .}} +
+
+
+
+{{template "base/footer" .}} diff --git a/templates/repo/home_content.tmpl b/templates/repo/view_content.tmpl similarity index 100% rename from templates/repo/home_content.tmpl rename to templates/repo/view_content.tmpl diff --git a/web_src/css/repo/home.css b/web_src/css/repo/home.css index 11fc7a263c399..f81dba8b81d34 100644 --- a/web_src/css/repo/home.css +++ b/web_src/css/repo/home.css @@ -49,13 +49,19 @@ } } -.repo-grid-tree-sidebar { +.repo-view-with-sidebar { display: grid; grid-template-columns: 300px auto; grid-template-rows: auto auto 1fr; } -.repo-grid-tree-sidebar .repo-home-filelist { +.repo-view-content { + min-width: 0; + grid-column: 1; + grid-row: 1 / 4; +} + +.repo-view-with-sidebar .repo-view-content { min-width: 0; grid-column: 2; grid-row: 1 / 4; @@ -66,7 +72,7 @@ aspect-ratio: 5.415; /* the size is about 790 x 145 */ } -.repo-grid-tree-sidebar .repo-view-file-tree-sidebar { +.repo-view-with-sidebar .repo-view-file-tree-sidebar { display: flex; flex-direction: column; gap: 8px; @@ -77,15 +83,19 @@ z-index: 8; } -.repo-grid-tree-sidebar .repo-button-row { +.repo-view-with-sidebar .repo-button-row { margin-top: 0 !important; } @media (max-width: 767.98px) { - .repo-grid-tree-sidebar { + .repo-view-with-sidebar { grid-template-columns: auto; grid-template-rows: auto auto auto; } + .repo-view-content { + grid-column: 1; + grid-row: 2; + } } .language-stats { diff --git a/web_src/js/features/repo-view-file-tree-sidebar.ts b/web_src/js/features/repo-view-file-tree-sidebar.ts index bfa4bfc326975..7c1bb4a316aab 100644 --- a/web_src/js/features/repo-view-file-tree-sidebar.ts +++ b/web_src/js/features/repo-view-file-tree-sidebar.ts @@ -9,8 +9,8 @@ const {appSubUrl} = window.config; async function toggleSidebar(sidebarEl: HTMLElement, shouldShow: boolean) { const showBtnEl = sidebarEl.parentElement.querySelector('.show-tree-sidebar-button'); const containerClassList = sidebarEl.parentElement.classList; - containerClassList.toggle('repo-grid-tree-sidebar', shouldShow); - containerClassList.toggle('repo-grid-filelist-only', !shouldShow); + containerClassList.toggle('repo-view-with-sidebar', shouldShow); + containerClassList.toggle('repo-view-content-only', !shouldShow); toggleElem(sidebarEl, shouldShow); toggleElem(showBtnEl, !shouldShow); @@ -49,7 +49,7 @@ function childrenLoader(sidebarEl: HTMLElement) { async function loadContent(sidebarEl: HTMLElement) { // load content by path (content based on home_content.tmpl) const response = await GET(`${window.location.href}?only_content=true`); - const contentEl = sidebarEl.parentElement.querySelector('.repo-home-filelist'); + const contentEl = sidebarEl.parentElement.querySelector('.repo-view-content'); contentEl.innerHTML = await response.text(); reloadContentScript(sidebarEl, contentEl); } @@ -67,7 +67,7 @@ export async function initViewFileTreeSidebar() { sidebarEl.querySelector('.hide-tree-sidebar-button').addEventListener('click', () => { toggleSidebar(sidebarEl, false); }); - sidebarEl.parentElement.querySelector('.repo-home-filelist .show-tree-sidebar-button').addEventListener('click', () => { + sidebarEl.parentElement.querySelector('.repo-view-content .show-tree-sidebar-button').addEventListener('click', () => { toggleSidebar(sidebarEl, true); }); From e7613605552b499dc2ed2a0476a54038cdffa5c5 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Mon, 10 Mar 2025 07:34:15 +0000 Subject: [PATCH 77/77] Change the layout of the view page from CSS Grid to Flexbox --- templates/repo/view.tmpl | 2 +- web_src/css/repo/home.css | 28 +++++++++------------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/templates/repo/view.tmpl b/templates/repo/view.tmpl index f28dd30f54aaf..6073b91914aef 100644 --- a/templates/repo/view.tmpl +++ b/templates/repo/view.tmpl @@ -16,7 +16,7 @@ {{template "repo/code/recently_pushed_new_branches" .}} -
+
{{template "repo/view_file_tree_sidebar" .}}
{{template "repo/view_content" .}} diff --git a/web_src/css/repo/home.css b/web_src/css/repo/home.css index f81dba8b81d34..222a5082f72a2 100644 --- a/web_src/css/repo/home.css +++ b/web_src/css/repo/home.css @@ -49,23 +49,14 @@ } } -.repo-view-with-sidebar { - display: grid; - grid-template-columns: 300px auto; - grid-template-rows: auto auto 1fr; +.repo-view-container { + display: flex; + flex-wrap: wrap; + gap: var(--page-spacing); } .repo-view-content { - min-width: 0; - grid-column: 1; - grid-row: 1 / 4; -} - -.repo-view-with-sidebar .repo-view-content { - min-width: 0; - grid-column: 2; - grid-row: 1 / 4; - margin-left: 1rem; + flex: 1; } #view-file-tree.is-loading { @@ -73,6 +64,7 @@ } .repo-view-with-sidebar .repo-view-file-tree-sidebar { + flex: 0 1 15%; display: flex; flex-direction: column; gap: 8px; @@ -83,18 +75,16 @@ z-index: 8; } -.repo-view-with-sidebar .repo-button-row { +.repo-view-container .repo-button-row { margin-top: 0 !important; } @media (max-width: 767.98px) { .repo-view-with-sidebar { - grid-template-columns: auto; - grid-template-rows: auto auto auto; + flex: 1 1 0; } .repo-view-content { - grid-column: 1; - grid-row: 2; + flex: 1 1 0; } }