Add setting to set default and global disabled repository units. (#8788)
* Add possibility to global disable repo units. * Add Default Repo Unit app.ini setting. * Hide units * Hide disabled repo units * Minor fixes * Indicate disabled units in team settings. Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: zeripath <art27@cantab.net>
This commit is contained in:
		
							parent
							
								
									36943e56d6
								
							
						
					
					
						commit
						3c07d03c03
					
				
					 14 changed files with 315 additions and 140 deletions
				
			
		|  | @ -42,6 +42,13 @@ DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH = false | ||||||
| ; Allow users to push local repositories to Gitea and have them automatically created for a user or an org | ; Allow users to push local repositories to Gitea and have them automatically created for a user or an org | ||||||
| ENABLE_PUSH_CREATE_USER = false | ENABLE_PUSH_CREATE_USER = false | ||||||
| ENABLE_PUSH_CREATE_ORG = false | ENABLE_PUSH_CREATE_ORG = false | ||||||
|  | ; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki | ||||||
|  | DISABLED_REPO_UNITS =  | ||||||
|  | ; Comma separated list of default repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki. | ||||||
|  | ; 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 | ||||||
| 
 | 
 | ||||||
| [repository.editor] | [repository.editor] | ||||||
| ; List of file extensions for which lines should be wrapped in the CodeMirror editor | ; List of file extensions for which lines should be wrapped in the CodeMirror editor | ||||||
|  |  | ||||||
|  | @ -128,6 +128,7 @@ func loadRepoConfig() { | ||||||
| // NewRepoContext creates a new repository context
 | // NewRepoContext creates a new repository context
 | ||||||
| func NewRepoContext() { | func NewRepoContext() { | ||||||
| 	loadRepoConfig() | 	loadRepoConfig() | ||||||
|  | 	loadUnitConfig() | ||||||
| 
 | 
 | ||||||
| 	RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp")) | 	RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp")) | ||||||
| } | } | ||||||
|  | @ -393,6 +394,7 @@ func (repo *Repository) getUnits(e Engine) (err error) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	repo.Units, err = getUnitsByRepoID(e, repo.ID) | 	repo.Units, err = getUnitsByRepoID(e, repo.ID) | ||||||
|  | 	log.Trace("repo.Units: %-+v", repo.Units) | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1442,14 +1444,19 @@ func UpdateRepositoryUpdatedTime(repoID int64, updateTime time.Time) error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // UpdateRepositoryUnits updates a repository's units
 | // UpdateRepositoryUnits updates a repository's units
 | ||||||
