Compare commits

..

No commits in common. "e35f8e15a67e8268542d2442dac32993b6944043" and "c2774d9e80d9a436d9c2044960369c4db227e3a0" have entirely different histories.

19 changed files with 71 additions and 149 deletions

View File

@ -578,16 +578,12 @@ func runCreateUser(c *cli.Context) error {
restricted = util.OptionalBoolOf(c.Bool("restricted")) restricted = util.OptionalBoolOf(c.Bool("restricted"))
} }
// default user visibility in app.ini
visibility := setting.Service.DefaultUserVisibilityMode
u := &user_model.User{ u := &user_model.User{
Name: username, Name: username,
Email: c.String("email"), Email: c.String("email"),
Passwd: password, Passwd: password,
IsAdmin: c.Bool("admin"), IsAdmin: c.Bool("admin"),
MustChangePassword: changePassword, MustChangePassword: changePassword,
Visibility: visibility,
} }
overwriteDefault := &user_model.CreateUserOverwriteOptions{ overwriteDefault := &user_model.CreateUserOverwriteOptions{

View File

@ -927,18 +927,14 @@ ROUTER = console
;USE_COMPAT_SSH_URI = false ;USE_COMPAT_SSH_URI = false
;; ;;
;; Close issues as long as a commit on any branch marks it as fixed ;; Close issues as long as a commit on any branch marks it as fixed
;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages ;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects
;DISABLED_REPO_UNITS = ;DISABLED_REPO_UNITS =
;; ;;
;; Comma separated list of default new repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects, repo.packages. ;; Comma separated list of default repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects.
;; Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility. ;; Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility.
;; External wiki and issue tracker can't be enabled by default as it requires additional settings. ;; External wiki and issue tracker can't be enabled by default as it requires additional settings.
;; Disabled repo units will not be added to new repositories regardless if it is in the default list. ;; Disabled repo units will not be added to new repositories regardless if it is in the default list.
;DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages ;DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects
;;
;; Comma separated list of default forked repo units.
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
;DEFAULT_FORK_REPO_UNITS = repo.code,repo.pulls
;; ;;
;; Prefix archive files by placing them in a directory named after the repository ;; Prefix archive files by placing them in a directory named after the repository
;PREFIX_ARCHIVE_FILES = true ;PREFIX_ARCHIVE_FILES = true
@ -1222,6 +1218,10 @@ ROUTER = console
;; ;;
;; Whether to enable a Service Worker to cache frontend assets ;; Whether to enable a Service Worker to cache frontend assets
;USE_SERVICE_WORKER = false ;USE_SERVICE_WORKER = false
;;
;; Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
;; A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
;ONLY_SHOW_RELEVANT_REPOS = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -104,8 +104,7 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build
- `ENABLE_PUSH_CREATE_USER`: **false**: Allow users to push local repositories to Gitea and have them automatically created for a user. - `ENABLE_PUSH_CREATE_USER`: **false**: Allow users to push local repositories to Gitea and have them automatically created for a user.
- `ENABLE_PUSH_CREATE_ORG`: **false**: Allow users to push local repositories to Gitea and have them automatically created for an org. - `ENABLE_PUSH_CREATE_ORG`: **false**: Allow users to push local repositories to Gitea and have them automatically created for an org.
- `DISABLED_REPO_UNITS`: **_empty_**: Comma separated list of globally disabled repo units. Allowed values: \[repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects\] - `DISABLED_REPO_UNITS`: **_empty_**: Comma separated list of globally disabled repo units. Allowed values: \[repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects\]
- `DEFAULT_REPO_UNITS`: **repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages**: Comma separated list of default new repo units. Allowed values: \[repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects\]. Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility. External wiki and issue tracker can't be enabled by default as it requires additional settings. Disabled repo units will not be added to new repositories regardless if it is in the default list. - `DEFAULT_REPO_UNITS`: **repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects**: Comma separated list of default repo units. Allowed values: \[repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects\]. Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility. External wiki and issue tracker can't be enabled by default as it requires additional settings. Disabled repo units will not be added to new repositories regardless if it is in the default list.
- `DEFAULT_FORK_REPO_UNITS`: **repo.code,repo.pulls**: Comma separated list of default forked repo units. The set of allowed values and rules is the same as `DEFAULT_REPO_UNITS`.
- `PREFIX_ARCHIVE_FILES`: **true**: Prefix archive files by placing them in a directory named after the repository. - `PREFIX_ARCHIVE_FILES`: **true**: Prefix archive files by placing them in a directory named after the repository.
- `DISABLE_MIGRATIONS`: **false**: Disable migrating feature. - `DISABLE_MIGRATIONS`: **false**: Disable migrating feature.
- `DISABLE_STARS`: **false**: Disable stars feature. - `DISABLE_STARS`: **false**: Disable stars feature.
@ -231,6 +230,8 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used. - `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
- `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page. - `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page.
- `USE_SERVICE_WORKER`: **false**: Whether to enable a Service Worker to cache frontend assets. - `USE_SERVICE_WORKER`: **false**: Whether to enable a Service Worker to cache frontend assets.
- `ONLY_SHOW_RELEVANT_REPOS`: **false** Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
### UI - Admin (`ui.admin`) ### UI - Admin (`ui.admin`)

View File

@ -27,9 +27,3 @@ const (
SearchOrderByForks SearchOrderBy = "num_forks ASC" SearchOrderByForks SearchOrderBy = "num_forks ASC"
SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
) )
const (
// Which means a condition to filter the records which don't match any id.
// It's different from zero which means the condition could be ignored.
NoneID = -1
)

View File

@ -1251,8 +1251,6 @@ func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) {
if opts.ProjectID > 0 { if opts.ProjectID > 0 {
sess.Join("INNER", "project_issue", "issue.id = project_issue.issue_id"). sess.Join("INNER", "project_issue", "issue.id = project_issue.issue_id").
And("project_issue.project_id=?", opts.ProjectID) And("project_issue.project_id=?", opts.ProjectID)
} else if opts.ProjectID == db.NoneID { // show those that are in no project
sess.And(builder.NotIn("issue.id", builder.Select("issue_id").From("project_issue")))
} }
if opts.ProjectBoardID != 0 { if opts.ProjectBoardID != 0 {

View File

@ -494,7 +494,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
} }
if opts.OnlyShowRelevant { if opts.OnlyShowRelevant {
// Only show a repo that has at least a topic, an icon, or a description // Only show a repo that either has a topic or description.
subQueryCond := builder.NewCond() subQueryCond := builder.NewCond()
// Topic checking. Topics are present. // Topic checking. Topics are present.
@ -504,13 +504,13 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
subQueryCond = subQueryCond.Or(builder.And(builder.Neq{"topics": "null"}, builder.Neq{"topics": "[]"})) subQueryCond = subQueryCond.Or(builder.And(builder.Neq{"topics": "null"}, builder.Neq{"topics": "[]"}))
} }
// Description checking. Description not empty // Description checking. Description not empty.
subQueryCond = subQueryCond.Or(builder.Neq{"description": ""}) subQueryCond = subQueryCond.Or(builder.Neq{"description": ""})
// Repo has a avatar // Repo has a avatar.
subQueryCond = subQueryCond.Or(builder.Neq{"avatar": ""}) subQueryCond = subQueryCond.Or(builder.Neq{"avatar": ""})
// Always hide repo's that are empty // Always hide repo's that are empty.
subQueryCond = subQueryCond.And(builder.Eq{"is_empty": false}) subQueryCond = subQueryCond.And(builder.Eq{"is_empty": false})
cond = cond.And(subQueryCond) cond = cond.And(subQueryCond)

View File

@ -94,12 +94,6 @@ var (
TypePackages, TypePackages,
} }
// ForkRepoUnits contains the default unit types for forks
DefaultForkRepoUnits = []Type{
TypeCode,
TypePullRequests,
}
// NotAllowedDefaultRepoUnits contains units that can't be default // NotAllowedDefaultRepoUnits contains units that can't be default
NotAllowedDefaultRepoUnits = []Type{ NotAllowedDefaultRepoUnits = []Type{
TypeExternalWiki, TypeExternalWiki,
@ -116,41 +110,26 @@ var (
DisabledRepoUnits = []Type{} DisabledRepoUnits = []Type{}
) )
// Get valid set of default repository units from settings // LoadUnitConfig load units from settings
func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type { func LoadUnitConfig() {
units := defaultUnits setDefaultRepoUnits := FindUnitTypes(setting.Repository.DefaultRepoUnits...)
// Default repo units set if setting is not empty
// Use setting if not empty if len(setDefaultRepoUnits) > 0 {
if len(settingDefaultUnits) > 0 {
// MustRepoUnits required as default // MustRepoUnits required as default
units = make([]Type, len(MustRepoUnits)) DefaultRepoUnits = make([]Type, len(MustRepoUnits))
copy(units, MustRepoUnits) copy(DefaultRepoUnits, MustRepoUnits)
for _, settingUnit := range settingDefaultUnits { for _, defaultU := range setDefaultRepoUnits {
if !settingUnit.CanBeDefault() { if !defaultU.CanBeDefault() {
log.Warn("Not allowed as default unit: %s", settingUnit.String()) log.Warn("Not allowed as default unit: %s", defaultU.String())
continue continue
} }
// MustRepoUnits already added // MustRepoUnits already added
if settingUnit.CanDisable() { if defaultU.CanDisable() {
units = append(units, settingUnit) DefaultRepoUnits = append(DefaultRepoUnits, defaultU)
} }
} }
} }
// Remove disabled units
for _, disabledUnit := range DisabledRepoUnits {
for i, unit := range units {
if unit == disabledUnit {
units = append(units[:i], units[i+1:]...)
}
}
}
return units
}
// LoadUnitConfig load units from settings
func LoadUnitConfig() {
DisabledRepoUnits = FindUnitTypes(setting.Repository.DisabledRepoUnits...) DisabledRepoUnits = FindUnitTypes(setting.Repository.DisabledRepoUnits...)
// Check that must units are not disabled // Check that must units are not disabled
for i, disabledU := range DisabledRepoUnits { for i, disabledU := range DisabledRepoUnits {
@ -159,11 +138,14 @@ func LoadUnitConfig() {
DisabledRepoUnits = append(DisabledRepoUnits[:i], DisabledRepoUnits[i+1:]...) DisabledRepoUnits = append(DisabledRepoUnits[:i], DisabledRepoUnits[i+1:]...)
} }
} }
// Remove disabled units from default units
setDefaultRepoUnits := FindUnitTypes(setting.Repository.DefaultRepoUnits...) for _, disabledU := range DisabledRepoUnits {
DefaultRepoUnits = validateDefaultRepoUnits(DefaultRepoUnits, setDefaultRepoUnits) for i, defaultU := range DefaultRepoUnits {
setDefaultForkRepoUnits := FindUnitTypes(setting.Repository.DefaultForkRepoUnits...) if defaultU == disabledU {
DefaultForkRepoUnits = validateDefaultRepoUnits(DefaultForkRepoUnits, setDefaultForkRepoUnits) DefaultRepoUnits = append(DefaultRepoUnits[:i], DefaultRepoUnits[i+1:]...)
}
}
}
} }
// UnitGlobalDisabled checks if unit type is global disabled // UnitGlobalDisabled checks if unit type is global disabled

View File

@ -30,7 +30,7 @@ import (
) )
// CreateRepositoryByExample creates a repository for the user/organization. // CreateRepositoryByExample creates a repository for the user/organization.
func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository, overwriteOrAdopt, isFork bool) (err error) { func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository, overwriteOrAdopt bool) (err error) {
if err = repo_model.IsUsableRepoName(repo.Name); err != nil { if err = repo_model.IsUsableRepoName(repo.Name); err != nil {
return err return err
} }
@ -67,12 +67,8 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re
} }
// insert units for repo // insert units for repo
defaultUnits := unit.DefaultRepoUnits units := make([]repo_model.RepoUnit, 0, len(unit.DefaultRepoUnits))
if isFork { for _, tp := range unit.DefaultRepoUnits {
defaultUnits = unit.DefaultForkRepoUnits
}
units := make([]repo_model.RepoUnit, 0, len(defaultUnits))
for _, tp := range defaultUnits {
if tp == unit.TypeIssues { if tp == unit.TypeIssues {
units = append(units, repo_model.RepoUnit{ units = append(units, repo_model.RepoUnit{
RepoID: repo.ID, RepoID: repo.ID,
@ -216,7 +212,7 @@ func CreateRepository(doer, u *user_model.User, opts CreateRepoOptions) (*repo_m
var rollbackRepo *repo_model.Repository var rollbackRepo *repo_model.Repository
if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error {
if err := CreateRepositoryByExample(ctx, doer, u, repo, false, false); err != nil { if err := CreateRepositoryByExample(ctx, doer, u, repo, false); err != nil {
return err return err
} }

View File

@ -319,7 +319,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
TrustModel: templateRepo.TrustModel, TrustModel: templateRepo.TrustModel,
} }
if err = CreateRepositoryByExample(ctx, doer, owner, generateRepo, false, false); err != nil { if err = CreateRepositoryByExample(ctx, doer, owner, generateRepo, false); err != nil {
return nil, err return nil, err
} }

View File

@ -41,7 +41,6 @@ var (
EnablePushCreateOrg bool EnablePushCreateOrg bool
DisabledRepoUnits []string DisabledRepoUnits []string
DefaultRepoUnits []string DefaultRepoUnits []string
DefaultForkRepoUnits []string
PrefixArchiveFiles bool PrefixArchiveFiles bool
DisableMigrations bool DisableMigrations bool
DisableStars bool `ini:"DISABLE_STARS"` DisableStars bool `ini:"DISABLE_STARS"`
@ -158,7 +157,6 @@ var (
EnablePushCreateOrg: false, EnablePushCreateOrg: false,
DisabledRepoUnits: []string{}, DisabledRepoUnits: []string{},
DefaultRepoUnits: []string{}, DefaultRepoUnits: []string{},
DefaultForkRepoUnits: []string{},
PrefixArchiveFiles: true, PrefixArchiveFiles: true,
DisableMigrations: false, DisableMigrations: false,
DisableStars: false, DisableStars: false,

View File

@ -241,6 +241,7 @@ var (
CustomEmojisMap map[string]string `ini:"-"` CustomEmojisMap map[string]string `ini:"-"`
SearchRepoDescription bool SearchRepoDescription bool
UseServiceWorker bool UseServiceWorker bool
OnlyShowRelevantRepos bool
Notification struct { Notification struct {
MinTimeout time.Duration MinTimeout time.Duration
@ -1122,6 +1123,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
UI.DefaultShowFullName = Cfg.Section("ui").Key("DEFAULT_SHOW_FULL_NAME").MustBool(false) UI.DefaultShowFullName = Cfg.Section("ui").Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
UI.SearchRepoDescription = Cfg.Section("ui").Key("SEARCH_REPO_DESCRIPTION").MustBool(true) UI.SearchRepoDescription = Cfg.Section("ui").Key("SEARCH_REPO_DESCRIPTION").MustBool(true)
UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(false) UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(false)
UI.OnlyShowRelevantRepos = Cfg.Section("ui").Key("ONLY_SHOW_RELEVANT_REPOS").MustBool(false)
HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt")) HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt"))
if err != nil { if err != nil {

View File

@ -1306,8 +1306,7 @@ issues.filter_label_no_select = All labels
issues.filter_milestone = Milestone issues.filter_milestone = Milestone
issues.filter_milestone_no_select = All milestones issues.filter_milestone_no_select = All milestones
issues.filter_project = Project issues.filter_project = Project
issues.filter_project_all = All projects issues.filter_project_no_select = All projects
issues.filter_project_none = No project
issues.filter_assignee = Assignee issues.filter_assignee = Assignee
issues.filter_assginee_no_select = All assignees issues.filter_assginee_no_select = All assignees
issues.filter_poster = Author issues.filter_poster = Author

View File

@ -17,8 +17,7 @@ import (
const ( const (
// tplExploreRepos explore repositories page template // tplExploreRepos explore repositories page template
tplExploreRepos base.TplName = "explore/repos" tplExploreRepos base.TplName = "explore/repos"
relevantReposOnlyParam string = "no_filter"
) )
// RepoSearchOptions when calling search repositories // RepoSearchOptions when calling search repositories
@ -82,11 +81,13 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
default: default:
ctx.Data["SortType"] = "recentupdate" ctx.Data["SortType"] = "recentupdate"
orderBy = db.SearchOrderByRecentUpdated orderBy = db.SearchOrderByRecentUpdated
onlyShowRelevant = setting.UI.OnlyShowRelevantRepos && !ctx.FormBool("no_filter")
} }
onlyShowRelevant = !ctx.FormBool(relevantReposOnlyParam)
keyword := ctx.FormTrim("q") keyword := ctx.FormTrim("q")
if keyword != "" {
onlyShowRelevant = false
}
ctx.Data["OnlyShowRelevant"] = onlyShowRelevant ctx.Data["OnlyShowRelevant"] = onlyShowRelevant
@ -138,7 +139,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
pager.SetDefaultParams(ctx) pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "topic", "TopicOnly") pager.AddParam(ctx, "topic", "TopicOnly")
pager.AddParam(ctx, "language", "Language") pager.AddParam(ctx, "language", "Language")
pager.AddParamString(relevantReposOnlyParam, ctx.FormString(relevantReposOnlyParam)) pager.AddParamString("no_filter", ctx.FormString("no_filter"))
ctx.Data["Page"] = pager ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, opts.TplName) ctx.HTML(http.StatusOK, opts.TplName)

View File

@ -363,10 +363,16 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
return 0 return 0
} }
retrieveProjects(ctx, repo) projects, _, err := project_model.FindProjects(ctx, project_model.SearchOptions{
if ctx.Written() { RepoID: repo.ID,
Type: project_model.TypeRepository,
IsClosed: util.OptionalBoolOf(isShowClosed),
})
if err != nil {
ctx.ServerError("FindProjects", err)
return return
} }
ctx.Data["Projects"] = projects
ctx.Data["IssueStats"] = issueStats ctx.Data["IssueStats"] = issueStats
ctx.Data["SelLabelIDs"] = labelIDs ctx.Data["SelLabelIDs"] = labelIDs

View File

@ -67,7 +67,7 @@ func AdoptRepository(doer, u *user_model.User, opts repo_module.CreateRepoOption
} }
} }
if err := repo_module.CreateRepositoryByExample(ctx, doer, u, repo, true, false); err != nil { if err := repo_module.CreateRepositoryByExample(ctx, doer, u, repo, true); err != nil {
return err return err
} }
if err := adoptRepository(ctx, repoPath, doer, repo, opts); err != nil { if err := adoptRepository(ctx, repoPath, doer, repo, opts); err != nil {

View File

@ -119,7 +119,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
}() }()
err = db.WithTx(ctx, func(txCtx context.Context) error { err = db.WithTx(ctx, func(txCtx context.Context) error {
if err = repo_module.CreateRepositoryByExample(txCtx, doer, owner, repo, false, true); err != nil { if err = repo_module.CreateRepositoryByExample(txCtx, doer, owner, repo, false); err != nil {
return err return err
} }

View File

@ -75,41 +75,19 @@
</div> </div>
<!-- Project --> <!-- Project -->
<div class="ui{{if not (or .OpenProjects .ClosedProjects)}} disabled{{end}} dropdown jump item"> <div class="ui {{if not .Projects}}disabled{{end}} dropdown jump item">
<span class="text"> <span class="text">
{{.locale.Tr "repo.issues.filter_projects"}} {{.locale.Tr "repo.issues.filter_project"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span> </span>
<div class="menu"> <div class="menu">
<div class="ui icon search input"> <div class="ui icon search input">
<i class="icon df ac jc">{{svg "octicon-search" 16}}</i> <i class="icon df ac jc">{{svg "octicon-search" 16}}</i>
<input type="text" placeholder="{{.locale.Tr "repo.issues.filter_projects"}}"> <input type="text" placeholder="{{.locale.Tr "repo.issues.filter_project"}}">
</div> </div>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_project_all"}}</a> <a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_project_no_select"}}</a>
<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.SelectLabels}}&project=-1&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.locale.Tr "repo.issues.filter_project_none"}}</a> {{range .Projects}}
{{if .OpenProjects}} <a class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{.ID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">{{.Title}}</a>
<div class="divider"></div>
<div class="header">
{{.locale.Tr "repo.issues.new.open_projects"}}
</div>
{{range .OpenProjects}}
<a class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{.ID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">
{{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "mr-3"}}{{else}}{{svg "octicon-project" 18 "mr-3"}}{{end}}
{{.Title}}
</a>
{{end}}
{{end}}
{{if .ClosedProjects}}
<div class="divider"></div>
<div class="header">
{{.locale.Tr "repo.issues.new.closed_projects"}}
</div>
{{range .ClosedProjects}}
<a class="{{if $.ProjectID}}{{if eq $.ProjectID .ID}}active selected{{end}}{{end}} item" href="{{$.Link}}?type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{$.SelectLabels}}&milestone={{$.MilestoneID}}&project={{.ID}}&assignee={{$.AssigneeID}}&poster={{$.PosterID}}">
{{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "mr-3"}}{{else}}{{svg "octicon-project" 18 "mr-3"}}{{end}}
{{.Title}}
</a>
{{end}}
{{end}} {{end}}
</div> </div>
</div> </div>
@ -244,38 +222,18 @@
</div> </div>
<!-- Projects --> <!-- Projects -->
<div class="ui{{if not (or .OpenProjects .ClosedProjects)}} disabled{{end}} dropdown jump item"> <div class="ui {{if not .Projects}}disabled{{end}} dropdown jump item">
<span class="text"> <span class="text">
{{.locale.Tr "repo.project_board"}} {{.locale.Tr "repo.project_board"}}
{{svg "octicon-triangle-down" 14 "dropdown icon"}} {{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span> </span>
<div class="menu"> <div class="menu">
<div class="item issue-action" data-element-id="0" data-url="{{$.Link}}/projects"> <div class="item issue-action" data-element-id="0" data-url="{{$.Link}}/projects">
{{.locale.Tr "repo.issues.new.clear_projects"}} {{.locale.Tr "repo.issues.new.no_projects"}}
</div> </div>
{{if .OpenProjects}} {{range .Projects}}
<div class="divider"></div> <div class="item issue-action" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/projects">
<div class="header"> {{.Title}}
{{.locale.Tr "repo.issues.new.open_projects"}}
</div>
{{range .OpenProjects}}
<div class="item issue-action" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/projects">
{{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "mr-3"}}{{else}}{{svg "octicon-project" 18 "mr-3"}}{{end}}
{{.Title}}
</div>
{{end}}
{{end}}
{{if .ClosedProjects}}
<div class="divider"></div>
<div class="header">
{{.locale.Tr "repo.issues.new.closed_projects"}}
</div>
{{range .ClosedProjects}}
<div class="item issue-action" data-element-id="{{.ID}}" data-url="{{$.RepoLink}}/issues/projects">
{{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "mr-3"}}{{else}}{{svg "octicon-project" 18 "mr-3"}}{{end}}
{{.Title}}
</div>
{{end}}
</div> </div>
{{end}} {{end}}
</div> </div>

View File

@ -72,10 +72,6 @@ export function filterRepoFilesWeighted(files, filter) {
return filterResult; return filterResult;
} }
export function escapePath(s) {
return s.split('/').map(encodeURIComponent).join('/');
}
function filterRepoFiles(filter) { function filterRepoFiles(filter) {
const treeLink = $repoFindFileInput.attr('data-url-tree-link'); const treeLink = $repoFindFileInput.attr('data-url-tree-link');
$repoFindFileTableBody.empty(); $repoFindFileTableBody.empty();
@ -87,7 +83,7 @@ function filterRepoFiles(filter) {
for (const r of filterResult) { for (const r of filterResult) {
const $row = $(tmplRow); const $row = $(tmplRow);
const $a = $row.find('a'); const $a = $row.find('a');
$a.attr('href', `${treeLink}/${escapePath(r.matchResult.join(''))}`); $a.attr('href', `${treeLink}/${r.matchResult.join('')}`);
const $octiconFile = $(svg('octicon-file')).addClass('mr-3'); const $octiconFile = $(svg('octicon-file')).addClass('mr-3');
$a.append($octiconFile); $a.append($octiconFile);
// if the target file path is "abc/xyz", to search "bx", then the matchResult is ['a', 'b', 'c/', 'x', 'yz'] // if the target file path is "abc/xyz", to search "bx", then the matchResult is ['a', 'b', 'c/', 'x', 'yz']

View File

@ -1,5 +1,5 @@
import {describe, expect, test} from 'vitest'; import {describe, expect, test} from 'vitest';
import {strSubMatch, calcMatchedWeight, filterRepoFilesWeighted, escapePath} from './repo-findfile.js'; import {strSubMatch, calcMatchedWeight, filterRepoFilesWeighted} from './repo-findfile.js';
describe('Repo Find Files', () => { describe('Repo Find Files', () => {
test('strSubMatch', () => { test('strSubMatch', () => {
@ -32,9 +32,4 @@ describe('Repo Find Files', () => {
expect(res).toHaveLength(2); expect(res).toHaveLength(2);
expect(res[0].matchResult).toEqual(['', 'word', '.txt']); expect(res[0].matchResult).toEqual(['', 'word', '.txt']);
}); });
test('escapePath', () => {
expect(escapePath('a/b/c')).toEqual('a/b/c');
expect(escapePath('a/b/ c')).toEqual('a/b/%20c');
});
}); });