diff --git a/models/unit/unit.go b/models/unit/unit.go
index b216712d3..e37adf995 100644
--- a/models/unit/unit.go
+++ b/models/unit/unit.go
@@ -108,6 +108,10 @@ var (
// DisabledRepoUnits contains the units that have been globally disabled
DisabledRepoUnits = []Type{}
+
+ // AllowedRepoUnitGroups contains the units that have been globally enabled,
+ // with mutually exclusive units grouped together.
+ AllowedRepoUnitGroups = [][]Type{}
)
// Get valid set of default repository units from settings
@@ -162,6 +166,45 @@ func LoadUnitConfig() error {
if len(DefaultForkRepoUnits) == 0 {
return errors.New("no default fork repository units found")
}
+
+ // Collect the allowed repo unit groups. Mutually exclusive units are
+ // grouped together.
+ AllowedRepoUnitGroups = [][]Type{}
+ for _, unit := range []Type{
+ TypeCode,
+ TypePullRequests,
+ TypeProjects,
+ TypePackages,
+ TypeActions,
+ } {
+ // If unit is globally disabled, ignore it.
+ if unit.UnitGlobalDisabled() {
+ continue
+ }
+
+ // If it is allowed, add it to the group list.
+ AllowedRepoUnitGroups = append(AllowedRepoUnitGroups, []Type{unit})
+ }
+
+ addMutuallyExclusiveGroup := func(unit1, unit2 Type) {
+ var list []Type
+
+ if !unit1.UnitGlobalDisabled() {
+ list = append(list, unit1)
+ }
+
+ if !unit2.UnitGlobalDisabled() {
+ list = append(list, unit2)
+ }
+
+ if len(list) > 0 {
+ AllowedRepoUnitGroups = append(AllowedRepoUnitGroups, list)
+ }
+ }
+
+ addMutuallyExclusiveGroup(TypeIssues, TypeExternalTracker)
+ addMutuallyExclusiveGroup(TypeWiki, TypeExternalWiki)
+
return nil
}
diff --git a/modules/context/repo.go b/modules/context/repo.go
index b48f6ded2..727c18cad 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -81,6 +81,31 @@ func (r *Repository) CanCreateBranch() bool {
return r.Permission.CanWrite(unit_model.TypeCode) && r.Repository.CanCreateBranch()
}
+// AllUnitsEnabled returns true if all units are enabled for the repo.
+func (r *Repository) AllUnitsEnabled(ctx context.Context) bool {
+ hasAnyUnitEnabled := func(unitGroup []unit_model.Type) bool {
+ // Loop over the group of units
+ for _, unit := range unitGroup {
+ // If *any* of them is enabled, return true.
+ if r.Repository.UnitEnabled(ctx, unit) {
+ return true
+ }
+ }
+
+ // If none are enabled, return false.
+ return false
+ }
+
+ for _, unitGroup := range unit_model.AllowedRepoUnitGroups {
+ // If any disabled unit is found, return false immediately.
+ if !hasAnyUnitEnabled(unitGroup) {
+ return false
+ }
+ }
+
+ return true
+}
+
// RepoMustNotBeArchived checks if a repo is archived
func RepoMustNotBeArchived() func(ctx *Context) {
return func(ctx *Context) {
@@ -1053,6 +1078,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
ctx.Data["IsViewTag"] = ctx.Repo.IsViewTag
ctx.Data["IsViewCommit"] = ctx.Repo.IsViewCommit
ctx.Data["CanCreateBranch"] = ctx.Repo.CanCreateBranch()
+ ctx.Data["AllUnitsEnabled"] = ctx.Repo.AllUnitsEnabled(ctx)
ctx.Repo.CommitsCount, err = ctx.Repo.GetCommitsCount()
if err != nil {
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index be2a06b38..9c8b3fc54 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -2068,6 +2068,7 @@ settings.mirror_settings.push_mirror.edit_sync_time = Edit mirror sync interval
settings.units.units = Repository Units
settings.units.overview = Overview
+settings.units.add_more = Add more...
settings.sync_mirror = Synchronize Now
settings.pull_mirror_sync_in_progress = Pulling changes from the remote %s at the moment.
diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl
index ef3e40eea..681cba9ef 100644
--- a/templates/repo/header.tmpl
+++ b/templates/repo/header.tmpl
@@ -219,6 +219,11 @@
{{end}}
{{if .Permission.IsAdmin}}
+ {{if not .AllUnitsEnabled}}
+
+ {{svg "octicon-diff-added"}} {{ctx.Locale.Tr "repo.settings.units.add_more"}}
+
+ {{end}}
{{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}}