| func UpdateRepositoryUnits(repo *Repository, units []RepoUnit) (err error) { | func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes []UnitType) (err error) { | ||||||
| 	sess := x.NewSession() | 	sess := x.NewSession() | ||||||
| 	defer sess.Close() | 	defer sess.Close() | ||||||
| 	if err = sess.Begin(); err != nil { | 	if err = sess.Begin(); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if _, err = sess.Where("repo_id = ?", repo.ID).Delete(new(RepoUnit)); err != nil { | 	// Delete existing settings of units before adding again
 | ||||||
|  | 	for _, u := range units { | ||||||
|  | 		deleteUnitTypes = append(deleteUnitTypes, u.Type) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if _, err = sess.Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(RepoUnit)); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -170,5 +170,16 @@ func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func getUnitsByRepoID(e Engine, repoID int64) (units []*RepoUnit, err error) { | func getUnitsByRepoID(e Engine, repoID int64) (units []*RepoUnit, err error) { | ||||||
| 	return units, e.Where("repo_id = ?", repoID).Find(&units) | 	var tmpUnits []*RepoUnit | ||||||
|  | 	if err := e.Where("repo_id = ?", repoID).Find(&tmpUnits); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, u := range tmpUnits { | ||||||
|  | 		if !u.Type.UnitGlobalDisabled() { | ||||||
|  | 			units = append(units, u) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return units, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ import ( | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // UnitType is Unit's Type
 | // UnitType is Unit's Type
 | ||||||
|  | @ -78,13 +79,89 @@ var ( | ||||||
| 		UnitTypeWiki, | 		UnitTypeWiki, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// NotAllowedDefaultRepoUnits contains units that can't be default
 | ||||||
|  | 	NotAllowedDefaultRepoUnits = []UnitType{ | ||||||
|  | 		UnitTypeExternalWiki, | ||||||
|  | 		UnitTypeExternalTracker, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// MustRepoUnits contains the units could not be disabled currently
 | 	// MustRepoUnits contains the units could not be disabled currently
 | ||||||
| 	MustRepoUnits = []UnitType{ | 	MustRepoUnits = []UnitType{ | ||||||
| 		UnitTypeCode, | 		UnitTypeCode, | ||||||
| 		UnitTypeReleases, | 		UnitTypeReleases, | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	// DisabledRepoUnits contains the units that have been globally disabled
 | ||||||
|  | 	DisabledRepoUnits = []UnitType{} | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | func loadUnitConfig() { | ||||||
|  | 	setDefaultRepoUnits := FindUnitTypes(setting.Repository.DefaultRepoUnits...) | ||||||
|  | 	// Default repo units set if setting is not empty
 | ||||||
|  | 	if len(setDefaultRepoUnits) > 0 { | ||||||
|  | 		// MustRepoUnits required as default
 | ||||||
|  | 		DefaultRepoUnits = make([]UnitType, len(MustRepoUnits)) | ||||||
|  | 		copy(DefaultRepoUnits, MustRepoUnits) | ||||||
|  | 		for _, defaultU := range setDefaultRepoUnits { | ||||||
|  | 			if !defaultU.CanBeDefault() { | ||||||
|  | 				log.Warn("Not allowed as default unit: %s", defaultU.String()) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			// MustRepoUnits already added
 | ||||||
|  | 			if defaultU.CanDisable() { | ||||||
|  | 				DefaultRepoUnits = append(DefaultRepoUnits, defaultU) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	DisabledRepoUnits = FindUnitTypes(setting.Repository.DisabledRepoUnits...) | ||||||
|  | 	// Check that must units are not disabled
 | ||||||
|  | 	for i, disabledU := range DisabledRepoUnits { | ||||||
|  | 		if !disabledU.CanDisable() { | ||||||
|  | 			log.Warn("Not allowed to global disable unit %s", disabledU.String()) | ||||||
|  | 			DisabledRepoUnits = append(DisabledRepoUnits[:i], DisabledRepoUnits[i+1:]...) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// Remove disabled units from default units
 | ||||||
|  | 	for _, disabledU := range DisabledRepoUnits { | ||||||
|  | 		for i, defaultU := range DefaultRepoUnits { | ||||||
|  | 			if defaultU == disabledU { | ||||||
|  | 				DefaultRepoUnits = append(DefaultRepoUnits[:i], DefaultRepoUnits[i+1:]...) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // UnitGlobalDisabled checks if unit type is global disabled
 | ||||||
|  | func (u UnitType) UnitGlobalDisabled() bool { | ||||||
|  | 	for _, ud := range DisabledRepoUnits { | ||||||
|  | 		if u == ud { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // CanDisable checks if this unit type can be disabled.
 | ||||||
|  | func (u *UnitType) CanDisable() bool { | ||||||
|  | 	for _, mu := range MustRepoUnits { | ||||||
|  | 		if *u == mu { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // CanBeDefault checks if the unit type can be a default repo unit
 | ||||||
|  | func (u *UnitType) CanBeDefault() bool { | ||||||
|  | 	for _, nadU := range NotAllowedDefaultRepoUnits { | ||||||
|  | 		if *u == nadU { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Unit is a section of one repository
 | // Unit is a section of one repository
 | ||||||
| type Unit struct { | type Unit struct { | ||||||
| 	Type    UnitType | 	Type    UnitType | ||||||
|  | @ -96,7 +173,7 @@ type Unit struct { | ||||||
| 
 | 
 | ||||||
| // CanDisable returns if this unit could be disabled.
 | // CanDisable returns if this unit could be disabled.
 | ||||||
| func (u *Unit) CanDisable() bool { | func (u *Unit) CanDisable() bool { | ||||||
| 	return true | 	return u.Type.CanDisable() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // IsLessThan compares order of two units
 | // IsLessThan compares order of two units
 | ||||||
|  |  | ||||||
|  | @ -622,6 +622,7 @@ func (u *User) GetRepositories(page, pageSize int) (err error) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // GetRepositoryIDs returns repositories IDs where user owned and has unittypes
 | // GetRepositoryIDs returns repositories IDs where user owned and has unittypes
 | ||||||
|  | // Caller shall check that units is not globally disabled
 | ||||||
| func (u *User) GetRepositoryIDs(units ...UnitType) ([]int64, error) { | func (u *User) GetRepositoryIDs(units ...UnitType) ([]int64, error) { | ||||||
| 	var ids []int64 | 	var ids []int64 | ||||||
| 
 | 
 | ||||||
|  | @ -636,6 +637,7 @@ func (u *User) GetRepositoryIDs(units ...UnitType) ([]int64, error) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // GetOrgRepositoryIDs returns repositories IDs where user's team owned and has unittypes
 | // GetOrgRepositoryIDs returns repositories IDs where user's team owned and has unittypes
 | ||||||
|  | // Caller shall check that units is not globally disabled
 | ||||||
| func (u *User) GetOrgRepositoryIDs(units ...UnitType) ([]int64, error) { | func (u *User) GetOrgRepositoryIDs(units ...UnitType) ([]int64, error) { | ||||||
| 	var ids []int64 | 	var ids []int64 | ||||||
| 
 | 
 | ||||||
|  | @ -656,6 +658,7 @@ func (u *User) GetOrgRepositoryIDs(units ...UnitType) ([]int64, error) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // GetAccessRepoIDs returns all repositories IDs where user's or user is a team member organizations
 | // GetAccessRepoIDs returns all repositories IDs where user's or user is a team member organizations
 | ||||||
|  | // Caller shall check that units is not globally disabled
 | ||||||
| func (u *User) GetAccessRepoIDs(units ...UnitType) ([]int64, error) { | func (u *User) GetAccessRepoIDs(units ...UnitType) ([]int64, error) { | ||||||
| 	ids, err := u.GetRepositoryIDs(units...) | 	ids, err := u.GetRepositoryIDs(units...) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  |  | ||||||
|  | @ -37,6 +37,8 @@ var ( | ||||||
| 		DefaultCloseIssuesViaCommitsInAnyBranch bool | 		DefaultCloseIssuesViaCommitsInAnyBranch bool | ||||||
| 		EnablePushCreateUser                    bool | 		EnablePushCreateUser                    bool | ||||||
| 		EnablePushCreateOrg                     bool | 		EnablePushCreateOrg                     bool | ||||||
|  | 		DisabledRepoUnits                       []string | ||||||
|  | 		DefaultRepoUnits                        []string | ||||||
| 
 | 
 | ||||||
| 		// Repository editor settings
 | 		// Repository editor settings
 | ||||||
| 		Editor struct { | 		Editor struct { | ||||||
|  | @ -98,6 +100,8 @@ var ( | ||||||
| 		DefaultCloseIssuesViaCommitsInAnyBranch: false, | 		DefaultCloseIssuesViaCommitsInAnyBranch: false, | ||||||
| 		EnablePushCreateUser:                    false, | 		EnablePushCreateUser:                    false, | ||||||
| 		EnablePushCreateOrg:                     false, | 		EnablePushCreateOrg:                     false, | ||||||
|  | 		DisabledRepoUnits:                       []string{}, | ||||||
|  | 		DefaultRepoUnits:                        []string{}, | ||||||
| 
 | 
 | ||||||
| 		// Repository editor settings
 | 		// Repository editor settings
 | ||||||
| 		Editor: struct { | 		Editor: struct { | ||||||
|  |  | ||||||
|  | @ -636,6 +636,7 @@ stargazers = Stargazers | ||||||
| forks = Forks | forks = Forks | ||||||
| pick_reaction = Pick your reaction | pick_reaction = Pick your reaction | ||||||
| reactions_more = and %d more | reactions_more = and %d more | ||||||
|  | unit_disabled = The site administrator has disabled this repository section. | ||||||
| 
 | 
 | ||||||
| template.items = Template Items | template.items = Template Items | ||||||
| template.git_content = Git Content (Default Branch) | template.git_content = Git Content (Default Branch) | ||||||
|  | @ -1613,6 +1614,7 @@ team_desc_helper = Describe the purpose or role of the team. | ||||||
| team_access_desc = Repository access | team_access_desc = Repository access | ||||||
| team_permission_desc = Permission | team_permission_desc = Permission | ||||||
| team_unit_desc = Allow Access to Repository Sections | team_unit_desc = Allow Access to Repository Sections | ||||||
|  | team_unit_disabled = (Disabled) | ||||||
| 
 | 
 | ||||||
| form.name_reserved = The organization name '%s' is reserved. | form.name_reserved = The organization name '%s' is reserved. | ||||||
| form.name_pattern_not_allowed = The pattern '%s' is not allowed in an organization name. | form.name_pattern_not_allowed = The pattern '%s' is not allowed in an organization name. | ||||||
|  |  | ||||||
|  | @ -757,25 +757,10 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { | ||||||
| 	repo := ctx.Repo.Repository | 	repo := ctx.Repo.Repository | ||||||
| 
 | 
 | ||||||
| 	var units []models.RepoUnit | 	var units []models.RepoUnit | ||||||
|  | 	var deleteUnitTypes []models.UnitType | ||||||
| 
 | 
 | ||||||
| 	for _, tp := range models.MustRepoUnits { | 	if opts.HasIssues != nil { | ||||||
| 		units = append(units, models.RepoUnit{ | 		if *opts.HasIssues && opts.ExternalTracker != nil && !models.UnitTypeExternalTracker.UnitGlobalDisabled() { | ||||||
| 			RepoID: repo.ID, |  | ||||||
| 			Type:   tp, |  | ||||||
| 			Config: new(models.UnitConfig), |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if opts.HasIssues == nil { |  | ||||||
| 		// If HasIssues setting not touched, rewrite existing repo unit
 |  | ||||||
| 		if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil { |  | ||||||
| 			units = append(units, *unit) |  | ||||||
| 		} else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil { |  | ||||||
| 			units = append(units, *unit) |  | ||||||
| 		} |  | ||||||
| 	} else if *opts.HasIssues { |  | ||||||
| 		if opts.ExternalTracker != nil { |  | ||||||
| 
 |  | ||||||
| 			// Check that values are valid
 | 			// Check that values are valid
 | ||||||
| 			if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) { | 			if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) { | ||||||
| 				err := fmt.Errorf("External tracker URL not valid") | 				err := fmt.Errorf("External tracker URL not valid") | ||||||
|  | @ -797,7 +782,8 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { | ||||||
| 					ExternalTrackerStyle:  opts.ExternalTracker.ExternalTrackerStyle, | 					ExternalTrackerStyle:  opts.ExternalTracker.ExternalTrackerStyle, | ||||||
| 				}, | 				}, | ||||||
| 			}) | 			}) | ||||||
| 		} else { | 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues) | ||||||
|  | 		} else if *opts.HasIssues && opts.ExternalTracker == nil && !models.UnitTypeIssues.UnitGlobalDisabled() { | ||||||
| 			// Default to built-in tracker
 | 			// Default to built-in tracker
 | ||||||
| 			var config *models.IssuesConfig | 			var config *models.IssuesConfig | ||||||
| 
 | 
 | ||||||
|  | @ -823,19 +809,19 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { | ||||||
| 				Type:   models.UnitTypeIssues, | 				Type:   models.UnitTypeIssues, | ||||||
| 				Config: config, | 				Config: config, | ||||||
| 			}) | 			}) | ||||||
|  | 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker) | ||||||
|  | 		} else if !*opts.HasIssues { | ||||||
|  | 			if !models.UnitTypeExternalTracker.UnitGlobalDisabled() { | ||||||
|  | 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker) | ||||||
|  | 			} | ||||||
|  | 			if !models.UnitTypeIssues.UnitGlobalDisabled() { | ||||||
|  | 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if opts.HasWiki == nil { | 	if opts.HasWiki != nil { | ||||||
| 		// If HasWiki setting not touched, rewrite existing repo unit
 | 		if *opts.HasWiki && opts.ExternalWiki != nil && !models.UnitTypeExternalWiki.UnitGlobalDisabled() { | ||||||
| 		if unit, err := repo.GetUnit(models.UnitTypeWiki); err == nil { |  | ||||||
| 			units = append(units, *unit) |  | ||||||
| 		} else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil { |  | ||||||
| 			units = append(units, *unit) |  | ||||||
| 		} |  | ||||||
| 	} else if *opts.HasWiki { |  | ||||||
| 		if opts.ExternalWiki != nil { |  | ||||||
| 
 |  | ||||||
| 			// Check that values are valid
 | 			// Check that values are valid
 | ||||||
| 			if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) { | 			if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) { | ||||||
| 				err := fmt.Errorf("External wiki URL not valid") | 				err := fmt.Errorf("External wiki URL not valid") | ||||||
|  | @ -850,64 +836,72 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { | ||||||
| 					ExternalWikiURL: opts.ExternalWiki.ExternalWikiURL, | 					ExternalWikiURL: opts.ExternalWiki.ExternalWikiURL, | ||||||
| 				}, | 				}, | ||||||
| 			}) | 			}) | ||||||
| 		} else { | 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki) | ||||||
|  | 		} else if *opts.HasWiki && opts.ExternalWiki == nil && !models.UnitTypeWiki.UnitGlobalDisabled() { | ||||||
| 			config := &models.UnitConfig{} | 			config := &models.UnitConfig{} | ||||||
| 			units = append(units, models.RepoUnit{ | 			units = append(units, models.RepoUnit{ | ||||||
| 				RepoID: repo.ID, | 				RepoID: repo.ID, | ||||||
| 				Type:   models.UnitTypeWiki, | 				Type:   models.UnitTypeWiki, | ||||||
| 				Config: config, | 				Config: config, | ||||||
| 			}) | 			}) | ||||||
| 		} | 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki) | ||||||
| 	} | 		} else if !*opts.HasWiki { | ||||||
| 
 | 			if !models.UnitTypeExternalWiki.UnitGlobalDisabled() { | ||||||
| 	if opts.HasPullRequests == nil { | 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki) | ||||||
| 		// If HasPullRequest setting not touched, rewrite existing repo unit
 | 			} | ||||||
| 		if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil { | 			if !models.UnitTypeWiki.UnitGlobalDisabled() { | ||||||
| 			units = append(units, *unit) | 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki) | ||||||
| 		} |  | ||||||
| 	} else if *opts.HasPullRequests { |  | ||||||
| 		// We do allow setting individual PR settings through the API, so
 |  | ||||||
| 		// we get the config settings and then set them
 |  | ||||||
| 		// if those settings were provided in the opts.
 |  | ||||||
| 		unit, err := repo.GetUnit(models.UnitTypePullRequests) |  | ||||||
| 		var config *models.PullRequestsConfig |  | ||||||
| 		if err != nil { |  | ||||||
| 			// Unit type doesn't exist so we make a new config file with default values
 |  | ||||||
| 			config = &models.PullRequestsConfig{ |  | ||||||
| 				IgnoreWhitespaceConflicts: false, |  | ||||||
| 				AllowMerge:                true, |  | ||||||
| 				AllowRebase:               true, |  | ||||||
| 				AllowRebaseMerge:          true, |  | ||||||
| 				AllowSquash:               true, |  | ||||||
| 			} | 			} | ||||||
| 		} else { |  | ||||||
| 			config = unit.PullRequestsConfig() |  | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 		if opts.IgnoreWhitespaceConflicts != nil { |  | ||||||
| 			config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts |  | ||||||
| 		} |  | ||||||
| 		if opts.AllowMerge != nil { |  | ||||||
| 			config.AllowMerge = *opts.AllowMerge |  | ||||||
| 		} |  | ||||||
| 		if opts.AllowRebase != nil { |  | ||||||
| 			config.AllowRebase = *opts.AllowRebase |  | ||||||
| 		} |  | ||||||
| 		if opts.AllowRebaseMerge != nil { |  | ||||||
| 			config.AllowRebaseMerge = *opts.AllowRebaseMerge |  | ||||||
| 		} |  | ||||||
| 		if opts.AllowSquash != nil { |  | ||||||
| 			config.AllowSquash = *opts.AllowSquash |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		units = append(units, models.RepoUnit{ |  | ||||||
| 			RepoID: repo.ID, |  | ||||||
| 			Type:   models.UnitTypePullRequests, |  | ||||||
| 			Config: config, |  | ||||||
| 		}) |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := models.UpdateRepositoryUnits(repo, units); err != nil { | 	if opts.HasPullRequests != nil { | ||||||
|  | 		if *opts.HasPullRequests && !models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||||
|  | 			// We do allow setting individual PR settings through the API, so
 | ||||||
|  | 			// we get the config settings and then set them
 | ||||||
|  | 			// if those settings were provided in the opts.
 | ||||||
|  | 			unit, err := repo.GetUnit(models.UnitTypePullRequests) | ||||||
|  | 			var config *models.PullRequestsConfig | ||||||
|  | 			if err != nil { | ||||||
|  | 				// Unit type doesn't exist so we make a new config file with default values
 | ||||||
|  | 				config = &models.PullRequestsConfig{ | ||||||
|  | 					IgnoreWhitespaceConflicts: false, | ||||||
|  | 					AllowMerge:                true, | ||||||
|  | 					AllowRebase:               true, | ||||||
|  | 					AllowRebaseMerge:          true, | ||||||
|  | 					AllowSquash:               true, | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				config = unit.PullRequestsConfig() | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if opts.IgnoreWhitespaceConflicts != nil { | ||||||
|  | 				config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts | ||||||
|  | 			} | ||||||
|  | 			if opts.AllowMerge != nil { | ||||||
|  | 				config.AllowMerge = *opts.AllowMerge | ||||||
|  | 			} | ||||||
|  | 			if opts.AllowRebase != nil { | ||||||
|  | 				config.AllowRebase = *opts.AllowRebase | ||||||
|  | 			} | ||||||
|  | 			if opts.AllowRebaseMerge != nil { | ||||||
|  | 				config.AllowRebaseMerge = *opts.AllowRebaseMerge | ||||||
|  | 			} | ||||||
|  | 			if opts.AllowSquash != nil { | ||||||
|  | 				config.AllowSquash = *opts.AllowSquash | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			units = append(units, models.RepoUnit{ | ||||||
|  | 				RepoID: repo.ID, | ||||||
|  | 				Type:   models.UnitTypePullRequests, | ||||||
|  | 				Config: config, | ||||||
|  | 			}) | ||||||
|  | 		} else if !*opts.HasPullRequests && !models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||||
|  | 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypePullRequests) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := models.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil { | ||||||
| 		ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err) | 		ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -205,78 +205,85 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | ||||||
| 
 | 
 | ||||||
| 	case "advanced": | 	case "advanced": | ||||||
| 		var units []models.RepoUnit | 		var units []models.RepoUnit | ||||||
|  | 		var deleteUnitTypes []models.UnitType | ||||||
| 
 | 
 | ||||||
| 		// This section doesn't require repo_name/RepoName to be set in the form, don't show it
 | 		// This section doesn't require repo_name/RepoName to be set in the form, don't show it
 | ||||||
| 		// as an error on the UI for this action
 | 		// as an error on the UI for this action
 | ||||||
| 		ctx.Data["Err_RepoName"] = nil | 		ctx.Data["Err_RepoName"] = nil | ||||||
| 
 | 
 | ||||||
| 		for _, tp := range models.MustRepoUnits { | 		if form.EnableWiki && form.EnableExternalWiki && !models.UnitTypeExternalWiki.UnitGlobalDisabled() { | ||||||
|  | 			if !validation.IsValidExternalURL(form.ExternalWikiURL) { | ||||||
|  | 				ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error")) | ||||||
|  | 				ctx.Redirect(repo.Link() + "/settings") | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 			units = append(units, models.RepoUnit{ | 			units = append(units, models.RepoUnit{ | ||||||
| 				RepoID: repo.ID, | 				RepoID: repo.ID, | ||||||
| 				Type:   tp, | 				Type:   models.UnitTypeExternalWiki, | ||||||
|  | 				Config: &models.ExternalWikiConfig{ | ||||||
|  | 					ExternalWikiURL: form.ExternalWikiURL, | ||||||
|  | 				}, | ||||||
|  | 			}) | ||||||
|  | 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki) | ||||||
|  | 		} else if form.EnableWiki && !form.EnableExternalWiki && !models.UnitTypeWiki.UnitGlobalDisabled() { | ||||||
|  | 			units = append(units, models.RepoUnit{ | ||||||
|  | 				RepoID: repo.ID, | ||||||
|  | 				Type:   models.UnitTypeWiki, | ||||||
| 				Config: new(models.UnitConfig), | 				Config: new(models.UnitConfig), | ||||||
| 			}) | 			}) | ||||||
| 		} | 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki) | ||||||
| 
 | 		} else { | ||||||
| 		if form.EnableWiki { | 			if !models.UnitTypeExternalWiki.UnitGlobalDisabled() { | ||||||
| 			if form.EnableExternalWiki { | 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki) | ||||||
| 				if !validation.IsValidExternalURL(form.ExternalWikiURL) { | 			} | ||||||
| 					ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error")) | 			if !models.UnitTypeWiki.UnitGlobalDisabled() { | ||||||
| 					ctx.Redirect(repo.Link() + "/settings") | 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki) | ||||||
| 					return |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				units = append(units, models.RepoUnit{ |  | ||||||
| 					RepoID: repo.ID, |  | ||||||
| 					Type:   models.UnitTypeExternalWiki, |  | ||||||
| 					Config: &models.ExternalWikiConfig{ |  | ||||||
| 						ExternalWikiURL: form.ExternalWikiURL, |  | ||||||
| 					}, |  | ||||||
| 				}) |  | ||||||
| 			} else { |  | ||||||
| 				units = append(units, models.RepoUnit{ |  | ||||||
| 					RepoID: repo.ID, |  | ||||||
| 					Type:   models.UnitTypeWiki, |  | ||||||
| 					Config: new(models.UnitConfig), |  | ||||||
| 				}) |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if form.EnableIssues { | 		if form.EnableIssues && form.EnableExternalTracker && !models.UnitTypeExternalTracker.UnitGlobalDisabled() { | ||||||
| 			if form.EnableExternalTracker { | 			if !validation.IsValidExternalURL(form.ExternalTrackerURL) { | ||||||
| 				if !validation.IsValidExternalURL(form.ExternalTrackerURL) { | 				ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error")) | ||||||
| 					ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error")) | 				ctx.Redirect(repo.Link() + "/settings") | ||||||
| 					ctx.Redirect(repo.Link() + "/settings") | 				return | ||||||
| 					return | 			} | ||||||
| 				} | 			if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) { | ||||||
| 				if len(form.TrackerURLFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(form.TrackerURLFormat) { | 				ctx.Flash.Error(ctx.Tr("repo.settings.tracker_url_format_error")) | ||||||
| 					ctx.Flash.Error(ctx.Tr("repo.settings.tracker_url_format_error")) | 				ctx.Redirect(repo.Link() + "/settings") | ||||||
| 					ctx.Redirect(repo.Link() + "/settings") | 				return | ||||||
| 					return | 			} | ||||||
| 				} | 			units = append(units, models.RepoUnit{ | ||||||
| 				units = append(units, models.RepoUnit{ | 				RepoID: repo.ID, | ||||||
| 					RepoID: repo.ID, | 				Type:   models.UnitTypeExternalTracker, | ||||||
| 					Type:   models.UnitTypeExternalTracker, | 				Config: &models.ExternalTrackerConfig{ | ||||||
| 					Config: &models.ExternalTrackerConfig{ | 					ExternalTrackerURL:    form.ExternalTrackerURL, | ||||||
| 						ExternalTrackerURL:    form.ExternalTrackerURL, | 					ExternalTrackerFormat: form.TrackerURLFormat, | ||||||
| 						ExternalTrackerFormat: form.TrackerURLFormat, | 					ExternalTrackerStyle:  form.TrackerIssueStyle, | ||||||
| 						ExternalTrackerStyle:  form.TrackerIssueStyle, | 				}, | ||||||
| 					}, | 			}) | ||||||
| 				}) | 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues) | ||||||
| 			} else { | 		} else if form.EnableIssues && !form.EnableExternalTracker && !models.UnitTypeIssues.UnitGlobalDisabled() { | ||||||
| 				units = append(units, models.RepoUnit{ | 			units = append(units, models.RepoUnit{ | ||||||
| 					RepoID: repo.ID, | 				RepoID: repo.ID, | ||||||
| 					Type:   models.UnitTypeIssues, | 				Type:   models.UnitTypeIssues, | ||||||
| 					Config: &models.IssuesConfig{ | 				Config: &models.IssuesConfig{ | ||||||
| 						EnableTimetracker:                form.EnableTimetracker, | 					EnableTimetracker:                form.EnableTimetracker, | ||||||
| 						AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime, | 					AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime, | ||||||
| 						EnableDependencies:               form.EnableIssueDependencies, | 					EnableDependencies:               form.EnableIssueDependencies, | ||||||
| 					}, | 				}, | ||||||
| 				}) | 			}) | ||||||
|  | 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker) | ||||||
|  | 		} else { | ||||||
|  | 			if !models.UnitTypeExternalTracker.UnitGlobalDisabled() { | ||||||
|  | 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker) | ||||||
|  | 			} | ||||||
|  | 			if !models.UnitTypeIssues.UnitGlobalDisabled() { | ||||||
|  | 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if form.EnablePulls { | 		if form.EnablePulls && !models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||||
| 			units = append(units, models.RepoUnit{ | 			units = append(units, models.RepoUnit{ | ||||||
| 				RepoID: repo.ID, | 				RepoID: repo.ID, | ||||||
| 				Type:   models.UnitTypePullRequests, | 				Type:   models.UnitTypePullRequests, | ||||||
|  | @ -288,9 +295,11 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | ||||||
| 					AllowSquash:               form.PullsAllowSquash, | 					AllowSquash:               form.PullsAllowSquash, | ||||||
| 				}, | 				}, | ||||||
| 			}) | 			}) | ||||||
|  | 		} else if !models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||||
|  | 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypePullRequests) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if err := models.UpdateRepositoryUnits(repo, units); err != nil { | 		if err := models.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil { | ||||||
| 			ctx.ServerError("UpdateRepositoryUnits", err) | 			ctx.ServerError("UpdateRepositoryUnits", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -261,6 +261,11 @@ func RegisterRoutes(m *macaron.Macaron) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	m.Use(user.GetNotificationCount) | 	m.Use(user.GetNotificationCount) | ||||||
|  | 	m.Use(func(ctx *context.Context) { | ||||||
|  | 		ctx.Data["UnitWikiGlobalDisabled"] = models.UnitTypeWiki.UnitGlobalDisabled() | ||||||
|  | 		ctx.Data["UnitIssuesGlobalDisabled"] = models.UnitTypeIssues.UnitGlobalDisabled() | ||||||
|  | 		ctx.Data["UnitPullsGlobalDisabled"] = models.UnitTypePullRequests.UnitGlobalDisabled() | ||||||
|  | 	}) | ||||||
| 
 | 
 | ||||||
| 	// FIXME: not all routes need go through same middlewares.
 | 	// FIXME: not all routes need go through same middlewares.
 | ||||||
| 	// Especially some AJAX requests, we can reduce middleware number to improve performance.
 | 	// Especially some AJAX requests, we can reduce middleware number to improve performance.
 | ||||||
|  |  | ||||||
|  | @ -158,6 +158,12 @@ func Dashboard(ctx *context.Context) { | ||||||
| 
 | 
 | ||||||
| // Milestones render the user milestones page
 | // Milestones render the user milestones page
 | ||||||
| func Milestones(ctx *context.Context) { | func Milestones(ctx *context.Context) { | ||||||
|  | 	if models.UnitTypeIssues.UnitGlobalDisabled() && models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||||
|  | 		log.Debug("Milestones overview page not available as both issues and pull requests are globally disabled") | ||||||
|  | 		ctx.Status(404) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	ctx.Data["Title"] = ctx.Tr("milestones") | 	ctx.Data["Title"] = ctx.Tr("milestones") | ||||||
| 	ctx.Data["PageIsMilestonesDashboard"] = true | 	ctx.Data["PageIsMilestonesDashboard"] = true | ||||||
| 
 | 
 | ||||||
|  | @ -335,10 +341,22 @@ func Issues(ctx *context.Context) { | ||||||
| 	isPullList := ctx.Params(":type") == "pulls" | 	isPullList := ctx.Params(":type") == "pulls" | ||||||
| 	unitType := models.UnitTypeIssues | 	unitType := models.UnitTypeIssues | ||||||
| 	if isPullList { | 	if isPullList { | ||||||
|  | 		if models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||||
|  | 			log.Debug("Pull request overview page not available as it is globally disabled.") | ||||||
|  | 			ctx.Status(404) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		ctx.Data["Title"] = ctx.Tr("pull_requests") | 		ctx.Data["Title"] = ctx.Tr("pull_requests") | ||||||
| 		ctx.Data["PageIsPulls"] = true | 		ctx.Data["PageIsPulls"] = true | ||||||
| 		unitType = models.UnitTypePullRequests | 		unitType = models.UnitTypePullRequests | ||||||
| 	} else { | 	} else { | ||||||
|  | 		if models.UnitTypeIssues.UnitGlobalDisabled() { | ||||||
|  | 			log.Debug("Issues overview page not available as it is globally disabled.") | ||||||
|  | 			ctx.Status(404) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		ctx.Data["Title"] = ctx.Tr("issues") | 		ctx.Data["Title"] = ctx.Tr("issues") | ||||||
| 		ctx.Data["PageIsIssues"] = true | 		ctx.Data["PageIsIssues"] = true | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -10,9 +10,15 @@ | ||||||
| 
 | 
 | ||||||
| 	{{if .IsSigned}} | 	{{if .IsSigned}} | ||||||
| 		<a class="item {{if .PageIsDashboard}}active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "dashboard"}}</a> | 		<a class="item {{if .PageIsDashboard}}active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "dashboard"}}</a> | ||||||
|  | 		{{if not .UnitIssuesGlobalDisabled}} | ||||||
| 		<a class="item {{if .PageIsIssues}}active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | 		<a class="item {{if .PageIsIssues}}active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | ||||||
|  | 		{{end}} | ||||||
|  | 		{{if not .UnitPullsGlobalDisabled}} | ||||||
| 		<a class="item {{if .PageIsPulls}}active{{end}}" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | 		<a class="item {{if .PageIsPulls}}active{{end}}" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | ||||||
|  | 		{{end}} | ||||||
|  | 		{{if not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled)}} | ||||||
| 		{{if .ShowMilestonesDashboardPage}}<a class="item {{if .PageIsMilestonesDashboard}}active{{end}}" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>{{end}} | 		{{if .ShowMilestonesDashboardPage}}<a class="item {{if .PageIsMilestonesDashboard}}active{{end}}" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>{{end}} | ||||||
|  | 		{{end}} | ||||||
| 		<a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "explore"}}</a> | 		<a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "explore"}}</a> | ||||||
| 	{{else if .IsLandingPageHome}} | 	{{else if .IsLandingPageHome}} | ||||||
| 		<a class="item {{if .PageIsHome}}active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "home"}}</a> | 		<a class="item {{if .PageIsHome}}active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "home"}}</a> | ||||||
|  |  | ||||||
|  | @ -81,10 +81,14 @@ | ||||||
| 							<label>{{.i18n.Tr "org.team_unit_desc"}}</label> | 							<label>{{.i18n.Tr "org.team_unit_desc"}}</label> | ||||||
| 							<br> | 							<br> | ||||||
| 							{{range $t, $unit := $.Units}} | 							{{range $t, $unit := $.Units}} | ||||||
|  | 							{{if $unit.Type.UnitGlobalDisabled}} | ||||||
|  | 							<div class="field poping up" data-content="{{$.i18n.Tr "repo.unit_disabled"}}"> | ||||||
|  | 							{{else}} | ||||||
| 							<div class="field"> | 							<div class="field"> | ||||||
|  | 							{{end}} | ||||||
| 								<div class="ui toggle checkbox"> | 								<div class="ui toggle checkbox"> | ||||||
| 									<input type="checkbox" class="hidden" name="units" value="{{$unit.Type.Value}}"{{if or (eq $.Team.ID 0) ($.Team.UnitEnabled $unit.Type)}} checked{{end}}> | 									<input type="checkbox" class="hidden" name="units" value="{{$unit.Type.Value}}"{{if or (eq $.Team.ID 0) ($.Team.UnitEnabled $unit.Type)}} checked{{end}}> | ||||||
| 									<label>{{$.i18n.Tr $unit.NameKey}}</label> | 									<label>{{$.i18n.Tr $unit.NameKey}}{{if $unit.Type.UnitGlobalDisabled}} {{$.i18n.Tr "org.team_unit_disabled"}}{{end}}</label> | ||||||
| 									<span class="help">{{$.i18n.Tr $unit.DescKey}}</span> | 									<span class="help">{{$.i18n.Tr $unit.DescKey}}</span> | ||||||
| 								</div> | 								</div> | ||||||
| 							</div> | 							</div> | ||||||
|  |  | ||||||
|  | @ -144,20 +144,32 @@ | ||||||
| 				{{$isWikiEnabled := or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} | 				{{$isWikiEnabled := or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} | ||||||
| 				<div class="inline field"> | 				<div class="inline field"> | ||||||
| 					<label>{{.i18n.Tr "repo.wiki"}}</label> | 					<label>{{.i18n.Tr "repo.wiki"}}</label> | ||||||
|  | 					{{if and (.UnitTypeWiki.UnitGlobalDisabled) (.UnitTypeExternalWiki.UnitGlobalDisabled)}} | ||||||
|  | 					<div class="ui checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||||
|  | 					{{else}} | ||||||
| 					<div class="ui checkbox"> | 					<div class="ui checkbox"> | ||||||
|  | 					{{end}} | ||||||
| 						<input class="enable-system" name="enable_wiki" type="checkbox" data-target="#wiki_box" {{if $isWikiEnabled}}checked{{end}}> | 						<input class="enable-system" name="enable_wiki" type="checkbox" data-target="#wiki_box" {{if $isWikiEnabled}}checked{{end}}> | ||||||
| 						<label>{{.i18n.Tr "repo.settings.wiki_desc"}}</label> | 						<label>{{.i18n.Tr "repo.settings.wiki_desc"}}</label> | ||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 				<div class="field {{if not $isWikiEnabled}}disabled{{end}}" id="wiki_box"> | 				<div class="field {{if not $isWikiEnabled}}disabled{{end}}" id="wiki_box"> | ||||||
| 					<div class="field"> | 					<div class="field"> | ||||||
|  | 						{{if .UnitTypeWiki.UnitGlobalDisabled}} | ||||||
|  | 						<div class="ui radio checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||||
|  | 						{{else}} | ||||||
| 						<div class="ui radio checkbox"> | 						<div class="ui radio checkbox"> | ||||||
|  | 						{{end}} | ||||||
| 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="false" data-target="#external_wiki_box" {{if not (.Repository.UnitEnabled $.UnitTypeExternalWiki)}}checked{{end}}/> | 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="false" data-target="#external_wiki_box" {{if not (.Repository.UnitEnabled $.UnitTypeExternalWiki)}}checked{{end}}/> | ||||||
| 							<label>{{.i18n.Tr "repo.settings.use_internal_wiki"}}</label> | 							<label>{{.i18n.Tr "repo.settings.use_internal_wiki"}}</label> | ||||||
| 						</div> | 						</div> | ||||||
| 					</div> | 					</div> | ||||||
| 					<div class="field"> | 					<div class="field"> | ||||||
|  | 						{{if .UnitTypeExternalWiki.UnitGlobalDisabled}} | ||||||
|  | 						<div class="ui radio checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||||
|  | 						{{else}} | ||||||
| 						<div class="ui radio checkbox"> | 						<div class="ui radio checkbox"> | ||||||
|  | 						{{end}} | ||||||
| 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="true" data-target="#external_wiki_box" {{if .Repository.UnitEnabled $.UnitTypeExternalWiki}}checked{{end}}/> | 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="true" data-target="#external_wiki_box" {{if .Repository.UnitEnabled $.UnitTypeExternalWiki}}checked{{end}}/> | ||||||
| 							<label>{{.i18n.Tr "repo.settings.use_external_wiki"}}</label> | 							<label>{{.i18n.Tr "repo.settings.use_external_wiki"}}</label> | ||||||
| 						</div> | 						</div> | ||||||
|  | @ -174,14 +186,22 @@ | ||||||
| 				{{$isIssuesEnabled := or (.Repository.UnitEnabled $.UnitTypeIssues) (.Repository.UnitEnabled $.UnitTypeExternalTracker)}} | 				{{$isIssuesEnabled := or (.Repository.UnitEnabled $.UnitTypeIssues) (.Repository.UnitEnabled $.UnitTypeExternalTracker)}} | ||||||
| 				<div class="inline field"> | 				<div class="inline field"> | ||||||
| 					<label>{{.i18n.Tr "repo.issues"}}</label> | 					<label>{{.i18n.Tr "repo.issues"}}</label> | ||||||
|  | 					{{if and (.UnitTypeIssues.UnitGlobalDisabled) (.UnitTypeExternalTracker.UnitGlobalDisabled)}} | ||||||
|  | 					<div class="ui checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||||
|  | 					{{else}} | ||||||
| 					<div class="ui checkbox"> | 					<div class="ui checkbox"> | ||||||
|  | 					{{end}} | ||||||
| 						<input class="enable-system" name="enable_issues" type="checkbox" data-target="#issue_box" {{if $isIssuesEnabled}}checked{{end}}> | 						<input class="enable-system" name="enable_issues" type="checkbox" data-target="#issue_box" {{if $isIssuesEnabled}}checked{{end}}> | ||||||
| 						<label>{{.i18n.Tr "repo.settings.issues_desc"}}</label> | 						<label>{{.i18n.Tr "repo.settings.issues_desc"}}</label> | ||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 				<div class="field {{if not $isIssuesEnabled}}disabled{{end}}" id="issue_box"> | 				<div class="field {{if not $isIssuesEnabled}}disabled{{end}}" id="issue_box"> | ||||||
| 					<div class="field"> | 					<div class="field"> | ||||||
|  | 						{{if .UnitTypeIssues.UnitGlobalDisabled}} | ||||||
|  | 						<div class="ui radio checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||||
|  | 						{{else}} | ||||||
| 						<div class="ui radio checkbox"> | 						<div class="ui radio checkbox"> | ||||||
|  | 						{{end}} | ||||||
| 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="false" data-context="#internal_issue_box" data-target="#external_issue_box" {{if not (.Repository.UnitEnabled $.UnitTypeExternalTracker)}}checked{{end}}/> | 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="false" data-context="#internal_issue_box" data-target="#external_issue_box" {{if not (.Repository.UnitEnabled $.UnitTypeExternalTracker)}}checked{{end}}/> | ||||||
| 							<label>{{.i18n.Tr "repo.settings.use_internal_issue_tracker"}}</label> | 							<label>{{.i18n.Tr "repo.settings.use_internal_issue_tracker"}}</label> | ||||||
| 						</div> | 						</div> | ||||||
|  | @ -209,7 +229,11 @@ | ||||||
| 							</div> | 							</div> | ||||||
| 					</div> | 					</div> | ||||||
| 					<div class="field"> | 					<div class="field"> | ||||||
|  | 						{{if .UnitTypeExternalTracker.UnitGlobalDisabled}} | ||||||
|  | 						<div class="ui radio checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||||
|  | 						{{else}} | ||||||
| 						<div class="ui radio checkbox"> | 						<div class="ui radio checkbox"> | ||||||
|  | 						{{end}} | ||||||
| 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="true" data-context="#internal_issue_box" data-target="#external_issue_box" {{if .Repository.UnitEnabled $.UnitTypeExternalTracker}}checked{{end}}/> | 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="true" data-context="#internal_issue_box" data-target="#external_issue_box" {{if .Repository.UnitEnabled $.UnitTypeExternalTracker}}checked{{end}}/> | ||||||
| 							<label>{{.i18n.Tr "repo.settings.use_external_issue_tracker"}}</label> | 							<label>{{.i18n.Tr "repo.settings.use_external_issue_tracker"}}</label> | ||||||
| 						</div> | 						</div> | ||||||
|  | @ -251,7 +275,11 @@ | ||||||
| 					{{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} | 					{{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} | ||||||
| 					<div class="inline field"> | 					<div class="inline field"> | ||||||
| 						<label>{{.i18n.Tr "repo.pulls"}}</label> | 						<label>{{.i18n.Tr "repo.pulls"}}</label> | ||||||
|  | 						{{if .UnitTypePullRequests.UnitGlobalDisabled}} | ||||||
|  | 						<div class="ui checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||||
|  | 						{{else}} | ||||||
| 						<div class="ui checkbox"> | 						<div class="ui checkbox"> | ||||||
|  | 						{{end}} | ||||||
| 							<input class="enable-system" name="enable_pulls" type="checkbox" data-target="#pull_box" {{if $pullRequestEnabled}}checked{{end}}> | 							<input class="enable-system" name="enable_pulls" type="checkbox" data-target="#pull_box" {{if $pullRequestEnabled}}checked{{end}}> | ||||||
| 							<label>{{.i18n.Tr "repo.settings.pulls_desc"}}</label> | 							<label>{{.i18n.Tr "repo.settings.pulls_desc"}}</label> | ||||||
| 						</div> | 						</div> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue