diff --git a/models/unit/unit.go b/models/unit/unit.go index b216712d37..e37adf995e 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 b48f6ded26..727c18cad6 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 be2a06b38f..9c8b3fc541 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 ef3e40eea8..681cba9ef4 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"}}